How to make an HTTP request in golang with best practices?

A guide explains how to make HTTP request in golang with best practices

Pranav Sharma
Pranav Sharma
July 01, 2021
2 min read

The Email API by developers, for developers

Integrate in minutes with our Email API or SMTP and deliver emails to customer's inbox instantly. Mailazy Email API built for developers that fits into any tech stack.

Making a HTTP request in golang is pretty straightforward and simple, following are the examples by HTTP verbs

GET

The HTTP GET method requests a representation of the specified resource. Requests using GET should only retrieve data.

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

func main() {
  resp, err := http.Get("https://httpbin.org/get")
  if err != nil {
      log.Fatal(err)
  }

  defer resp.Body.Close()

  body, err := ioutil.ReadAll(resp.Body)
  if err != nil {
      log.Fatal(err)
  }

  fmt.Println(string(body))
}

GET with Query Args

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

func main() {
	client := &http.Client{}
	req, err := http.NewRequest(http.MethodGet, "https://httpbin.org/get", nil)
	if err != nil {
		log.Fatal(err)
	}

	// appending to existing query args
	q := req.URL.Query()
	q.Add("foo", "bar")

	// assign encoded query string to http request
	req.URL.RawQuery = q.Encode()

	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Errored when sending request to the server")
		return
	}

	defer resp.Body.Close()
	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(resp.Status)
	fmt.Println(string(responseBody))
}

POST

The following example sends a POST request with data in JSON format.

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

func main() {
	values := map[string]string{"foo": "baz"}
	jsonData, err := json.Marshal(values)

	req, err := http.NewRequest(http.MethodPost, "https://httpbin.org/post", bytes.NewBuffer(jsonData))
	if err != nil {
		log.Fatal(err)
	}

	// appending to existing query args
	q := req.URL.Query()
	q.Add("foo", "bar")

	// assign encoded query string to http request
	req.URL.RawQuery = q.Encode()

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Errored when sending request to the server")
		return
	}

	defer resp.Body.Close()
	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(resp.Status)
	fmt.Println(string(responseBody))
}

Best Practices

Re-use HTTP Client

The HTTP 1.1 protocol supports HTTP Persistent connections, or also known as HTTP Keep-Alive. This allows a client and a server to re-use the same underlying TCP connection when sending multiple HTTP Requests/Responses. So instead of establishing a connection for each HTTP Request, the client re-uses the TCP connection previously created more than once. This is particularly useful for performance reasons and when sending multiple requests to the same host.

func httpClient() *http.Client {
	client := &http.Client{Timeout: 10 * time.Second}
	return client
}

Reuse the http.Client throughout your code base.

An example of it as follows:

package main

import (
	"bytes"
	"io/ioutil"
	"log"
	"net/http"
	"time"
)

func httpClient() *http.Client {
	client := &http.Client{Timeout: 10 * time.Second}
	return client
}

func sendRequest(client *http.Client, method string) []byte {
	endpoint := "https://httpbin.org/post"
      values := map[string]string{"foo": "baz"}
	jsonData, err := json.Marshal(values)

	req, err := http.NewRequest(method, endpoint, bytes.NewBuffer(jsonData))
	if err != nil {
		log.Fatalf("Error Occurred. %+v", err)
	}

	response, err := client.Do(req)
	if err != nil {
		log.Fatalf("Error sending request to API endpoint. %+v", err)
	}

	// Close the connection to reuse it
	defer response.Body.Close()

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		log.Fatalf("Couldn't parse response body. %+v", err)
	}

	return body
}

func main() {
  // c should be re-used for further calls
	c := httpClient()
	response := sendRequest(c, http.MethodPost)
	log.Println("Response Body:", string(response))
}


Mailazy Docs

Integrate with Transactional email service in minutes

click here

Most Popular Tags

EngineeringSMTPShort ReadBest PracticesEmailAPIsEmail SecurityCommunicationEmail APIEmail Delivery



What is Mailazy?

Mailazy is a Transactional Email Platform specially built for developers which satisfies the requirement for use cases like Reset Password Emails, OTP Emails, Welcome Emails, and so on. The Mailazy platform helps you to send transactional emails seamlessly and track email deliverability. Mailazy enables your applications to send messages via a simple HTTP REST interface or via easy SMTP integration and abstracts away the complexities of sending transactional emails.

Visit website

Pranav Sharma

Pranav Sharma

Pranav Sharma is a Lead Software Development Engineer at Mailazy. He graduated in Computer Science and considers himself a learner of life. He loves to play cricket, football and computer games.

View Profile