paint-brush
Building a Simple Rest API with Goby@tansawit
579 reads
579 reads

Building a Simple Rest API with Go

by Sawit TrisirisatayawongFebruary 3rd, 2020
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Building a Simple Rest API with Go's Go language, we use the language's official getting started guide. This article assumes that you have go installed and working on your computer. We first need to define our program and import the necessary packages. The code is responsible for writing the response code and writing the code. The response code is the code that reads the request and reads the code in the response. We also need to use a struct type to store useful information in it. We use the function to write the code and run through each line of the code, and the response is written in the context of the function.

Company Mentioned

Mention Thumbnail
featured image - Building a Simple Rest API with Go
Sawit Trisirisatayawong HackerNoon profile picture

After recently joining Central Tech, I was given my first project: implement a new product creation and querying API in Go. I took this as a chance for me to finally dive deep into Go, something I've been wanted to do after having heard praises about it from many others. I also decided to start detailing the things I learned along the way, both for personal reference and to ensure that I understand concepts enough to explain it in writing.

As such, this article and my site will hopefully come to act as a resource that I can refer back to, and hopefully be helpful to someone else as well.

Basics

This piece assumes that you have go installed and working on your computer. If not, please see the Go language's official getting started guide.

Before writing the actual functions to execute, we first need to define our program and import the necessary packages. Create a new file called

main.go
and add the following lines.

package main

import (
    "log"
    "net/http"
)

Let's go over each of the components of the code above.

Packages

Packages are Go's source code, organized into system directories. They allow for code reusability across different applications. In order to differentiate an executable program from a library to be used by other programs, Go dictates that we includes

package main
in the header of the main file of any executables. When compiling, that
package main
tells the Go compiler that the package should compile as an executable program rather than being built as a library.

Imports

The keyword

import
is used for importing packages into our program or another package. When importing packages, the Go compiler will look in the locations specified by the two environment variables:

  • $GOROOT
    where packages from the standard library shipped with Go are stored
  • $GOPATH
    for fetched third-party or self-made packages.
Note: Go by design does not allow declaration of unused import and will adamantly complain about it during compile time if any is found

In our case, both packages comes from the standard library:

  • log
    allows us to log errors and other issues.
  • net/http
    gives us HTTP client and server implementation for building the actual API

After declaring the packages, we can begin defining and serving our API. Without using third party libraries and routers, there are two main 'approaches' to this.

If we implement our handler as a function, we'd use

http.HandleFunc
. Otherwise, if we'd implemented our handler as a type with a
ServeHTTP
method, we'd use
http.Handle
.

For simple implementations, the first option is much easier and clearer to read and understand. But using a struct type allows storing of useful information in it, an example of which is the file server from the standard library. The struct contains the root directory for file service. See this Stack Overflow post for a more detailed explanation.

As our program is rather simple and straightforward, we'll stick to the first approach.

Note: HTTP handlers are processes that runs in response to a request made to a web application. For more information, see its Wikipedia page

Building a Web Server

Now we get to defining how our API server will actually behave, and the content we're going to send as our response. Add the following lines below our imports and package declarations:

func apiResponse(w http.ResponseWriter, r *http.Request) {
  w.WriteHeader(http.StatusOK)
  w.Header().Set("Content-Type", "application/json")
  w.Write([]byte(`{"message":"hello world!"}`))
}

func main() {
  http.HandleFunc("/",apiResponse)
  log.Fatal(http.ListenAndServe(":8080",nil))
}

Again, let's run through each function.

apiResponse

The function apiResponse is responsible for writing the response code and JSON. The function itself takes two arguments:

w
of type
http.ResponseWriter
assembles our HTTP server's responses, while
r
reads and parse the requests. Now to go through each line of the function:

-

w.WriteHeader(http.StatusOK)
writes the HTTP response code 200, indicating that the requested resource (the JSON response in our case) has been successfully fetched and is transmitted in the message body.

-

w.Header().Set("Content-Type", "application/json")
indicates the return type of the requested resource.

-

w.Write([]byte('{"message":"hello world!"}'))
finally writes our response in the message body.

main

The

main()
function serves a special purpose in Go: it acts as the entry point of the executable programs. It does not take any argument nor return anything. And unlike some other languages, we do not need to explicitly call
main
, as Go automatically calls the function when run.

In our main function, the

HandleFunc
call tells the HTTP package to handle all requests to the web root ("/") with our apiResponse function. It then calls
http.ListenAndServe
, specifying that it should listen on port
8080
on any interface.

If we now run the command

go run .
and navigate to
localhost:8080
on our web browser, we should see something like this.

We can also enter the same URL into our REST Client (i.e. Postman, Insomnia, Paw) using the "GET" method to get the same result.

Making it RESTful

Now that our server can return a response, we can configure it to do different things depending on the method being requested.

To do so, we can modify our

apiResponse
function as such:

func apiResponse(w http.ResponseWriter, r *http.Request) {
  // Set the return Content-Type as JSON like before
  w.Header().Set("Content-Type", "application/json")

  // Change the response depending on the method being requested
  switch r.Method {
    case "GET":
      w.WriteHeader(http.StatusOK)
      w.Write([]byte(`{"message": "GET method requested"}`))
    case "POST":
        w.WriteHeader(http.StatusCreated)
        w.Write([]byte(`{"message": "POST method requested"}`))
    default:
        w.WriteHeader(http.StatusNotFound)
        w.Write([]byte(`{"message": "Can't find method requested"}`))
    }
}

Now if we close the previous version of our server with

ctrl-c
and start it once again, we should get different responses depending on the method we requested from our REST Client.

Our final

main.go
should look something like:

package main

import (
    "log"
    "net/http"
)

func apiResponse(w http.ResponseWriter, r *http.Request) {
  // Set the return Content-Type as JSON like before
  w.Header().Set("Content-Type", "application/json")

  // Change the response depending on the method being requested
  switch r.Method {
    case "GET":
      w.WriteHeader(http.StatusOK)
      w.Write([]byte(`{"message": "GET method requested"}`))
    case "POST":
        w.WriteHeader(http.StatusCreated)
        w.Write([]byte(`{"message": "POST method requested"}`))
    default:
        w.WriteHeader(http.StatusNotFound)a
        w.Write([]byte(`{"message": "Can't find method requested"}`))
    }
}

func main() {
  http.HandleFunc("/",apiResponse)
  log.Fatal(http.ListenAndServe(":8080",nil))
}

Closing

This covers the basic of building a REST API server using Go. In later posts I plan on going over the

net/http
library in more detail, as well as using third-party router libraries such as gorillia/mux and go-chi/chi for more complex routings.

If you have any questions, feel free to reach out to me on Twitter or via email.