Creating REST Endpoints

Building a reliable and scalable application often requires exposing functionality through APIs. Among all architectural styles, REST (Representational State Transfer) remains one of the most popular and widely adopted approaches for designing web services. REST endpoints power mobile applications, web apps, internal systems, and large-scale distributed architectures.

This post explores the essential elements involved in creating REST endpoints, including endpoint design, controllers/handlers, route mapping, and handling request parameters. We will examine best practices, typical pitfalls, and practical examples, offering a comprehensive understanding suitable for both beginners and experienced developers.

Table of Contents

  1. Introduction to REST Endpoints
  2. Understanding Resource-Based Design
  3. Designing API Endpoints
  4. HTTP Methods and Their Role
  5. Status Codes and Error Handling
  6. Controllers and Handlers
  7. Route Mapping Fundamentals
  8. Handling Path, Query, and Body Parameters
  9. Validation and Serialization
  10. Versioning REST APIs
  11. Securing REST Endpoints

1. Introduction to REST Endpoints

A REST endpoint is a URL that represents a resource and allows clients to perform operations using HTTP methods such as GET, POST, PUT, DELETE, etc. The philosophy of REST is simplicity: resources are treated like nouns, and actions are inferred from HTTP verbs.

REST endpoints are used everywhere—from social media feeds and payment systems to IoT devices and enterprise backends. Their popularity stems from:

  • Stateless interaction
  • Clear separation between client and server
  • Language-agnostic architecture
  • Scalability and ease of caching

To build effective REST endpoints, you must design them thoughtfully, structure your controller logic properly, map routes cleanly, and understand how to work with different kinds of request parameters.

2. Understanding Resource-Based Design

REST revolves around resources. A resource is anything your application exposes to clients:

  • Users
  • Products
  • Orders
  • Files
  • Categories
  • Blog posts

Each resource has a unique identifier, usually represented as a URL path.

Example:

/users
/users/42
/products/10/reviews

Good resource-based design is:

  • Consistent
  • Predictable
  • Meaningful
  • Hierarchical when needed

You avoid exposing actions as endpoints. For example, instead of:

/getAllUsers

Use:

/users

REST encourages noun-based endpoints rather than verbs. The actions are reflected through the HTTP methods, not the endpoint itself.

3. Designing API Endpoints

Designing endpoints requires careful thinking to make APIs intuitive, scalable, and maintainable. Below are essential guidelines.


3.1 Keep URLs Simple and Descriptive

Use plural nouns for collections:

/books
/books/5

Avoid technical or implementation details in the URL:

/getBooksList
✔️ /books

/fetch_user_info
✔️ /users/{id}


3.2 Use Hierarchical Structure Where Appropriate

Resources often have relationships.

Example:

/users/{id}/orders
/orders/{orderId}/items

Hierarchy helps clients understand the connection between data.


3.3 Avoid Excessive Nesting

Too much nesting reduces readability:

/users/5/orders/12/items/2/details/history
/orders/12/items/2/history

A good rule is to avoid going deeper than two levels.


3.4 Be Consistent With Naming Conventions

Consistency makes APIs easy to learn:

  • Use lowercase
  • Use hyphens to separate words (preferred)
  • Avoid underscores

Good:

/user-profiles
/product-images

3.5 Support Filtering, Sorting, and Pagination via Query Parameters

Examples:

/products?category=electronics
/orders?sort=date&order=desc
/users?page=3&limit=20

Query parameters should configure how to receive data—not what resource is being accessed.


3.6 Keep Endpoints Stable

Once clients depend on your API, changes can break integrations. Use versioning (covered later) to evolve APIs safely.


4. HTTP Methods and Their Role

REST relies on specific HTTP verbs to represent actions.


4.1 GET – Retrieve Resource Data

Used for fetching data:

GET /users
GET /users/5

Should never change server state.


4.2 POST – Create New Resources

Example:

POST /users

The body typically contains JSON data representing the new resource.


4.3 PUT – Replace an Entire Resource

Example:

PUT /users/5

PUT should replace the full object. If partial update is needed, use PATCH.


4.4 PATCH – Partially Update a Resource

PATCH /users/5

PATCH modifies only specific fields.


4.5 DELETE – Remove a Resource

DELETE /users/5

Should be idempotent; deleting the same resource twice should not cause errors.


5. Status Codes and Error Handling

Good APIs communicate clearly using proper HTTP status codes.


5.1 Common Successful Status Codes

CodeMeaning
200OK (successful GET)
201Created (POST success)
204No content (DELETE)

5.2 Client Errors (4xx)

CodeMeaning
400Bad request
401Unauthorized
403Forbidden
404Resource not found
409Conflict (duplicate resource)

5.3 Server Errors (5xx)

CodeMeaning
500Internal error
503Service unavailable

5.4 Error Messages Should Be Useful

Example:

{
  "error": "Validation failed",
  "details": {
"email": "Invalid email format"
} }

6. Controllers and Handlers

