<img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=1063935717132479&amp;ev=PageView&amp;noscript=1 https://www.facebook.com/tr?id=1063935717132479&amp;ev=PageView&amp;noscript=1 "> REST, JSON:API & Sparse Fieldsets

REST, JSON:API & Sparse Fieldsets

This course covers three ways a backend exposes functionality to the outside world: REST, WebHooks, and RPC. We start with REST and the JSON:API convention.

REST stands for Representational State Transfer. It isn't a protocol; it's a style of designing web APIs that maps naturally onto HTTP. The core idea is simple: everything is a resource (a book, a user, an order), and HTTP methods define what you want to do to it.

Before REST, every API invented its own vocabulary: one called creating a user createUser, another addUser, another user.new. REST standardizes this. URLs are nouns (/books, /books/42), HTTP methods are the verbs, and a developer who knows HTTP already knows the shape of any REST API before reading a single line of docs.

The verbs

GET    /books       → list all books (safe, no side effects)
GET    /books/42    → get one book
POST   /books       → create a book (server assigns the ID, returns 201)
PUT    /books/42    → replace the whole book — omitted fields are erased
PATCH  /books/42    → update only the fields you send
DELETE /books/42    → remove it (idempotent — calling twice is safe)

Three properties REST leverages from HTTP:

  • Stateless — every request carries all the info the server needs. No session memory between calls.
  • Uniform interface — the same methods mean the same thing everywhere. GET always reads; POST always creates.
  • Resource-based — URLs identify things, methods describe actions on them.

Responses carry standard status codes: 2xx success (201 Created, 204 No Content), 4xx the client's fault (400 malformed input, 404 not found), 5xx the server's fault (500 unhandled error).

Check your understanding

You PATCH a book with { author: 'Tolkien' }. What happens to its title?

Check your understanding

Why is it fine to retry a failed DELETE but risky to retry a failed POST?

JSON:API

Plain REST tells you which verbs to use, but says nothing about what the JSON in the body should look like. Every team ends up debating the same questions: where do errors go, how do you embed related records, what's the pagination envelope? JSON:API (jsonapi.org) is a specification that answers all of them once.

A JSON:API response identifies every record by type and id, puts its fields under attributes, and links related records under relationships:

{
  "data": {
    "type": "books",
    "id": "42",
    "attributes": {
      "title": "The Hobbit",
      "isAvailable": true
    },
    "relationships": {
      "author": {
        "data": { "type": "authors", "id": "7" }
      }
    }
  }
}

Requests and responses use the media type application/vnd.api+json. The payoff isn't this one document; it's the conventions that come with it: sparse fieldsets, pagination, and compound documents.

Sparse fieldsets

A REST endpoint normally returns every field of a resource on every request. A list view that only needs each book's title still downloads due dates, timestamps, and author bios. That's over-fetching, and on large lists it adds up. Sparse fieldsets fix it with a query parameter: the client names exactly the fields it wants, per type.

GET /books?fields[books]=title,isAvailable
Default response GET /books/42 title: "The Hobbit" isAvailable: true dueDate: null createdAt: "2024-…" updatedAt: "2024-…" authorBio: "Born…" 6 fields ship — 5 unused Sparse fieldset GET /books/42?fields[books]=title type: "books" id: "42" title: "The Hobbit" only the field the view needs
A default response ships every column. A sparse fieldset request returns only the fields the view actually renders, shrinking the payload.

The same parameter works per type, so a request that includes related resources can trim both sides:

GET /books?include=author&fields[books]=title&fields[authors]=name
{
  "data": [
    {
      "type": "books",
      "id": "42",
      "attributes": { "title": "The Hobbit" },
      "relationships": {
        "author": { "data": { "type": "authors", "id": "7" } }
      }
    }
  ],
  "included": [
    { "type": "authors", "id": "7", "attributes": { "name": "J.R.R. Tolkien" } }
  ]
}

The server returns only the requested attributes. type and id always come back, since they identify the record.

Exercise

Code challenge

Build a sparse fieldset URL

A dropdown only needs each book's title, and each author's name. Build the query string that requests just those fields, using JSON:API sparse fieldsets. Fill in the two field lists.