RESTful Routes Convention

Welcome to our comprehensive guide on RESTful Routes! REST (REpresentational State Transfer) may sound fancy, but at its core, it’s about a straightforward approach to structuring web application endpoints that everyone can understand.


What We'll Cover


Routes vs. Endpoints

Route: The URL path for a request, for example /tweets.
Endpoint: A combination of the HTTP method (verb) + route that defines how the server should process the request and what the response should look like. For instance, GET /tweets vs. POST /tweets are two separate endpoints, each describing a different “action” on the /tweets path.

Think of a route like an address in a city (e.g., Main St.), and the endpoint as not just the address but also the instruction you give the delivery driver (“Pick up a package” or “Drop off a package”). Both the address (route) and the instruction (HTTP verb) determine the final action.

REST prescribes a uniform and predictable way to define endpoints, making it easier for fellow developers to integrate with or understand your web service.


Route Parameters

Sometimes a URL needs to capture dynamic values—like user IDs or tweet IDs. A route parameter is a placeholder in the path. For example:

/tweets/:tweetId

This “:tweetId” can represent any valid ID, such as /tweets/17 or /tweets/123abc. Route parameters allow you to have flexible paths while maintaining a single endpoint definition in your code or documentation.


Rules of REST

REST (REpresentational State Transfer) defines an architecture style, not an official standard. However, there are generally accepted constraints or “rules”:

  1. Decoupled Client-Server: The server and client should be independent. The server focuses on delivering data (or performing actions), and the client focuses on the user experience or display logic.
  2. Stateless: Each request stands alone without requiring the server to remember prior requests. (Though you can use cookies or tokens, the fundamental idea is that no stored “session state” is strictly required to process the request.)
  3. Uniform Interface: Keep endpoints self-describing and consistent. Typically, each operation (create, read, update, delete) uses a separate URL pattern and HTTP verb. This uniformity makes APIs easy to learn and navigate.

In practice, you can think of CRUD operations (Create, Read, Update, Delete) mapped to the standard HTTP verbs (POST, GET, PUT/PATCH, DELETE).


What Does a RESTful Route Look Like?

RESTful routes often align with the data entities in your application. If you’re building a Twitter clone, you’ll have “tweets,” “users,” “comments,” etc. The route structure typically follows two patterns:

1. Collection URLs vs. Singular URLs

A collection URL (e.g., /tweets) represents all tweets. A singular URL (e.g., /tweets/17) represents one specific tweet with the ID “17”.

/invoices            -- All invoices
/invoices/PK-200201    -- A single invoice with id PK-200201

/people                -- All people
/people/10103          -- Person with id 10103

/houses                -- All houses
/houses/bdfa5ef9-0c86-... -- A specific house by GUID

For our Twitter example, /my/tweets gets the entire collection of your tweets, while /my/tweets/17 points to one tweet.

2. Using “Special” IDs for Special Behavior

Sometimes, the ID section of a route might be replaced with words like current or latest to denote a specific “record” that changes over time (like /weather/current or /weather/latest). This is a design choice that’s still RESTful—just with a custom identifier instead of a numeric or GUID-based ID.


Creating RESTful Endpoints with HTML Forms

Traditional HTML forms can only send GET and POST requests, so a common practice is to “simulate” PUT and DELETE through special routes or hidden form fields. Still, we can keep endpoints “RESTful” in concept.

Path Pattern HTTP Verb Meaning
/resource-name GET Index page: Get an HTML list of the resource
/resource-name/new GET Create form page: Show a form to create a new record
/resource-name POST Submit create form: Create a new record for the resource
/resource-name/:record-id GET Detail page: Show details of a single record
/resource-name/:record-id/edit GET Edit form page: Show form to edit the specified record
/resource-name/:record-id POST Submit edit form: Update the specified record
/resource-name/:record-id/delete POST Submit delete form: Delete the specified record

For a Twitter clone’s “tweet” resource, you might have:

Path HTTP Verb Meaning
/my/tweets GET Index page: List all your tweets
/my/tweets/new GET Create form page: Show a form to create a new tweet
/my/tweets POST Submit create form: Create a new tweet
/my/tweets/17 GET Detail page: Show the details of tweet #17
/my/tweets/17/edit GET Edit form page: Show a form to edit tweet #17
/my/tweets/17 POST Submit edit form: Update tweet #17
/my/tweets/17/delete POST Submit delete form: Delete tweet #17

Notice how each “GET” route corresponds to a page that shows or lists content, and each “POST” route either creates, updates, or deletes something. After these actions, you typically redirect to another page, like the tweet’s detail page or your tweets list.


Nesting Resources

Sometimes a resource “lives under” another resource. For example, “comments” might depend on a specific “tweet.” This leads to nested routes:

POST /tweets/:tweetId/comments   -- Create a comment for a specific tweet
GET  /tweets/:tweetId/comments   -- List all comments for a specific tweet

Here, tweetId is a path parameter telling the server which tweet you’re referring to. This makes it clear that these comments belong to that particular tweet, and not any others.

Path Pattern HTTP Verb Meaning
/resource-name/:record-id/nested-resource GET Index page of nested resource for a specific record
/resource-name/:record-id/nested-resource/new GET Form page: create a new nested resource record
/resource-name/:record-id/nested-resource POST Submit create form: create a new nested resource record
/nested-resource/:nested-record-id GET Detail page: Show the details of the nested resource record
/nested-resource/:nested-record-id/edit GET Form page: edit an existing nested resource record
/nested-resource/:nested-record-id POST Submit edit form: update the nested resource record
/nested-resource/:nested-record-id/delete POST Submit delete form: remove the nested resource record

RESTful vs. Other Conventions

REST isn’t the only game in town! There are many ways to structure web application endpoints. Some APIs might use /api/v1/doSomething, while others might use GraphQL or custom RPC-style endpoints. However, RESTful routes remain popular because they are easy to read and consistent across a wide variety of applications.


Real-World Examples and Code Snippets

Express.js Example

Suppose you want to build a simple Express.js application that follows RESTful routing for a “tweets” resource. Here’s a minimal example:

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

// Middleware to parse incoming request body
app.use(express.json());

// 1) Index page: get a list of tweets
app.get('/tweets', (req, res) => {
  // Imagine you fetch tweets from a database
  res.json({ message: 'Here are all the tweets!' });
});

// 2) Create form page (in a real app, you'd serve an HTML form here)
app.get('/tweets/new', (req, res) => {
  res.send('<form>...create tweet form...</form>');
});

// 3) Submit create form: add new tweet
app.post('/tweets', (req, res) => {
  // Insert tweet into a database
  res.redirect('/tweets'); 
});

// 4) Detail page: see one tweet
app.get('/tweets/:tweetId', (req, res) => {
  const tweetId = req.params.tweetId;
  res.send(`Detail view of tweet #${tweetId}`);
});

// 5) Edit form page
app.get('/tweets/:tweetId/edit', (req, res) => {
  const tweetId = req.params.tweetId;
  res.send(`<form>Edit tweet #${tweetId}</form>`);
});

// 6) Submit edit form
app.post('/tweets/:tweetId', (req, res) => {
  const tweetId = req.params.tweetId;
  // Update tweet in database
  res.redirect('/tweets/' + tweetId);
});

// 7) Submit delete form
app.post('/tweets/:tweetId/delete', (req, res) => {
  const tweetId = req.params.tweetId;
  // Delete the tweet from the database
  res.redirect('/tweets');
});

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

Notice how each app.VERB corresponds to a different endpoint. Each route is structured in a clear, predictable manner.


What You've Learned

By understanding and applying RESTful design principles, you’ll create APIs that are easier to maintain, document, and consume. In your next projects, try experimenting with different naming conventions and see how naturally others can navigate your endpoints!