REST frameworks typically separate logic into controllers (or routers) and service layers. Controllers handle incoming requests and forward tasks to other modules.


6.1 What Is a Controller?

A controller is responsible for:

  • Mapping endpoints to handler functions
  • Validating request data
  • Communicating with the service layer
  • Returning responses to clients

It should not contain business logic.


6.2 Example Controller Responsibilities

  1. Receive a request
  2. Extract path/query/body parameters
  3. Validate input
  4. Call the service layer
  5. Format a response
  6. Return appropriate status code

6.3 Keep Controllers Clean

Bad example:

// Too much logic inside controller

Good example:

const userService = require('../services/userService');

exports.getUser = async (req, res) => {
  const id = req.params.id;
  const user = await userService.findUser(id);
  res.json(user);
};

7. Route Mapping Fundamentals

Route mapping connects a URL + method combination to a controller handler.


7.1 Understanding Route Definitions

Example conceptual mapping:

GET /users           → getAllUsers()
GET /users/:id       → getUserById()
POST /users          → createUser()
PUT /users/:id       → updateUser()
DELETE /users/:id    → deleteUser()

7.2 Route Organization

Group routes by resource:

/users/...
/orders/...
/products/...

Avoid putting unrelated routes in the same controller.


7.3 Route Parameters

Paths can include dynamic values:

/users/:id

These are extracted inside handlers.


8. Handling Path, Query, and Body Parameters

Different types of requests carry data in different ways.


8.1 Path Parameters

Used to uniquely identify a resource.

Example endpoint:

GET /users/10

Value 10 is a path parameter.

Extracting (example pseudocode):

const userId = req.params.id;

Use path parameters for:

  • IDs
  • Nested resources
  • Resource hierarchies

8.2 Query Parameters

Used for:

  • Filtering
  • Pagination
  • Sorting
  • Optional values

Example:

GET /products?category=shoes&page=2&sort=price

Extracting:

const { category, page, sort } = req.query;

8.3 Body Parameters

Used primarily in POST, PUT, PATCH for sending content.

Typical JSON body:

{
  "name": "John",
  "email": "[email protected]"
}

Extracted via:

const { name, email } = req.body;

Body parameters can contain nested objects, arrays, and complex structures.


8.4 Validation for Each Parameter Type

  • Path parameters → Validate type and format
  • Query parameters → Validate presence and allowed values
  • Body parameters → Validate required fields, length, format

Example validation rule set:

  • email must be valid
  • name is required
  • age must be a positive number

8.5 Handling Optional Parameters

Query parameters are often optional, so APIs should provide default values:

Example:

GET /users?page=1&limit=20

If client omits them:

const page = req.query.page || 1;
const limit = req.query.limit || 20;

9. Validation and Serialization

Validation ensures data integrity; serialization ensures consistent output formatting.


9.1 Why Validation Matters

Poor validation leads to:

  • Crashes
  • Security vulnerabilities
  • Corrupted data
  • Unexpected behavior

Good validation protects both client and server.


9.2 Input Validation Methods

Common approaches:

  • Schema-based validation (e.g., JSON Schema)
  • Framework-provided validators
  • Middleware validation

Validation should occur before business logic executes.


9.3 Serialization and Response Formatting

Your endpoint should consistently format responses.

Good example:

{
  "id": 4,
  "name": "Laptop",
  "price": 999.99
}

Avoid leaking:

  • Internal IDs
  • Debug logs
  • Unnecessary metadata

Serialization ensures that returned objects follow a standard structure.


10. Versioning REST APIs

Versioning ensures backward compatibility when the API evolves.


10.1 Why Version APIs?

You may need to modify:

  • Endpoint structures
  • Field names
  • Functionality
  • Behavior

Without breaking existing clients.


10.2 Common Versioning Strategies

1. URL-Based Versioning

/api/v1/users
/api/v2/users

Simple and widely used.


2. Header-Based Versioning

Clients send:

Accept-Version: v2

Offers clean URLs but adds complexity.


3. Query Parameter Versioning

/users?version=2

Less common.


10.3 Versioning Best Practices

  • Deprecate old versions gradually
  • Provide documentation for all versions
  • Communicate changes early

11. Securing REST Endpoints

Security is critical for modern APIs. Common security layers include:


11.1 Authentication

Determines who the user is.

Popular methods:

  • JWT (JSON Web Tokens)
  • OAuth 2.0
  • API keys
  • Session tokens

11.2 Authorization

Determines what the user can do.

Example:

  • Only admins can delete users
  • Users can edit only their own profiles

11.3 Input Sanitization

Protects against:

  • SQL injection
  • XSS
  • Command injection

Always validate user input.


11.4 Rate Limiting

Prevents abuse:

100 requests per minute per user

11.5 HTTPS Everywhere

Endpoints must encrypt data-in-transit.

http:// → ❌
https:// → ✔️


11.6 CORS Settings

For web clients making cross-origin calls, configure allowed:

  • Origins
  • Methods
  • Headers

Too strict → breaks clients
Too permissive → security risk


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *