Skip to main content

Anatomy of a REST request

It’s important to know that a request is made up of four elements, which will be discussed separately in subsequent chapters:

  • The endpoint
  • The (optional) query parameters
  • The method
  • The headers
  • The data (or body)

Request endpoint

The endpoint (or route) is the url you request for. It follows this structure:

root-endpoint/?

The root-endpoint is the starting point of the API you’re requesting from. The root-endpoint of Github’s API is https://api.github.com while the root-endpoint of Twitter’s API is https://api.twitter.com.

The path determines the resource you’re requesting for. Think of it like an automatic answering machine that asks you to press 1 for a service, press 2 for another service, 3 for yet another service and so on.

You can access paths just like you can link to parts of a website. For example, to get a list of all time entries tagged in your database, you send a request to https://api.database.com/time-entries. api.database.com/ is the root-endpoint and /time-entries is the path.

Query parameters

Query parameters are a defined set of optional parameters attached to the end of a request endpoint. They are extensions of the URL that are used to provide specific parameters that affect the response of your request. For example, using query parameters, you can refine your request so that it returns more selective data, thereby lightening the load of your request and possibly improving the speed of your application.

Query parameters are appended to the end of the request endpoint, using a ?. The question mark sign is used to separate path and query parameters. If you want to add multiple query parameters, an & sign is placed in between them to form what is known as a query string. It can feature various object types with distinct lengths such as arrays, strings, and numbers.

https://api.database.com/time-entries?sort=ASC&page=2

In the following request, there are two query parameters: sort, and page, with ASC and 2 being their values.

Further reading

Request body

The data (sometimes called “body” or “message”) contains information you want to be sent to the server. This option is usually only used with POST, PUT, PATCH or DELETE requests as the request body will contain data regarding updated/new/to-be-deleted data points. Important: request bodies are therefore not required in every request.

const requestBody = {
client: 'Heineken',
startTime: "2019-09-23T16:00:00.000Z",
stopTime: "2019-09-23T18:00:00.000Z",
id: 1
}

Above is an example of a REST POST-request body that will attempt to add a new time entry to our json-server. The request body is in JSON-format. This kind of scenario is common in user-registration flows on websites requiring user-accounts: a user fills in an online registration-form, which collects new user data, which is then combined in a request body that is then sent to the RESTful database.

Request header

Headers are used to provide information to both the client and server. It can be used for many purposes, such as authentication and providing information about the body content. You can find a list of valid headers on MDN’s HTTP Headers Reference.

HTTP Headers are property-value pairs that are separated by a colon. The example below shows a header that tells the server to expect JSON content.

const requestHeader = {
"Content-Type": "application/json",
},
adding sensitive data to a request header

It is common that REST requests are subject to security measures that involve sending a user account id, and a user password/token. These account details are sensitive data and thus it is important that such sensitive data is not commited to source code, but instead injected in the source code in build/development builds from a .env file that that is not committed.

Further reading

Request methods

The method is the type of request you send to the server. We will be using the five types below:

  • GET
  • POST
  • PUT
  • PATCH
  • DELETE

These methods provide meaning for the request you’re making. They are used to perform four possible actions: Create, Read, Update and Delete (CRUD).

GET

This request is used to get a resource from a server. If you perform a GET request, the server looks for the data you requested and sends it back to you. In other words, a GET request performs a READ operation. This is the default request method.

DELETE

This request is used to delete a resource from a server. If you perform a DELETE request, the server deletes an entry in the database and tells you whether the deletion is successful. In other words, a DELETE request performs a DELETE operation.

POST

This request is used to create a new resource on a server. If you perform a POST request, the server creates a new entry in the database and tells you whether the creation is successful. In other words, a POST request performs a CREATE operation. Usually the entry that was created will be returned to you after a successful request, so you immediately can access the id that was created by the database.

PUT / PATCH

These two requests are used to update a resource on a server. If you perform a PUT or PATCH request, the server updates an entry in the database and tells you whether the update is successful. In other words, a PUT or PATCH request performs an UPDATE operation.

Example request

Now that the separate components of a typical REST API Request have been described, let's have a look at an example of how a REST API can be used in React. A common way of integrating a REST API request in a React application is via the Fetch API.

Using the Fetch API to send a GET Request

The Fetch API is part of browsers and available as a package for JavaScript. It is supported by default within Next.js projects and is a common method for getting resources from a server or a (REST) API endpoint from within your React project.

The fetch function always takes in a compulsory argument, which is the path or URL to the resource you want to fetch. It returns a promise that points to the response from the request, whether the request is successful or not.

Once a response has been fetched, there are several inbuilt methods available to define what the body content is and how it should be handled.

Example: "Fetching" time entries from our JSON-server

export async function getTimeEntries():Promise<Types.TimeEntry[]>  {
const response = await fetch("http://localhost:3004/time-entries", {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});

return response.json();
}

Note three things: first, the function takes no arguments and uses the fetch function to send a RESTful request to our node-server to "GET" all the tasks present in our db.json. Second, the getTimeEntries function is defined as "async", and it "awaits" the results of the fetch request, and eventually returns the response in JSON-format via the .json() method. For now you may take these 'two syntactic newcomers' (await & async) for granted - we will discuss them more in depth in the 'useEffect & async code' chapter. Finally, the return type for this service is similar to how you would create interfaces for components and in this case would constitute an array containing objects conforming to the TimeEntry interface.

In the above "GET" request, we can see the aformentioned ingredients of a RESTful request:

  • Endpoint: http://localhost:3004/time-entries
  • Path: /time-entries
  • Request method: GET
  • Header:
{
"Content-Type": "application/json",
}

Further reading