Skip to main content
Back to module
Back-End Web APIs · HTTP and REST

REST resources and verbs

Reading19mLesson 1 of 3 in this module

Design predictable API routes by naming resources in the URL and letting HTTP methods carry the action.

Why it matters

Almost every app you will build talks to a server. A mobile app loads a user's feed, a web page saves a form, a dashboard pulls numbers. The server side of that conversation is an API (application programming interface): a set of URLs that accept requests and send back data. If the API is designed well, front-end and mobile developers can guess how it works before they read the docs. If it is designed badly, every screen needs special cases.

Most web APIs today follow a style called REST (representational state transfer). REST is not a library or a standard you install. It is a set of conventions built on top of HTTP, the same protocol your browser uses to load pages.

The core idea: resources and verbs

REST splits every request into two parts:

  • The resource: a noun, identified by a URL path. /courses, /courses/42, /courses/42/lessons.
  • The verb: the HTTP method, which says what to do with that resource.
MethodMeaningTypical pathChanges data?
GETRead/courses, /courses/42No
POSTCreate a new item in a collection/coursesYes
PUTReplace an item completely/courses/42Yes
PATCHUpdate some fields of an item/courses/42Yes
DELETERemove an item/courses/42Yes

Two properties are worth remembering:

  • Safe methods do not change data. GET is safe, so browsers, caches and crawlers may call it freely. Never let a GET delete or update anything.
  • Idempotent methods give the same result if you repeat them. GET, PUT and DELETE are idempotent: deleting item 42 twice leaves it just as deleted. POST is not: sending "create order" twice can create two orders. That is why payment APIs often ask for an idempotency key.

Worked example: designing routes for a resource

Say you are building the API for a course platform, and the first resource is a course. Start with the nouns, then attach verbs:

GET    /courses              list courses (maybe ?level=beginner&page=2)
POST   /courses              create a course (data in the request body)
GET    /courses/:id          read one course
PATCH  /courses/:id          change some fields of one course
DELETE /courses/:id          delete one course
GET    /courses/:id/lessons  list the lessons that belong to one course

A few habits make this predictable:

  • Plural nouns for collections. /courses, not /course or /getCourses. The verb is already in the method, so do not repeat it in the path.
  • IDs in the path, filters in the query string. /courses/42 names one thing. /courses?level=beginner narrows a list. Sorting and paging (?sort=title&page=2) also go in the query string.
  • Nest only one level for ownership. /courses/42/lessons is clear. /schools/1/courses/42/lessons/7/comments is painful; once a lesson has its own ID, /lessons/7/comments works.
  • Lowercase, hyphenated paths. /learning-paths, not /LearningPaths.

A full request and response look like this when you run curl -i against a local server:

GET /courses/42 HTTP/1.1
Host: localhost:3000
Accept: application/json

HTTP/1.1 200 OK
Content-Type: application/json

{ "id": 42, "title": "Back-End Web APIs", "level": "intermediate" }

The request line holds the method and path. Headers carry metadata such as Accept (what format the client wants) and Content-Type (what format the body is in). The body holds the data. The response starts with a status code (200 OK here), which the next lesson covers in detail.

Actions that are not CRUD

Some operations do not fit create, read, update and delete neatly: "publish a course", "reset a password", "send a test email". Two common answers:

  1. Model it as a field change: PATCH /courses/42 with { "status": "published" }.
  2. Model it as creating a new resource: POST /password-resets with { "email": "..." }. The "reset request" becomes a thing you create.

Both are fine. What you should avoid is a path full of verbs such as POST /publishCourse?id=42, because each one becomes a special case for every client.

Common mistakes

  • Using GET for changes. A link like /courses/42/delete can be triggered by a browser prefetch, a crawler or an image tag on another site.
  • Verbs in paths. /createUser, /getAllUsers. Let the method carry the verb.
  • Inconsistent shapes. If GET /courses returns { "items": [...] }, do not make GET /lessons return a bare array. Pick one shape and keep it.
  • Leaking database details. The URL is a public contract. Exposing table names or internal columns makes it hard to change your database later.
  • Changing a route that clients already use. Once a mobile app ships, old versions keep calling the old URL for months. Add new fields and routes; remove old ones slowly, or version the API (/v2/...).

Quick recap

  • REST is a convention: resources are nouns in the URL, methods are verbs.
  • GET reads and must never change data. POST creates, PUT replaces, PATCH updates part, DELETE removes.
  • Use plural collections, IDs in the path, filters and paging in the query string, and shallow nesting.
  • Your routes are a contract with every client. Keep them consistent and change them carefully.

Head to the Do tab and test yourself on route design before moving on to status codes.

Also in this lesson: