Matt Shelley

A RESTful Guide to APIs

February 22, 2020

Fox lying down

Photo credit: Qijin Xu @obkim via Unsplash

Jumping into back-end from front-end (or vice versa) can be intimidating. Sure, both sides are just code in the end, but the technology and practices are different. With back-end, we manage data. With front-end, we manage user experience. But, in between them lies a bridge: the API.

When we write better APIs, we improve our teamwork and our applications.

What’s an API?

On the web, an API (Application Programming Interface) is how the front-end (client) communicates with the back-end (server).

For example, the client may want to display a list of products in a catalogue. So, the client asks the server which products are available. Then, the server answers with the list of products.

On the front-end, we send a request. On the back-end, we send a response.

This exchange is performed through an API.

CRUD

With resources, we have four actions: Create, Read, Update, and Delete.

Consider a collection of products:

Action Description
Create Add a product
Read Get the details of a product
Update Change a product
Delete Remove a product

We can perform these actions on resources through an API.

RESTful APIs

RESTful APIs are one approach to communicating CRUD actions between the client and the server.

REST (Representational State Transfer) refers to architectural constraints for web services. However, web APIs may not fulfill all of those constraints, so instead are called RESTful.

With RESTful APIs, we use HTTP methods to create, read, update, and delete resources given a clean URL and a URI (Unique Resource Identifier), like an id (42) or slug (towel).

Specifically, HTTP supports GET, POST, PATCH, PUT, and DELETE methods.

With a resource:

Method Description
GET Retrieve resource
POST Create a new “sub-resource,” and return its URI
PATCH Update resource with given instructions
PUT Replace resource
DELETE Delete resource

With a collection of resources:

Method Description
GET Retrieve all resources
POST Create a new resource, and return its URI
PATCH Update all resources with given instructions
PUT Replace all resources
DELETE Delete all resources

RESTful APIs support CRUD actions on collections and resources.

JSON:API

There is no standard format for requests, responses, and errors in RESTful APIs. However, I personally like to use JSON:API for most of my projects.

Each request includes an HTTP method, URL, and sometimes instructions.

Each response returns an HTTP status code and a JSON object with either data or error - but never both. Optionally, responses may return a meta object to tell us more about the data, such as pagination.

Let’s see how to create, read, update, and delete from our products collection.

(These examples will not cover every possible situation. For thorough details, please refer to the JSON:API specification.)

GET

To request all products:

GET https://api.example.com/products

To respond, we return an array of products:

200 OK

{
  data: [{
    type: "products",
    id: "toaster",
    attributes: {
      name: "Toaster",
      price: 29.99
    }
  }, {
    type: "products",
    id: "alarm-clock",
    attributes: {
      name: "Alarm Clock",
      price: 15.99
    }
  }]
}

If there are no products, we respond with an empty array:

200 OK

{
  data: []
}

To request a specific product:

GET https://api.example.com/products/toaster

To respond, we return the product:

200 OK

{
  data: {
    type: "products",
    id: "toaster",
    attributes: {
      name: "Toaster",
      price: 29.99
    }
  }
}

If we cannot find the product, we respond with an error:

404 Not Found

{
  errors: [{
    status: "404",
    detail: "The requested product could not be found."
  }]
}

Further, we can sort, filter, and paginate by providing a query:

GET https://api.example.com/products?sort=price&filter=0,100&page=5

POST

To request the creation of a product:

POST https://api.example.com/products

{
  data: {
    type: "products",
    attributes: {
      name: "Frying Pan",
      price: 19.99
    }
  }
}

To respond, we return the new product with its id:

201 Created

{
  data: {
    type: "products",
    id: "frying-pan",
    attributes: {
      name: "Frying Pan",
      price: 19.99
    }
  }
}

If we cannot create the product, we respond with an error:

403 Forbidden

{
  errors: [{
    status: "403",
    detail: "You do not have permission to create a product."
  }]
}

PATCH

To request updates to a product, we send the updated values and leave out the ones we do not want to change:

PATCH https://api.example.com/products

{
  data: {
    type: "products",
    id: "toaster",
    attributes: {
      description: "This product has a new description"
    }
  }
}

To respond, we return the updated product:

200 OK

{
  data: {
    type: "products",
    id: "toaster",
    attributes: {
      name: "Toaster",
      price: 29.99,
      description: "This product has a new description"
    }
  }
}

If we cannot update the product, we respond with an error:

403 Forbidden

{
  errors: [{
    status: "403",
    detail: "You do not have permission to update this product."
  }]
}

PUT

PUT is not supported by JSON:API. However, we can mimic PUT by providing all attributes to PATCH.

DELETE

To delete a product:

DELETE https://api.example.com/products/toaster

To respond, we simply confirm with no content:

204 No Content

If we cannot delete the product, we respond with an error:

403 Forbidden

{
  errors: [{
    status: "403",
    detail: "You do not have permission to delete this product."
  }]
}

Error Handling

When an error occurs, we respond with the HTTP status code and an array of errors containing status, details, and other attributes.

Final Thoughts

As developers, we often place ourselves on either the front-end or back-end. It is very easy to stick to the side we prefer, where we are comfortable, but as a result we limit our breadth of skills. Learning to build RESTful APIs is a great opportunity to expand our skills to the other side.

Ultimately, writing better APIs improves our teamwork and our applications.

Further Reading


Matt Shelley
Writing about software development and self-improvement