Representational State Transfer (REST) is one of the most common ways of building remote APIs in modern software, especially on public APIs that need to be consumed by third-party services/clients. The main reasons why REST is so widely used are the simplicity of the concepts it embraces and its flexibility to adapt whenever those concepts don’t 100% apply to your use case.
I’m going to take a pragmatic rather than a formal approach to describing REST. If you want a more formal definition of REST, you can go to Wikipedia’s REST page and follow some of the references there. So, let’s jump into the concepts.
REST concepts
In REST, there are resources and entities. An entity is an instance of a resource. For example, “users” is a resource that represents the users in the system, but “John Doe” is an instance of that resource, so “John Doe” is an entity. Every resource and entity has a unique way of being identified in the context of REST applications – that is, via a Uniform Resource Identifier (URI). This is the URL that you use to access the resource or entity. For example, resource users could have a URI of https://example.com/api/v1/users
, whereas the “John Doe” entity could have a URI of https://example.com/api/v1/users/42
.
Now that we know what resources and entities are and how we can identify them by their URIs, we need a way to represent their data. How is the “John Doe” entity data represented?
REST doesn’t impose any form of data representation, but the communicating applications need to at least be able to understand the same representation. The reality is that the de facto standard that’s used for representing entities in REST is JavaScript Object Notation (JSON). In some scenarios, you may wish to select a different representation for whatever reason (for example, for performance or compatibility purposes). Other common options are MessagePack, Binary JSON (BSON), and XML.
Now that you understand the basic concepts of entities, resources, URIs, and representation, you have a solid foundation for building applications around REST. However, it’s also important to understand how we operate in those concepts and how we communicate them.
So, let’s talk about how REST leverages HTTP to communicate the operations that we want to apply to resources and entities.
REST and HTTP
Most REST APIs are based on the HTTP protocol and leverage multiple features.
In HTTP, the URL is the URI of a resource or an entity. You can put it in your browser or call it through your code, but at the end of the day, it’s the same concept: it’s a URL that represents a unique resource or entity in REST.
Once you’ve identified the resource or the entity and its URL, you must decide what you’re going to do. What action are you going to take? Are you going to delete the entity? Are you going to create a new one? Are you going to get an existing one?
The way we express the action that we want to execute in REST is done through HTTP verbs. The HTTP protocol defines a set of verbs or actions that you can execute on a URL; these are known as methods in HTTP.
There are multiple methods in HTTP, including GET
, POST
, and DELETE
, and each has an action associated with it in the context of REST, depending on whether it’s a resource or an entity. Let’s take a look:
- REST resource (for example,
/users
):
GET
: List the entities of the resource
POST
: Create a new entity for this resource
DELETE
: This is normally not accepted, but it can mean removing all the entities of the resource
PUT
: Normally not accepted
PATCH
: This is normally not accepted, but it can mean partially updating all the entities of the resource
- REST entity (for example,
/users/123
):
GET
: Get the entity’s information
POST
: Normally not accepted
DELETE
: Delete the entity
PUT
: Update the entire entity
PATCH
: Partially update the entity
Once we have a way to identify resources and entities and execute actions on them, we need a way to pass information in some instances. For example, if I want to create a new entity, I need information about that entity. If I’m creating a user, I need their username, email, name, surname, and any other information that I want to store.
For that, we can use the HTTP body of the request. This body needs to be serialized in a certain format – as I mentioned previously, the de facto standard for serialization is JSON – and we also need to communicate to the server that we’re using that serialization mechanism. To do so, we can use the Content-Type: application/json
header. So, the combination of the Content-Type
header and the request body is enough for the client to convey the necessary information to the server.
The server now knows what action the client wants to execute – and with what data – due to the method in the request being serialized and included in the body of the request. However, we need a way to respond to that. This can also be handled using the HTTP protocol.
HTTP provides two things that are handy in this case: the response body (similar to the request body) and the status code. In REST, the response body will contain the information you’re requesting, as well as the entity or the list of entities. The status code gives you information about what happened with the operation itself.
It’s very important to pay attention to the status code because it gives you information about what happened with your request, and maybe you need to take action and handle something differently. The following are some of the most common HTTP status codes:
200 OK
: Everything went well
201 Created
: A new entity has been created
202 Accepted
: The request has been accepted but hasn’t necessarily been processed
204 No Content
: Everything went well, but no data is available
301 Moved Permanently
: Permanent redirect
302 Moved
: Temporary redirect
304 Not Modified
: The data hasn’t changed (used for caches)
400 Bad Request
: The client sent the wrong data
401 Unauthorized
: Authentication needed
403 Forbidden
: Authorization needed
404 Not found
: Resource or entity doesn’t exist
405 Method Not Allowed
: The action that you’re trying to execute isn’t allowed
500 Internal Server Error
: Something went wrong on the server side
There are other status codes, but they aren’t as widely used as the ones mentioned here.
Once you know the status code and the data that you want to return, which can be done in the request body, you must serialize that to JSON and communicate to the client that you’re using JSON format by using the Content-Type
header.
So, now that we know we need a URI, an HTTP method, an HTTP request body, an HTTP status code, an HTTP response body, and a couple of Content-Type
headers, let’s see some examples of this using curl
.
Let’s imagine we have an API with users
resources in the http://localhost:8888/api/v1/users
URI, and we want to create a new entity for that. We know the resource URI, and because we want to create a new entity, we know that we have to use the POST
verb on the resource URI and pass new user information in the request’s body in JSON format. So, we can do something like this:
$ curl -X POST -d'{"username": "john.doe", "name": "John", "surename": "Doe"}' -H "Content-Type: application/json" http://localhost:8888/api/v1/users
Quick tip: Enhance your coding experience with the AI Code Explainer and Quick Copy features. Open this book in the next-gen Packt Reader. Click the Copy button
(1) to quickly copy code into your coding environment, or click the Explain button
(2) to get the AI assistant to explain a block of code to you.

