In this section you're going to learn everything you need to know to write a web servers and clients in Go.
The net/http
package provides a series of functions and types to help you sending HTTP requests.
The most important types are:
We'll get to see how those types work in a minute. But before that it is important to realize that there's helper functions that will make our life easier here too.
One of those helper functions is Get
.
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
// try changing the value of this url
res, err := http.Get("https://golang.org")
if err != nil {
log.Fatal(err)
}
fmt.Println(res.Status)
}
This program will send a GET HTTP request to the Go homepage and will print the status code of the response, unless something goes wrong in which case it will log the error and stop the execution of the program.
Try changing the value of the URL to see what other codes you're able to get. Some ideas you could try:
- https://golang.org/foo
- https://thisurldoesntexist.com
- https:/thisisnotaurl
The Get
function we just used returns a Response
and an error
.
Read the documentation of Response
and modify get.go
so it prints a message only when the status code of the response is 404.
The Response
type also has a Body
field of type io.ReadCloser
.
The type of this field is a big hint on what we can do with it: read it and close it.
Modify the program get.go
so it will also print the body of the Response
onto the standard output.
Remember that the Body
should be closed at the end of your program to avoid leaking memory!
The Get
method we just used is a helper function that calls the Get
method of the http.DefaultClient
.
The Client
type offers some other methods related directly to the HTTP methods we all know:
and the equivalent helper functions:
What if you want to use some other methods? Meet the Do
method.
This method receives a pointer to http.Request
as parameters and return a http.Response
and an error
.
The Request
method provides all the expressivity we need to send any kind of HTTP requests.
For instance, we can create the equivalent request to the original get.go
program:
The Client
type exposes the Do
method that send the given Request
and returns a Response
and an error
.
package main
import (
"fmt"
"log"
"net/http"
)
func doGet() {
req, err := http.NewRequest("GET", "https://golang.org", nil)
if err != nil {
log.Fatalf("could not create request: %v", err)
}
client := http.DefaultClient
res, err := client.Do(req)
if err != nil {
log.Fatalf("http request failed: %v", err)
}
fmt.Println(res.Status)
}
This also allows us to provide a Body
for the Request
, similar to the one we had with the Response
.
The big question is how to create an io.Reader
?
Well, it depends on the type of what you want to read, but if you want to provide a string
it is quite easy.
You can create an io.Reader
from a string
with strings.NewReader
.
Modify the code above to send a PUT request to https://http-methods.appspot.com/YourName/Message.
Replace YourName
with your name, or something unique that no one else might be using.
This will save whatever string you send in the Body of the request so you can retrieve it later with:
$ curl https://http-methods.appspot.com/YourName/Message
The web application behind https://http-methods.appspot.com supports printing all the keys under a namespace.
Try visiting https://http-methods.appspot.com/Hungary/ and you'll see all the keys in that namespace.
To also show the values you can add ?v=true
to the url: https://http-methods.appspot.com/Hungary/?v=true .
Write a program that will fetch and display all the keys and values in a namespace.
Rather than adding the ?v=true
at the end of the URL passed to NewRequest
find the way to add it
directly in the Request
that you pass to Do
.
Good job! You now know pretty much everything there is to know (today) for HTTP clients, requests, and responses. Now, to understand how all of this is handled on the server side, let's go the next section.