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

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

Kunal Saini
Kunal Saini
July 01, 2021
2 min read

Send Transactional emails With Confidence

Our dedicated support team works around the clock because transactional emails never stop.

Free Sign UpSet up in 2 minutes . No Credit Card Required

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 ReadAPIsBest PracticesEmail SecurityEmailEmail TemplatesGolangMarketing Email



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. Mailazy has built to serve their customers a high value transactional email service. Sending transactional emails shouldn’t be hard with the right transaction email service. With an email service provider or simple transactional email service like Mailazy, you can easily send and track your transactional emails. Our goal is to help you achieve high delivery rates and keep your transactional emails out of the spam folder. We are always there for whenever ypu need us.

Lets get started!

Kunal Saini

Kunal Saini

Kunal 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