How to Embed Related Resources in JSON Server Responses Using `_embed`

Use the _embed query parameter to automatically include related records in JSON Server responses by appending ?_embed=relatedCollection to any GET request.

The typicode/json-server library generates a zero-configuration REST API that resolves relationships through strict naming conventions. By leveraging the _embed parameter, developers can enrich API responses with nested related data without writing custom middleware or database joins.

How _embed Works

JSON Server implements embedding through a two-stage pipeline. First, the query parser extracts the parameter values from the request URL. Then, the service layer resolves the relationships and attaches the data.

In src/app.ts, the parseListParams function (line 64) extracts the _embed values and forwards them to the data service. The Service class in src/service.ts receives these values through the embed option in both find (lines 28‑32) and findById (lines 96‑104) methods. The core enrichment logic resides in the embed helper (lines 23‑47), which determines relationship cardinality and attaches the related objects to the response payload.

Relationship Conventions and Foreign Key Patterns

JSON Server relies on convention over configuration to resolve relationships automatically. The system expects strict naming conventions:

  • Plural collection names: Resources must use plural forms (e.g., posts, comments, users).
  • Foreign key pattern: Child records must store the parent identifier using the pattern <parentSingular>Id. For example, a comment belonging to a post stores postId.
  • Inflection logic: The embedded inflection library handles singularization to determine if a relation is one-to-many (plural name like comments) or many-to-one (singular name like post).

When processing _embed=comments, the code calls inflection.singularize('comments') which returns 'comment'. Since this differs from the input, JSON Server treats it as a one-to-many relationship. Conversely, _embed=post singularizes to 'post', matching the input and signaling a many-to-one lookup.

Embedding Examples

Embed One-to-Many Relationships

To fetch all posts with their associated comments, request the parent resource with the child collection name:

GET /posts?_embed=comments HTTP/1.1
Host: localhost:3000

Response:

[
  {
    "id": 1,
    "title": "Post 1",
    "author": "John",
    "comments": [
      { "id": 101, "postId": 1, "body": "Great post!" },
      { "id": 102, "postId": 1, "body": "Thanks for sharing." }
    ]
  }
]

According to the source code in src/service.ts (lines 35‑46), the service filters the comments collection for records where postId matches the parent id, then attaches the resulting array under the comments key.

Embed Many-to-One Relationships

To fetch a specific comment and include its parent post:

GET /comments/101?_embed=post HTTP/1.1
Host: localhost:3000

Response:

{
  "id": 101,
  "postId": 1,
  "body": "Great post!",
  "post": { "id": 1, "title": "Post 1", "author": "John" }
}

As implemented in src/service.ts (lines 25‑34), the embed function detects the singular relation name, locates the foreign key postId on the child record, queries the posts collection, and attaches the single matching object.

Embed Multiple Relations

Request multiple embedded resources by repeating the parameter or using comma-separated values:

GET /posts?_embed=comments&_embed=author HTTP/1.1
Host: localhost:3000

JSON Server processes each relation independently, adding both comments and author fields to every post object.

Combine with Filtering and Pagination

The embedding phase executes after filtering, sorting, and pagination. This ensures you only embed relations for the final result set:

GET /posts?_embed=comments&_sort=title&_page=2&_per_page=5 HTTP/1.1
Host: localhost:3000

The service first applies the sort order and pagination in src/service.ts (lines 28‑32), then iterates the reduced result set to embed comments.

Internal Implementation Details

The embedding algorithm distinguishes relationship types using the inflection library. In src/service.ts (line 24), the check inflection.singularize(related) === related determines the code path:

  • Many-to-one (singular): Uses the foreign key <related>Id (e.g., postId) to locate a single parent record.
  • One-to-many (plural): Uses the foreign key <singularParent>Id (e.g., postId) to filter child records where the foreign key matches the parent id.

This logic executes within the embed function (lines 23‑47), which is invoked synchronously during the find and findById operations before the response middleware serializes the result in src/app.ts (lines 55‑63).

Summary

  • Append ?_embed=relationName to any GET request to nest related resources automatically.
  • Follow the foreign key convention <parentSingular>Id (e.g., postId, userId) for automatic resolution.
  • Use plural names for one-to-many relations (e.g., _embed=comments) and singular names for many-to-one (e.g., _embed=post).
  • Embedding occurs after filtering, sorting, and pagination, ensuring optimal performance for large datasets.
  • The implementation resides in src/service.ts (lines 23‑47) with query parsing handled in src/app.ts (line 64).

Frequently Asked Questions

What naming convention does JSON Server use for foreign keys?

JSON Server expects foreign keys to follow the pattern <parentSingular>Id. For example, a child comment must store its parent post identifier as postId. The system uses the inflection library to singularize collection names and resolve these relationships automatically in src/service.ts.

Yes. Supply multiple _embed parameters as either repeated query strings (?_embed=comments&_embed=author) or comma-separated values (?_embed=comments,author). The parser in src/app.ts (line 64) collects all values into an array, and src/service.ts processes each relation independently.

Does embedding work with pagination and sorting?

Yes. The Service.find method in src/service.ts (lines 28‑32) applies filtering, sorting, and pagination before invoking the embed helper. This ensures you only fetch and attach related data for the records actually returned in the current page.

How does JSON Server determine one-to-many versus many-to-one relationships?

The code uses inflection.singularize(related) === related (line 24 in src/service.ts). If singularizing the requested relation name returns the same string (e.g., post → post), it treats the request as many-to-one and expects a single parent object. If singularization changes the string (e.g., comments → comment), it treats it as one-to-many and returns an array of child records.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →