Now that the skeleton structure for our project is in place, let’s focus our attention on getting a HTTP server up and running.
To start with, we’ll configure our server to have just one endpoint: /v1/healthcheck. This endpoint will return some basic information about our API, including its current version number and operating environment (development, staging, production, etc.).
URL Pattern
Handler
Action
/v1/healthcheck
healthcheckHandler
Show application information
If you’re following along, open up the cmd/api/main.go file and replace the ‘hello world’ application with the following code:
Creating the healthcheck handler
The next thing we need to do is create the healthcheckHandler method for responding to HTTP requests. For now, we’ll keep the logic in this handler really simple and have it return a plain-text response containing three pieces of information:
A fixed "status: available" string.
The API version from the hard-coded version constant.
The operating environment name from the env command-line flag.
Go ahead and create a new cmd/api/healthcheck.go file:
And then add the following code:
The important thing to point out here is that healthcheckHandler is implemented as a method on our application struct.
This is an effective and idiomatic way to make dependencies available to our handlers without resorting to global variables or closures — any dependency that the healthcheckHandler needs can simply be included as a field in the application struct when we initialize it in main().
We can see this pattern already being used in the code above, where the operating environment name is retrieved from the application struct by calling app.config.env.
Demonstration
OK, let’s try this out. Make sure that all your changes are saved, then use the go run command again to execute the code in the cmd/api package. You should see a log message confirming that the HTTP server is running, similar to this:
While the server is running, go ahead and try visiting localhost:4000/v1/healthcheck in your web browser. You should get a response from the healthcheckHandler which looks like this:
Or alternatively, you can use curl to make the request from your terminal:
If you want, you can also verify that the command-line flags are working correctly by specifying alternative port and env values when starting the application. When you do this, you should see the contents of the log message change accordingly. For example:
Additional Information
API versioning
APIs which support real-world businesses and users often need to change their functionality and endpoints over time — sometimes in a backwards-incompatible way. So, to avoid problems and confusion for clients, it’s a good idea to always implement some form of API versioning.
By prefixing all URLs with your API version, like /v1/healthcheck or /v2/healthcheck.
By using custom Accept and Content-Type headers on requests and responses to convey the API version, like Accept: application/vnd.greenlight-v1.
From a HTTP semantics point of view, using headers to convey the API version is the ‘purer’ approach. But from a user-experience point of view, using a URL prefix is arguably better. It makes it possible for developers to see which version of the API is being used at a glance, and it also means that the API can still be explored using a regular web browser (which is harder if custom headers are required).
Throughout this book we’ll version our API by prefixing all the URL paths with /v1/ — just like we did with the /v1/healthcheck endpoint in this chapter.