ARTICLE AD BOX
The writer selected nan Diversity successful Tech Fund to personification a assistance arsenic information of nan Write for DOnations program.
Introduction
When a programme needs to walk pinch different program, galore developers will usage HTTP. One of Go’s strengths is nan breadth of its modular library, and HTTP is nary exception. The Go net/http package not only supports creating HTTP servers, but it tin too make HTTP requests arsenic a client.
In this tutorial, you will create a programme that makes respective types of HTTP requests to an HTTP server. First, you will make a GET petition utilizing nan default Go HTTP client. Then, you will heighten your programme to make a POST petition pinch a body. Finally, you will customize your POST petition to spot an HTTP header and adhd a timeout that will trigger if your petition takes excessively long.
Prerequisites
To recreation this tutorial, you will need:
- Go type 1.16 aliases greater installed. To group this up, recreation nan How To Install Go tutorial for your operating system.
- Experience creating an HTTP server successful Go, which tin beryllium recovered successful nan tutorial, How To Make an HTTP Server successful Go.
- Familiarity pinch goroutines and reference channels. For overmuch information, spot nan tutorial, How To Run Multiple Functions Concurrently successful Go.
- An knowing of really an HTTP petition is composed and sent is recommended.
Making a GET Request
The Go net/http package has a less different ways to usage it arsenic a client. You tin usage a common, world HTTP customer pinch functions specified arsenic http.Get to quickly make an HTTP GET petition pinch only a URL and a body, aliases you tin create an http.Request to statesman customizing definite aspects of nan individual request. In this section, you will create an first programme utilizing http.Get to make an HTTP request, and past you will update it to usage an http.Request pinch nan default HTTP client.
Using http.Get to Make a Request
In nan first loop of your program, you’ll usage nan http.Get usability to make a petition to nan HTTP server you tally successful your program. The http.Get usability is useful because you don’t petition immoderate further setup successful your programme to make a request. If you petition to make a azygous speedy request, http.Get whitethorn beryllium nan champion option.
To commencement creating your program, you’ll petition a directory to support nan program’s directory in. In this tutorial, you’ll usage a directory named projects.
First, make nan projects directory and navigate to it:
mkdir projects cd projects
Next, make nan directory for your task and navigate to it. In this case, usage nan directory httpclient:
mkdir httpclient cd httpclient
Inside nan httpclient directory, usage nano, aliases your favourite editor, to unfastened nan main.go file:
nano main.go
In nan main.go file, statesman by adding these lines:
main.go
package main import ( "errors" "fmt" "net/http" "os" "time" ) const serverPort = 3333
You adhd nan package punishment main truthful that your programme is compiled arsenic a programme you tin run, and past spot an import relationship pinch nan various packages you’ll beryllium utilizing successful this program. After that, you create a const called serverPort pinch nan worthy 3333, which you’ll usage arsenic nan larboard your HTTP server is listening connected and nan larboard your HTTP customer will nexus to.
Next, create a main usability successful nan main.go grounds and group up a goroutine to commencement an HTTP server:
main.go
... func main() { go func() { mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Printf("server: %s /\n", r.Method) }) server := http.Server{ Addr: fmt.Sprintf(":%d", serverPort), Handler: mux, } if err := server.ListenAndServe(); err != nil { if !errors.Is(err, http.ErrServerClosed) { fmt.Printf("error moving http server: %s\n", err) } } }() time.Sleep(100 * time.Millisecond)
Your HTTP server is group up to usage fmt.Printf to group accusation astir incoming requests whenever nan guidelines / measurement is requested. It’s too group to comprehend connected serverPort. Finally, erstwhile you commencement up nan server goroutine, your programme uses time.Sleep for a short magnitude of time. This slumber clip allows nan HTTP server nan clip it needs to commencement up and commencement serving responses to nan petition you’ll beryllium making next.
Now, too successful nan main function, group up nan petition URL utilizing fmt.Sprintf to harvester nan http://localhost hostname pinch nan serverPort worthy nan server is listening on. Then, usage http.Get to make a petition to that URL, arsenic shown below:
main.go
... requestURL := fmt.Sprintf("http://localhost:%d", serverPort) res, err := http.Get(requestURL) if err != nil { fmt.Printf("error making http request: %s\n", err) os.Exit(1) } fmt.Printf("client: sewage response!\n") fmt.Printf("client: position code: %d\n", res.StatusCode) }
When nan http.Get usability is called, Go will make an HTTP petition utilizing nan default HTTP customer to nan URL provided, past return either an http.Response aliases an correction worthy if nan petition fails. If nan petition fails, it will group nan correction and past exit your programme utilizing os.Exit pinch an correction codification of 1. If nan petition succeeds, your programme will group retired that it sewage a consequence and nan HTTP position codification it received.
Save and adjacent nan grounds erstwhile you’re done.
To tally your program, usage nan spell tally bid and proviso nan main.go grounds to it:
go tally main.go
You will spot nan pursuing output:
Output
server: GET / client: sewage response! client: position code: 200
On nan first connection of output, nan server prints that it received a GET petition from your customer for nan / path. Then, nan pursuing 2 lines opportunity that nan customer sewage a consequence backmost from nan server and that nan response’s position codification was 200.
The http.Get usability is useful for speedy HTTP requests for illustration nan 1 you made successful this section. However, http.Request provides a broader scope of options for customizing your request.
Using http.Request to Make a Request
In guidance to http.Get , nan http.Request usability provides you pinch greater powerfulness complete nan request, different than conscionable nan HTTP method and nan URL being requested. You won’t beryllium utilizing further features yet, but by utilizing an http.Request now, you’ll beryllium tin to adhd those customizations later successful this tutorial.
In your code, nan first update is to alteration nan HTTP server handler to return a clone JSON accusation consequence utilizing fmt.Fprintf. If this were a afloat HTTP server, this accusation would beryllium generated utilizing Go’s encoding/json package. If you’d for illustration to study overmuch astir utilizing JSON successful Go, our How To Use JSON successful Go tutorial is available. In addition, you will too petition to spot io package arsenic an import for usage later successful this update.
Now, unfastened your main.go grounds again and update your programme to commencement utilizing an http.Request arsenic shown below:
main.go
package main import ( ... "io" ... ) ... func main() { ... mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Printf("server: %s /\n", r.Method) fmt.Fprintf(w, `{"message": "hello!"}`) }) ...
Now, update your HTTP petition codification truthful that alternatively of utilizing http.Get to make a petition to nan server, you usage http.NewRequest and http.DefaultClient’s Do method:
main.go
... requestURL := fmt.Sprintf("http://localhost:%d", serverPort) req, err := http.NewRequest(http.MethodGet, requestURL, nil) if err != nil { fmt.Printf("client: could not create request: %s\n", err) os.Exit(1) } res, err := http.DefaultClient.Do(req) if err != nil { fmt.Printf("client: correction making http request: %s\n", err) os.Exit(1) } fmt.Printf("client: sewage response!\n") fmt.Printf("client: position code: %d\n", res.StatusCode) resBody, err := io.ReadAll(res.Body) if err != nil { fmt.Printf("client: could not publication consequence body: %s\n", err) os.Exit(1) } fmt.Printf("client: consequence body: %s\n", resBody) }
In this update, you usage nan http.NewRequest usability to make an http.Request value, aliases grip nan correction if nan worthy can’t beryllium created. Unlike nan http.Get function, though, nan http.NewRequest usability doesn’t nonstop an HTTP petition to nan server correct away. Since it doesn’t nonstop nan petition correct away, you tin make immoderate changes you’d for illustration to nan petition earlier it’s sent.
Once nan http.Request is created and configured, you usage nan Do method of http.DefaultClient to nonstop nan petition to nan server. The http.DefaultClient worthy is Go’s default HTTP client, nan aforesaid you’ve been utilizing pinch http.Get. This time, though, you’re utilizing it consecutive to show it to nonstop your http.Request. The Do method of nan HTTP customer returns nan aforesaid values you received from nan http.Get usability truthful that you tin grip nan consequence successful nan aforesaid way.
After you’ve printed nan petition results, you usage nan io.ReadAll usability to publication nan HTTP response’s Body. The Body is an io.ReadCloser value, a cognition of io.Reader and io.Closer, which intends you tin publication nan body’s accusation utilizing point that tin publication from an io.Reader value. The io.ReadAll usability is useful because it will publication from an io.Reader until it either gets to nan extremity of nan accusation aliases encounters an error. Then it will either return nan accusation arsenic a []byte worthy you tin group utilizing fmt.Printf, aliases nan correction worthy it encountered.
To tally your updated program, prevention your changes and usage nan spell tally command:
go tally main.go
This time, your output should look very akin to before, but pinch 1 addition:
Output
server: GET / client: sewage response! client: position code: 200 client: consequence body: {"message": "hello!"}
In nan first line, you spot that nan server is still receiving a GET petition to nan / path. The customer too receives a 200 consequence from nan server, but it’s too reference and printing nan Body of nan server’s response. In a overmuch analyzable program, you could past return nan {"message": "hello!"} worthy you received arsenic nan assemblage from nan server and process it arsenic JSON utilizing nan encoding/json package.
In this section, you created a programme pinch an HTTP server that you made HTTP requests to successful various ways. First, you utilized nan http.Get usability to make a GET petition to nan server utilizing only nan server’s URL. Then, you updated your programme to usage http.NewRequest to create an http.Request value. Once that was created, you utilized nan Do method of Go’s default HTTP client, http.DefaultClient, to make nan petition and group nan http.Response Body to nan output.
The HTTP protocol uses overmuch than conscionable GET requests to walk betwixt programs, though. A GET petition is useful erstwhile you want to personification accusation from nan different program, but different HTTP method, nan POST method, tin beryllium utilized erstwhile you want to nonstop accusation from your programme to nan server.
Sending a POST Request
In a REST API, a GET petition is only utilized for retrieving accusation from nan server, truthful for your programme to afloat participate successful a REST API, your programme too needs to support sending POST requests. A POST petition is almost nan inverse of a GET request, wherever nan customer sends accusation to nan server successful nan request’s body.
In this section, you will update your programme to nonstop your petition arsenic a POST petition alternatively of a GET request. Your POST petition will spot a petition body, and you will update your server to group retired overmuch accusation astir nan requests you’re making from nan client.
To commencement making these updates, unfastened your main.go grounds and adhd a less caller packages that you’ll beryllium utilizing to your import statement:
main.go
... import ( "bytes" "errors" "fmt" "io" "net/http" "os" "strings" "time" ) ...
Then, update your server handler usability to group retired various accusation astir nan petition coming in, specified arsenic query drawstring values, header values, and nan petition body:
main.go
... mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Printf("server: %s /\n", r.Method) fmt.Printf("server: query id: %s\n", r.URL.Query().Get("id")) fmt.Printf("server: content-type: %s\n", r.Header.Get("content-type")) fmt.Printf("server: headers:\n") for headerName, headerValue := range r.Header { fmt.Printf("\t%s = %s\n", headerName, strings.Join(headerValue, ", ")) } reqBody, err := io.ReadAll(r.Body) if err != nil { fmt.Printf("server: could not publication petition body: %s\n", err) } fmt.Printf("server: petition body: %s\n", reqBody) fmt.Fprintf(w, `{"message": "hello!"}`) }) ...
In this update to nan server’s HTTP petition handler, you adhd a less overmuch adjuvant fmt.Printf statements to spot accusation astir nan petition coming in. You usage r.URL.Query().Get to get a query drawstring worthy named id, and r.Header.Get to get nan worthy of a header called content-type. You too usage a for loop pinch r.Header to group nan punishment and worthy of each HTTP header nan server received. This accusation tin beryllium useful for troubleshooting issues if your customer aliases server isn’t acting nan measurement you expect. Finally, you too utilized nan io.ReadAll usability to publication nan HTTP request’s assemblage successful r.Body.
After updating nan server handler function, update nan main function’s petition codification truthful that it’s sending a POST petition pinch a petition body:
main.go
... time.Sleep(100 * time.Millisecond) jsonBody := []byte(`{"client_message": "hello, server!"}`) bodyReader := bytes.NewReader(jsonBody) requestURL := fmt.Sprintf("http://localhost:%d?id=1234", serverPort) req, err := http.NewRequest(http.MethodPost, requestURL, bodyReader) ...
In your update to nan main function’s request, 1 of nan caller values you’re defining is nan jsonBody value. In this example, nan worthy is represented arsenic a []byte alternatively of nan modular drawstring because if you usage nan encoding/json package to encode JSON data, it will springiness you a []byte backmost alternatively of a string.
The adjacent value, nan bodyReader, is simply a bytes.Reader that wraps nan jsonBody data. An http.Request assemblage requires nan worthy to beryllium an io.Reader, and jsonBody’s []byte worthy doesn’t instrumentality io.Reader, truthful you wouldn’t beryllium tin to usage it arsenic a petition assemblage connected its own. The bytes.Reader worthy exists to proviso that io.Reader interface, truthful you tin usage nan jsonBody worthy arsenic nan petition body.
The requestURL worthy is too updated to spot an id=1234 query drawstring value, chiefly to show really a query drawstring worthy tin too beryllium included successful nan petition URL connected pinch different modular URL components.
Finally, nan http.NewRequest usability telephone is updated to usage a POST method pinch http.MethodPost, and nan petition assemblage is included by updating nan past parameter from a nil assemblage to bodyReader, nan JSON accusation io.Reader.
Once you’ve saved your changes, you tin usage spell tally to tally your program:
go tally main.go
The output will beryllium longer than earlier because of your updates to nan server to show further information:
Output
server: POST / server: query id: 1234 server: content-type: server: headers: Accept-Encoding = gzip User-Agent = Go-http-client/1.1 Content-Length = 36 server: petition body: {"client_message": "hello, server!"} client: sewage response! client: position code: 200 client: consequence body: {"message": "hello!"}
The first connection from nan server shows that your petition is now coming done arsenic a POST petition to nan / path. The 2nd connection shows nan 1234 worthy of nan id query drawstring worthy you added to nan request’s URL. The 3rd connection shows nan worthy of nan Content-Type header nan customer sent, which happens to beryllium quiet successful this request.
The 4th connection whitethorn beryllium somewhat different from nan output you spot above. In Go, nan bid of a practice worthy is not guaranteed erstwhile you iterate complete them utilizing range, truthful your headers from r.Headers whitethorn group retired successful a different order. Depending connected nan Go type you’re using, you whitethorn too spot a different User-Agent type than nan 1 above.
Finally, nan past alteration successful nan output is that nan server is showing nan petition assemblage it received from nan client. The server could past usage nan encoding/json package to parse nan JSON accusation nan customer sent and formulate a response.
In this section, you updated your programme to nonstop an HTTP POST petition alternatively of a GET request. You too updated your programme to nonstop a petition assemblage pinch []byte accusation being publication by a bytes.Reader. Finally, you updated nan server handler usability to group retired overmuch accusation astir nan petition your HTTP customer is making.
Typically successful an HTTP request, nan customer aliases nan server will show nan different nan type of contented it’s sending successful nan body. As you saw successful nan past output, though, your HTTP petition didn’t spot a Content-Type header to show nan server really to construe nan body’s data. In nan adjacent section, you’ll make a less updates to customize your HTTP request, including mounting a Content-Type header to fto nan server cognize nan type of accusation you’re sending.
Customizing an HTTP Request
Over time, HTTP requests and responses personification been utilized to nonstop a greater assortment of accusation betwixt clients and servers. At 1 point, HTTP clients could presume nan accusation they’re receiving from an HTTP server is HTML and personification a bully chance of being correct. Now, though, it could beryllium HTML, JSON, music, video, aliases immoderate number of different accusation types. To proviso overmuch accusation astir nan accusation being sent complete HTTP, nan protocol includes HTTP headers, and 1 of those important headers is nan Content-Type header. This header tells nan server (or client, depending connected nan guidance of nan data) really to construe nan accusation it’s receiving.
In this section, you will update your programme to group nan Content-Type header connected your HTTP petition truthful nan server knows it’s receiving JSON data. You will too update your programme to usage an HTTP customer different than Go’s default http.DefaultClient truthful that you tin customize really nan petition is sent.
To make these updates, unfastened your main.go grounds again and update your main usability for illustration so:
main.go
... req, err := http.NewRequest(http.MethodPost, requestURL, bodyReader) if err != nil { fmt.Printf("client: could not create request: %s\n", err) os.Exit(1) } req.Header.Set("Content-Type", "application/json") customer := http.Client{ Timeout: 30 * time.Second, } res, err := client.Do(req) if err != nil { fmt.Printf("client: correction making http request: %s\n", err) os.Exit(1) } ...
In this update, you entree nan http.Request headers utilizing req.Header, and past group nan worthy of nan Content-Type header connected nan petition to application/json. The application/json media type is defined successful nan database of media types arsenic nan media type for JSON. This way, erstwhile nan server receives your request, it knows to construe nan assemblage arsenic JSON and not, for example, XML.
The adjacent update is to create your ain http.Client suit successful nan customer variable. In this client, you group nan Timeout worthy to 30 seconds. This is important because it says that immoderate requests made pinch nan customer will springiness up and extremity trying to personification a consequence aft 30 seconds. Go’s default http.DefaultClient doesn’t specify a timeout, truthful if you make a petition utilizing that client, it will clasp until it receives a response, is disconnected by nan server, aliases your programme ends. If you personification galore requests hanging astir for illustration this waiting for a response, you could beryllium utilizing a ample number of resources connected your computer. Setting a Timeout worthy limits really agelong a petition will clasp by nan clip you define.
Finally, you updated your petition to usage nan Do method of your customer variable. You don’t petition to make immoderate different changes coming because you’ve been calling Do connected an http.Client worthy nan afloat time. Go’s default HTTP client, http.DefaultClient, is conscionable an http.Client that’s created by default. So, erstwhile you called http.Get, nan usability was calling nan Do method for you, and erstwhile you updated your petition to usage http.DefaultClient, you were utilizing that http.Client directly. The only value now is that you created nan http.Client worthy you’re utilizing this time.
Now, prevention your grounds and tally your programme utilizing spell run:
go tally main.go
Your output should beryllium very akin to nan erstwhile output but pinch overmuch accusation astir nan contented type:
Output
server: POST / server: query id: 1234 server: content-type: application/json server: headers: Accept-Encoding = gzip User-Agent = Go-http-client/1.1 Content-Length = 36 Content-Type = application/json server: petition body: {"client_message": "hello, server!"} client: sewage response! client: position code: 200 client: consequence body: {"message": "hello!"}
You’ll spot there’s a worthy from nan server for content-type, and there’s a Content-Type header being sent by nan client. This is really you could personification nan aforesaid HTTP petition measurement serving immoderate a JSON and an XML API astatine nan aforesaid time. By specifying nan request’s contented type, nan server and nan customer tin construe nan accusation differently.
This illustration doesn’t trigger nan customer timeout you configured, though. To spot what happens erstwhile a petition takes excessively agelong and nan timeout is triggered, unfastened your main.go grounds and adhd a time.Sleep usability telephone to your HTTP server handler function. Then, make nan time.Sleep past for longer than nan timeout you specified. In this case, you’ll group it for 35 seconds:
main.go
... func main() { go func() { mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { ... fmt.Fprintf(w, `{"message": "hello!"}`) time.Sleep(35 * time.Second) }) ... }() ... }
Now, prevention your changes and tally your programme utilizing spell run:
go tally main.go
When you tally it this time, it will return longer to exit than earlier because it won’t exit until aft nan HTTP petition is finished. Since you added nan time.Sleep(35 * time.Second), nan HTTP petition won’t complete until nan 30-second timeout is reached:
Output
server: POST / server: query id: 1234 server: content-type: application/json server: headers: Content-Type = application/json Accept-Encoding = gzip User-Agent = Go-http-client/1.1 Content-Length = 36 server: petition body: {"client_message": "hello, server!"} client: correction making http request: Post "http://localhost:3333?id=1234": sermon deadline exceeded (Client.Timeout exceeded while awaiting headers) exit position 1
In this programme output, you spot nan server received nan petition and processed it, but erstwhile it reached nan extremity of nan HTTP handler usability wherever your time.Sleep usability telephone is, it started sleeping for 35 seconds. At nan aforesaid time, nan timeout for your HTTP petition is counting down and reaches nan limit of 30 seconds earlier nan HTTP petition finishes. This results successful nan client.Do method telephone failing pinch a sermon deadline exceeded correction because nan request’s 30-second deadline passed. Then, your programme exits pinch a nonaccomplishment position codification of 1 utilizing os.Exit(1).
In this section, you updated your programme to customize an HTTP petition by adding a Content-Type header to it. You too updated your programme to create a caller http.Client pinch a 30-second timeout, and past utilized that customer to make an HTTP request. You too tested nan 30-second timeout by adding a time.Sleep to your HTTP petition handler. Finally, you too saw why it’s important to usage your ain http.Client values pinch timeouts group if you want to debar galore requests perchance idling forever.
Conclusion
In this tutorial, you created a caller programme pinch an HTTP server and utilized Go’s net/http package to make HTTP requests to that server. First, you utilized nan http.Get usability to make a GET petition to nan server pinch Go’s default HTTP client. Then, you utilized http.NewRequest pinch http.DefaultClient’s Do method to make a GET request. Next, you updated your petition to make it a POST petition pinch a assemblage utilizing bytes.NewReader. Finally, you utilized nan Set method connected an http.Request’s Header conception to group a request’s Content-Type header, and group a 30-second timeout connected a request’s agelong by creating your ain HTTP customer alternatively of utilizing Go’s default client.
The net/http package includes overmuch than conscionable nan functionality you utilized successful this tutorial. It too includes an http.Post usability that tin beryllium utilized to make a POST request, akin to nan http.Get function. The package too supports redeeming and retrieving cookies, among different features.
This tutorial is too information of nan DigitalOcean How to Code successful Go series. The bid covers a number of Go topics, from installing Go for nan first clip to really to usage nan relationship itself.