Go or Go lang as it’s commonly referred to is a wannabe system’s programming language originally designed and developed at Google, it’s aim was to be the ultimate replacement for C/C++. Go incorporates modern programming language features like type inference and generics while presenting itself in an effortless and minimalist style, Go has borrowed concepts from Typescript, Javascript, and Python.
Go has been used to buy some awesome projects like the open-source Pocketbase server amongst others and in today’s post we will expo how to set a basic REST server with Go and as such we will cover the following talking points;
- Project Setup
- Create a basic Server with net/http
- Parsing request headers
- Parsing request query params
- Parsing request body
Project Setup
The first thing to do is to ensure you have the Go compiler installed on your machine, if you don’t have it installed then you can download and install the Go executable and ensure that the GoPath is correctly configured. Now let’s set up a Go project, first navigate into your projects directory to create a Go project.
mkdir go_server && go mod init
This will create a go package for us, now we need to navigate into the newly created folder and create a new go file, index.go
. This file will house the content of our server.
cd go_server
Create a basic Server with net/http
Now we have our project all set up let's add the following code to our index.go
file,
package main
import (
"fmt"
"log"
"net/http"
)
func sayHello(w http.ResponseWriter, req *htt.Reques) {
fmt.FPrintf(w, "Hello World")
}
main () {
http.handleFunc("/", sayHello);
log.Println("Server listening on port", 8080);
http.ListenAndServer(":8080", nil);
}
The code snippet above demonstrates how to set up a basic HTTP server with Go, we need to declare a package for the current Go module, and then we import a bunch of packages from the standard Go library, the fmt
package is responsible for formatted printing and input/output operations. The log
package in the Go standard library provides basic logging functionality. The net/http package in the Go standard library provides a powerful and comprehensive set of tools for building both HTTP servers and clients in Go.
The sayHello
function is a route handler function, it accepts two arguments, the first is the response object, while the second is the request object. We use the FPrintf
function to write a message to the response body, this also effectively ends the request. Inside our main function, we register the sayHello
function as a handler for the /
route. Then we use the Println
function from the log
package to notify us when our server starts up. Then we use the ListenAndServe
method on the http
package to create a server on port 8080
.
The ListenAndServe
method accepts two arguments, The first is a string that specifies the network address and port on which the server will listen for incoming HTTP requests. It's typically formatted as "hostname:port" or just ":port". The second argument is an optional interface that can be used to customize the overall request-handling behavior of the server. In most cases, you'll leave this argument as nil and rely on specific handler functions registered using http.HandleFunc or other routing mechanisms.
Parsing request headers
There are times when you are interested in parsing the request and that is standard when building an API so in the next snippet we'll see how we can do just that;
package main
// cont'd
var headers map[string]string
func sayHello(w http.ResponseWriter, req *http.Request) {
for key, values := range req.Header {
headers[key] = values[0]
}
log.Println(headers) // do h
fmt.Fprint(w, "Hello, World!")
}
// cont'd
main () {
headers = make(map[string]string)
// cont'd
}
First, we create a new map object header
to store the contents of the request headers, inside our main
function we initialize the headers
to be an empty map object. Inside the sayHello
function we loop through the request headers and for each key on the request header we create a similar key on the headers
map object and its value is the value of the key on the request header then we print the headers
object to the console.
Parsing Request Query Parameters
To parse the request query parameters we just need to add a few extra lines of code to our handler function;
// cont'd
func sayHello(w http.ResponseWriter, req *http.Request) {
// cont'd
// Get all query parameters as a map
queryParams := req.URL.Query()
// Access specific parameters
name := queryParams.Get("name")
log.Println(name)
// cont'd
}
// cont'd
We use the req.URL.Query()
method of the http.Request
object to access the query string parameters as a url.Values
map. Then queryParams.Get("name")
retrieves the value for the "name" parameter as a string or an empty string if not present.
Parsing request body
package main
import (
"encoding/json"
"io"
// cont'd
)
type Payload struct {
Id string
}
// cont'd
func sayHello (w http.ResponeWriter, req http.Request) {
// cont'd
body, err := io.ReadAll(req.Body)
if err != nil {
log.Println("Error reading request body:", err)
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, "Error reading request body")
return
}
var payload Payload
err = json.Unmarshal(body, &payload)
if err != nil {
log.Println("Error parsing JSON body:", err)
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, "Invalid JSON format in request body")
return
}
log.Println("payload", payload.Id)
// cont'd
}
// cont'd
We have imported two new packages encoding/json
and io
. Next, we create a struct to serve as a type for the request body. Inside our handler function we call io.ReadAll
and pass the req.Body
as an argument to the ReadAll
method we just called.
This method returns two values we can destructre out, the request body and an error object. If there's an error we notify the user and end the request, otherwise we create a payload variable of type Payload
and call json.UnMarshall
and pass the body
as the first argument to it and a pointer to the payload
variable we just created. If there’s an error while trying to convert the body of the request we notify the user that their JSON is invalid then we end the request as a bad request, otherwise, we just log out the Id
of the payload and continue with the rest of the code.
Top comments (0)