REST Architecture

What is REST?

Representational State Transfer

(Roy Fielding, 2000)

Architecture style

that defines a set of constraints and properties based on HTTP

Allow easy communication between computer systems on the Internet

REST provides a definition of a "resource"

For example, a web page (HTML) is a representation of a "resource" (URLs)

Often used in the development of web services

The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (e.g. "today's weather in Los Angeles"), a collection of other resources, a non-virtual object (e.g. a person), and so on.

- Roy Fielding's dissertation.

http://localhost:1234/users # the resource is a collection

http://localhost:1234/users/1 # the resource is a singleton

Example of REST resources

Also called REST endpoints (API)

Separation of Client / Server

In REST architecture, the implementation of the client and the implementation of the server can be done independently

Different clients / type of clients can hit the same server by using the REST endpoints, perform the same actions and receive the same responses

SEPARATION OF CONCERN 🙌

We separate the user interface concerns from the data storage concerns 

Only thing to agree on: message format

Statelessness

In REST, the server does not store any state about the client session on the server side

Each client request must contain all necessary information so that the server understands it

(The server should not need the previous request to understand the current request...)

Scaling: from 10 to Millions of users (multiple servers, no session related dependency)

Less complex: no server side state synchronization logic

Advantages

Easy cache: only for GET HTTP requests (idempotent) 😅 https://twitter.com/rombulow/status/990684453734203392

Resources and representations

A resource can be a singleton or a collection

# collection
https://api-example/movies

# singleton
https://api-example/movies/{id}

# sub-collection
https://api-example/movies/{id}/actors

# controller (executable functions)
https://api-example/movies/{id}/tickets/{id}/checkout

Resource naming guide 🙌

👉 Use nouns for collections, singletons and verbs for controllers

👉 Use forward slash (/) for hierarchical relationships

👉 Use hyphens (-) to improve readability

JSON representation

{
  "id": "1",
  "title": "Black Panther",
  "release": "2019-01-29T00:00:00Z",
  "actors": [
    "Chadwick Boseman",
    "Michael B. Jordan",
    "Lupita Nyong'o"
  ]
}

XML representation

<?xml version="1.0" encoding="UTF-8" ?>
<id>1</id>
<title>Black Panther</title>
<release>2019-01-29T00:00:00Z</release>
<actors>Chadwick Boseman</actors>
<actors>Michael B. Jordan</actors>
<actors>Lupita Nyong'o</actors>

HTTP Verbs

https://api-example/movies

GET

Retrieve the entire collection of movies

Retrieve a single movie (id = 1)

https://api-example/movies/1
https://api-example/movies

POST

Create a new movie entry 

Not generally used for singleton resource

PUT

https://api-example/movies

Replace the entire collection with a new collection

Replace the addressed movie of the collection

https://api-example/movies/1

DELETE

https://api-example/movies

Delete the entire collection of movies

Delete the addressed movie of the collection

https://api-example/movies/1

Build a REST API with node & Express

$ yarn add express

Installing Express

$ npm install express --save

// file app.js

const express = require('express');
const app = express();

app.get('/', (req, res) => res.send('Hello, World!'));

app.listen(3000, () => {
  console.log('Listening on port 3000!');
});

Hello, World!

$ node ./app.js # then, load localhost:3000/ in a browser

Routing

How an application responds to a client request to a particular endpoint

Endpoint: a URI / path with a specific HTTP request method (GET, POST, PUT, DELETE)

app.method(path, handler);

Routing / GET

app.get('/movies', (req, res) => {
  // fetch movies from DB, from JSON, ...
  // send collection to `res` (response)
  res.status(200).json(movies);
});

Routing / POST

app.post('/movies', (req, res) => {
  const newMovie = req.body;
  
  // add new movie from `req` (request) to collection
  // send new movie to `res` (response)
  res.status(201).json(newMovie);
});
// To parse json body (for POST / PUT)
const bodyParser = require('body-parser');
app.use(bodyParser.json());

Routing / PUT

app.put('/movies/:id', (req, res) => {
  const movieId = req.params.id;
  const movie = req.body;
  
  // update movie from id in collection
  // send updated movie to `res` (or nothing)
  res.status(200).json(movie);
  // or res.status(204);
});

Routing / DELETE

app.delete('/movies/:id', (req, res) => {
  const movieId = req.params.id;
  
  // delete movie from id in collection
  // send response
  res.status(200).json(deletedMovie);
  // or res.status(204);
});

Middleware

A middleware is a function that has access to req, res objects and a next function. It can be called before each requests or before specific requests. It can perform any operations and call the next middleware function or stop the request-response cycle.

Middleware

const middleware = (req, res, next) => {
  console.log('Time:', Date.now());
  // calling next() to continue request-response cycle
  next();
};

const app = express();
app.use(middleware);

The middleware function will be executed for all request endpoints

Middleware

const middleware = (req, res, next) => { ... };

const app = express();
app.get('/movies', middleware, (req, res) => {
  // fetch all movies
  res.json(movies);
});

The middleware function will be executed only for the "/movies" request endpoint

REST Architecture

By Nicolas Payot

REST Architecture

  • 881