Sending JSON Via an HTTP POST Request in Go

Clive B. —
jump to solution

The Problem

You don’t know how to send JSON data in the body of an HTTP request in Go. For example:

{
  "description": "Buy cheese and bread for breakfast."
}

The Solution

The simplest way to send JSON data in an HTTP request is to use the http.Post function from the http package, which requires only a URL, a content type, and a request body.

Sending a JSON String Via HTTP POST in Go

To send a JSON via an HTTP POST request, use http.Post and wrap your JSON string in a bytes.Buffer.

package main

import (
	"bytes"
	"log"
	"net/http"
)

func main() {
	// Define the JSON body as a string.
	body := `{"description": "Buy cheese and bread for breakfast."}`

	// Make the request.
	response, err := http.Post("https://example.com/endpoint", "application/json", bytes.NewBufferString(body))
	if err != nil {
		log.Fatalf("POST failed: %s", err)
	}

	// Do something with the response.
	log.Printf("POST returned with %d status", response.StatusCode)
}

Note: The http.Post function requires only a URL, a content type, and a request body. If you want more control over your request, check out http.Client to learn how to set custom headers, timeouts, etc.

Generating JSON From a Struct in Go

If you’d like to generate your JSON programmatically, use Go’s encoding/json package.

The json.Marshal function uses user-defined json struct tags to format its output.

The Go Wiki offers more information about well-known struct tags.

package main

import (
	"bytes"
	"encoding/json"
	"log"
	"net/http"
)

// Task contains the fields that you'd like to marshal (or serialise) as JSON.
type Task struct {
	Title       string `json:"title"`
	Description string `json:"description"`
}

func main() {
	// Define a Task instance.
	task := Task{
		Title:       "Morning task",
		Description: "Buy cheese and bread for breakfast.",
	}

	// Generate a byte slice representing the Task.
	body, err := json.Marshal(&task)
	if err != nil {
		log.Fatalf("Failed to marshal JSON: %s", err)
	}

	// Make the request.
	// Note that this time, `body` is a slice of bytes, so we use `bytes.NewBuffer` instead.
	response, err := http.Post("https://example.com/endpoint", "application/json", bytes.NewBuffer(body))
	if err != nil {
		log.Fatalf("POST failed: %s", err)
	}

	// Do something with the response.
	log.Printf("POST returned with %d status", response.StatusCode)
}

Further Reading

How To Print Struct Fields in Go
Clive B. —
Map Entries are Unaddressable
Evan Hicks —
Reading a file line by line in Go
Clive B. —

Considered "not bad" by 4 million developers and more than 150,000 organizations worldwide, Sentry provides code-level observability to many of the world's best-known companies like Disney, Peloton, Cloudflare, Eventbrite, Slack, Supercell, and Rockstar Games. Each month we process billions of exceptions from the most popular products on the internet.

Sentry