Intro
Go has a strong standard library. Using this, it is easy to develop a simple REST API without
installing any additional dependencies. Although packages like gin are often used, I think it
is useful to do exercises like this to understand what Go can offer out of the box. In this
article, I'll show how to build a simple API that can handle GET and POST requests using the
net/http
package which is available as part of the Go standard library.
All the code in this article can be found in GitHub: https://github.com/MarkyMan4/go-rest-api
Getting Started
Create a file called main.go
and add the following code.
This is all it takes to get a basic end point running. There are a couple key components in this code.
The Book
type defines what the JSON data looks like. This is the structure of the JSON
that will be returned from the end point. Instead of setting up a database for this toy API, I just
created a JSON file with the data I want to work with. The data in that file can be directly read into a
Book
as well. The data I created can be found here.
The main
function sets up handling for different URLs. We can see that when we send a request to /books
,
the HandleBooks
function will be called. Also, the main
function starts the web server and tells which
port will be used. Based on what is set up here, we would be able to send and HTTP request to http://localhost:5000/books
.
The last component is the HandleBooks
function. This function contains the code that will run when a request is
sent to /books
. Since we want the response to be json, the Content-Type
is set accordingly in the
header of the response. The data is read in from a file (in a real API this would most likely read the data from a database instead).
Finally, the data is written to the response.
Now the server can be started with the command:
$ go run main.go
Send a request the end point with this command:
$ curl http://localhost:5000/books
Or to pretty print the JSON, you can pipe the result into json_pp
:
$ curl http://localhost:5000/books | json_pp
The response is all the contents of the data.json
file.
Handling HTTP Methods
Now I'll show how to handle both GET and POST request. I'll also show how to handle the case when an HTTP method is used that we do not handle (e.g. PUT, DELETE). I won't put the full code in this article, but it can be found here.
The handle books function should be refactored to simply determine which function to call based on what HTTP method was used. Notice that if the request was not a GET or POST, we'll get a bad request and a message.
The code to list the books which was used previously can be moved to a different function which gets called upon receiving a
GET request to /books
. The code for actually retrieving the books from the "database" (which in this example is
just a JSON file) got moved to a separate method as well. Again, the full code can be viewed in GitHub to see how the data
is retrieved from the JSON file.
Finally, we have the CreateBook
function which is called when a POST request is sent to /books
. This
function expects JSON to come in the body of the request which has the fields we need to create a book. If any errors happen
while reading the body or trying to unmarshal the body into a Book type, an appropriate message will be written to the
response. If successful, this method will return a 201 response to indicate that the book was successfully created. The
book that was created will also get sent in the body of the response.
Testing
The method I showed previously for getting all the books can be used the same as earlier:
$ curl http://localhost:5000/books
To create a book, the following request can be made:
$ curl -X POST --data '{"id": 7, "title": "test title", "author": "test author", "publicationYear": 2000, "genre": "horror"}' http://localhost:5000/books
If successful, the response will contain the data that was passed in the body.
Finally, we can make another GET request and see the newly created item shows up.
Conclusion
In this article, I've shown how to create a simple REST API using only the Go standard library. I wrote this article to show what can be accomplished without relying on any third-party libraries and to show how Go keeps things simple. I'm still learning Go myself, so I think it is good to understand how an API can be written in pure Go. It helps provide a better understanding of what is happening under the hood when using a package like gin.