The next-gen Packt Reader is included for free with the purchase of this book. Scan the QR code OR go to packtpub.com/unlock, then use the search bar to find this book by name. Double-check the edition shown to make sure you get the right one.

If something isn’t OK in the request, we could get something such as a 400 Bad Request
error from our API, but if everything goes well, we expect to receive a 201 Create
status code and an output similar to the following:
{
"id": 42,
"username": "jonh.doe",
"name": "John",
"surname": "Doe",
}
Here, we can see how the HTTP protocol conveys all the information that we need in both directions to decide what to do, how to do it, and what the final result of the operations will be. But that’s only part of the power that comes with the fact that REST is usually built on top of HTTP. Let’s take a look at some of its other advantages.
Other HTTP features used in REST
HTTP is a very rich protocol that provides many different HTTP features that we, as API developers, can leverage to improve our APIs.
Probably the most widely used one is the use of query parameters to convey extra information, such as pagination or filtering. For example, if I don’t want to get all the users in the system, I could use something such as /api/v1/users?page=0&perPage=100
, providing parameters to the users
resource to get only page number 0 and only 100 entities per page. The parameters that are used and their effects are defined by the REST API developer, so there’s no standard way of doing this. However, common patterns are used frequently in REST services.
Another important HTTP feature that’s widely used is cache headers. HTTP provides a set of HTTP headers related to the cache that instruct the server or the client on how we want the cache on the other side to behave. This can imply substantial performance improvements. For example, I can use the Cache-Control: max-age=60
HTTP header to instruct the client to cache this request’s result and use it for 60 seconds. That would help me avoid requesting the same data again during the next 60 seconds if there are more petitions.
The HTTP protocol provides security, authorization, and authentication mechanisms. CORS and the Authorization
header are good examples. HTTP also provides security-related headers, something we’re going to explore more deeply in Chapter 7.
Custom headers are something that can be seen in the REST API. It’s another way to send or receive information between the programs that are communicating. Custom headers are prefixed with X-
to differentiate them from the official headers. For example, I could deliver pagination information by adding headers such as X-Page: 0
and X-Entities-Per-Page: 100
, and perhaps the server could reply with the entities and another header, such as X-Has-Next-Page: true
. This kind of approach isn’t especially common or widely used, but it’s good to know that there’s that possibility.
The last important aspect that has made REST so successful is the fact that it uses a “human-readable” data representation. A huge percentage of APIs use JSON as their serialization mechanism, allowing the API consumers to inspect and debug the data they get from the API service quickly. This “easy-to-read” data provides developers with a boost in understanding the API and/or the errors that occur due to bad usage or service implementation errors.
So, REST defines resources and entities and is built on top of HTTP. But what does all this have to do with Go, and why should you use Go and not any other language? Let’s see.