Lesson 2
Encoding Structs into JSON in Go
Introduction to JSON Encoding in Go

Welcome back! In the previous lesson, we explored the basics of JSON and how Go uses structs to manage and organize JSON data. You learned how to define a struct in Go and use struct tags for JSON serialization. This foundational knowledge is crucial as we move forward to more advanced topics. In this lesson, we will focus on encoding Go structs into JSON format, a process known as marshaling. This is an essential skill for interacting with APIs, as JSON is the primary data format for most web services. By the end of this lesson, you will be able to seamlessly convert Go structs into JSON, preparing you for effective API communication.

Encoding Go Structs into JSON

To encode a Go struct into JSON, we use the encoding/json package, which provides the json.Marshal function. This function takes a Go struct and converts it into a JSON-encoded byte slice. Let's revisit the Todo struct from the previous lesson and see how we can marshal it into JSON.

Go
1package main 2 3import ( 4 "encoding/json" 5 "log" 6) 7 8// Todo structure represents a task with 'title' and 'done' status 9type Todo struct { 10 Title string `json:"title"` 11 Done bool `json:"done"` 12 Description string `json:"description"` 13} 14 15func main() { 16 // Create a new instance of Todo 17 todo := Todo{ 18 Title: "Walking the dog", 19 Done: false, 20 Description: "Walking the dog in the park", 21 } 22 23 // Convert Todo instance to JSON format 24 jsonTodo, err := json.Marshal(todo) 25 if err != nil { 26 log.Fatalf("Error occurred during marshalling: %s", err.Error()) 27 } 28 29 // Print the JSON object 30 log.Printf("JSON object: %s", jsonTodo) 31}

In this example, we define a Todo struct with fields Title, Done, and Description. Each field has a JSON tag that specifies the key name in the resulting JSON object. We create an instance of Todo and use json.Marshal to convert it into JSON. If successful, the JSON object is printed. The output will be a JSON string representing the Todo object, such as:

1JSON object: {"title":"Walking the dog","done":false,"description":"Walking the dog in the park"}
Practical Example: Sending JSON Data via HTTP
Step 1: Convert Struct to JSON

Before sending data, we need to marshal our Todo struct into JSON format.

Go
1jsonTodo, err := json.Marshal(todo) 2if err != nil { 3 log.Fatalf("Error occurred during marshalling: %s", err.Error()) 4}
Step 2: Create an HTTP Request

Now, we create an HTTP request with the JSON data.

Go
1req, err := http.NewRequest("POST", "http://localhost:8000/todos", bytes.NewBuffer(jsonTodo)) 2if err != nil { 3 log.Fatalf("Error occurred during creating HTTP request: %s", err.Error()) 4}
Step 3: Set Headers and Send Request

We need to specify the Content-Type and send the request using an HTTP client.

Go
1req.Header.Set("Content-Type", "application/json") 2client := &http.Client{} 3resp, err := client.Do(req) 4if err != nil { 5 log.Fatalf("Error occurred during sending HTTP request: %s", err.Error()) 6} 7defer resp.Body.Close()
Step 4: Handle HTTP Response

Finally, we check the response status to verify whether the request was successful.

Go
1body, err := io.ReadAll(resp.Body) 2if err != nil { 3 return err 4} 5 6if resp.StatusCode >= 400 { 7 return fmt.Errorf("HTTP request failed with status %d: %s", resp.StatusCode, string(body)) 8} 9 10log.Printf("Request successful! Response: %s", string(body))
Complete Code Example

Here is the final version of our code incorporating all the steps:

Go
1package main 2 3import ( 4 "encoding/json" 5 "log" 6 "bytes" 7 "net/http" 8) 9 10// Todo structure represents a task with 'title' and 'done' status 11type Todo struct { 12 Title string `json:"title"` 13 Done bool `json:"done"` 14 Description string `json:"description"` 15} 16 17func main() { 18 // Create a new instance of Todo 19 todo := Todo{ 20 Title: "Walking the dog", 21 Done: false, 22 Description: "Walking the dog in the park", 23 } 24 25 // Convert Todo instance to JSON format 26 jsonTodo, err := json.Marshal(todo) 27 if err != nil { 28 log.Fatalf("Error occurred during marshalling: %s", err.Error()) 29 } 30 log.Printf("JSON object: %s", jsonTodo) 31 32 // Send JSON data via HTTP 33 if err := sendJSONRequest(jsonTodo); err != nil { 34 log.Fatalf("Error occurred during HTTP request: %s", err.Error()) 35 } 36} 37 38// sendJSONRequest sends a JSON-encoded request to the specified endpoint. 39func sendJSONRequest(jsonData []byte) error { 40 req, err := http.NewRequest("POST", "http://localhost:8000/todos", bytes.NewBuffer(jsonData)) 41 if err != nil { 42 return err 43 } 44 45 req.Header.Set("Content-Type", "application/json") 46 47 client := &http.Client{} 48 resp, err := client.Do(req) 49 if err != nil { 50 return err 51 } 52 defer resp.Body.Close() 53 54 body, err := io.ReadAll(resp.Body) 55 if err != nil { 56 return err 57 } 58 59 if resp.StatusCode >= 400 { 60 return fmt.Errorf("HTTP request failed with status %d: %s", resp.StatusCode, string(body)) 61 } 62 63 log.Printf("Request successful! Response: %s", string(body)) 64 return nil 65}

In this code, we first marshal the Todo struct into JSON. We then create a new HTTP POST request to the /todos endpoint, using the JSON data as the request body. The Content-Type header is set to application/json to indicate that the request body contains JSON data. We use an http.Client to send the request and log the response status. This process is crucial for sending data to web services and APIs.

Handling HTTP Responses

After sending the JSON data, it's important to handle the HTTP response. This involves checking the response status and handling any potential errors. In the example above, we log the response status using resp.Status. This provides valuable feedback on whether the request was successful or if there were any issues. Properly handling responses is key to robust API interactions, allowing you to debug and ensure your application behaves as expected.

Summary and Preparation for Practice

In this lesson, you learned how to encode Go structs into JSON using the encoding/json package and send JSON data via HTTP requests. We covered the process of marshaling a Todo struct into JSON and demonstrated how to create and send an HTTP POST request. This knowledge is essential for effective API interactions in Go applications. As you move on to the practice exercises, I encourage you to experiment with different structs and endpoints. Mastering JSON encoding will enhance your ability to work with APIs and JSON data in Go. Keep practicing, and you'll be well-prepared for the next lesson on decoding JSON into structs.

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.