npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

also-json-server

v0.1.22

Published

A fork of json-server

Readme

also-json-server

This is a fork of json-server. Thanks to the author of the great project!

This fork can handle many-to-many relationship in data.

Install

npm install -g also-json-server

Try the server

Before you create your data file, you can let the server to generate a data file for you to try the server. The generated file name will be also-json-server-test-db.json5. The generated data will be like the example below.

also-json-server --try-server

The server will start and you can try any request you want.

Each time you use this option to start the server, you will get a brand new data file to try.

Usage

Create your data file <data_file_name>.json or <data_file_name>.json5 file like below. (or you can use --try-server option to generate the data to try the server first.)

{
  "users": [
    {
      "id": 1,
      "name": "Jhon Doe",
      "email": "[email protected]",
      "password": "JohnPass"
    },
    {
      "id": 2,
      "name": "Jane Doe",
      "email": "[email protected]",
      "password": "JanePass"
    },
  ],
  "posts": [
    { "id": 1, "title": "a title", "views": 100 },
    { "id": 2, "title": "another title", "views": 200 }
  ],
  "comments": [
    { "id": 1, "text": "a comment about post 1", "postId": 1 },
    { "id": 2, "text": "another comment about post 1", "postId": 1 }
  ],
  "contacts": [
    {
      "id": 1,
      "name": "Tracy",
      "mobile": "(555)1234-1256",
      "groups": [1, 2]
    },
    {
      "id": 2,
      "name": "Tina",
      "mobile": "(555)2367-1287",
      "groups": [1, 3]
    },
    {
      "id": 3,
      "name": "Bill",
      "mobile": "(555)2589-1134",
      "groups": [1, 2, 3]
    },
    { "id": 4, "name": "Michael", "mobile": "(555)3345-2345", "groups": [] },
    { "id": 5, "name": "Jackie", "mobile": "(555)1123-1123", "groups": [] }
  ],
  "groups": [
    { "id": 1, "name": "Collegue" },
    { "id": 2, "name": "Friend" },
    { "id": 3, "name": "Family" },
    { "id": 4, "name": "Business" }
  ],
  "profile": {
    "name": "typicode"
  }
}
{
  users: [
    {
      id: 1,
      name: "Jhon Doe",
      email: "[email protected]",
      password: "JohnPass"
    },
    {
      id: 2,
      name: "Jane Doe",
      email: "[email protected]",
      password: "JanePass"
    },
  ],
  posts: [
    { id: 1, title: "a title", views: 100 },
    { id: 2, title: "another title", views: 200 },
  ],
  comments: [
    { id: 1, text: "a comment about post 1", postId: 1 },
    { id: 2, text: "another comment about post 1", postId: 1 },
  ],
  contacts: [
    { id: 1, name: "Tracy", mobile: "(555)1234-1256", groups: [1, 2] },
    { id: 2, name: "Tina", mobile: "(555)2367-1287", groups: [1, 3] },
    {
      id: 3,
      name: "Bill",
      mobile: "(555)2589-1134",
      groups: [1, 2, 3],
    },
    { id: 4, name: "Michael", mobile: "(555)3345-2345", groups: [] },
    { id: 5, name: "Jackie", mobile: "(555)1123-1123", groups: [] },
  ],
  groups: [
    { id: 1, name: "Collegue" },
    { id: 2, name: "Friend" },
    { id: 3, name: "Family" },
    { id: 4, name: "Business" },
  ]
  profile: {
    name: "typicode",
  },
}

You can read more about JSON5 format here.

Pass it to JSON Server CLI

$ also-json-server <data_file_name>.json

Get a REST API

$ curl http://localhost:3000/posts/1
{
  "id": 1,
  "title": "a title",
  "views": 100
}

Run also-json-server --help for a list of options

Usage: also-json-server [options] <file>

Options:
  -p, --port <port>      Port (default: 3000)
  -h, --host <host>      Host (default: localhost)
  -s, --static <dir>     Static files directory (multiple allowed)
  -a, --auth             Use authorization to access
  -P, --path <path>      Add partial path to customize url, like /api/v1
  -o, --return-object    Return result as an object with status code, message and data
  -t  --try-server       Generate a data file to try the server
  -d  --delay <auto|ms>  Delay the response for some milliseconds to mimic network latency,
                         "auto" means the time will be in 300~1000 ms randomly for each request.     
  --help                 Show this message
  --version              Show version number

Relationship

You can utilize a specified JSON data structure to establish relationships such as one-to-many and many-to-many.

For a one-to-many relationship, you incorporate a foreign key into the records on the 'many' side, as demonstrated by the sample data provided with posts (representing the one side) and comments (representing the many side). The foreign key should be in lowercase singular form and appended with "Id", representing the referenced collection's name. For instance, you can use "postId" to reference the posts collection.

Regarding many-to-many relationships, you can employ an array property on one side (often associated with the side containing more records) to store the relationships with the other side. For instance, you could use the "groups" array property within the records on the "contacts" side to maintain these relationships.

When adding or modifying records, the specified reference IDs (whether specified using foreign keys or arrays) are automatically checked. If they do not exist, an error message will be returned to notify you of the reason. When deleting records, the 'many' side of a one-to-many relationship can either choose to cascade delete or set the foreign key to null. In the case of many-to-many relationships, they will be automatically removed. Of course, you can also change many-to-many relationships by modifying elements within the array property containing the other 'many' side.

Authorization

Use --auth option to use authorization. You can bear a token with the header field "Authorization", like Authorization: Bearer <token>, or you can just add a query parameter "_token" like _token=<token> to send the token. The token can be returned after login successfully.

When use --auth, the json data file should has a collection named "users", a user should has the properties of "id", "username", "password(plain text)".

Use POST "/auth/login" to login to get a user's token.

Routes

Based on the example <data_file_name>.json, you'll get the following routes:

GET    /posts
GET    /posts/:id
POST   /posts
PUT    /posts/:id
PATCH  /posts/:id
DELETE /posts/:id

# Same for other collections
GET   /profile
PUT   /profile
PATCH /profile

You can use --path <path> to add partial path to customize you url.

also-json-server --path /api/v1

will generate the routes like:

GET    api/v1/posts
GET    api/v1/posts/:id
POST   api/v1/posts
PUT    api/v1/posts/:id
PATCH  api/v1/posts/:id
DELETE api/v1/posts/:id

# Same for other collections

Delay Responses

You can use --delay <auto|ms> to delay a response for each request to mimic network letancy.

auto will delay each response from 300ms to 1000ms randomly.

Response format

By default, requests will return just data.

[
  {"id": 1, "name": "Lexi"},
  ...
]

You can use --return-object to tell the server to return an object with statusCode, message and the data properties.

{
  "statusCode": 200,
  "message": "Success",
  "data": [
    {"id": 1, "name": "Lexi"},
    ...
  ]
}

Params

Conditions

  • ==
  • lt<
  • lte<=
  • gt>
  • gte>=
  • ne!=
  • likelike
GET /posts?views_gt=9000

# contains
GET /contacts?name_like=bill
# startsWith
GET /contacts?name_like=bill*
# endsWith
GET /contacts?name_like=*bill

Range

  • start
  • end
  • limit
GET /posts?_start=10&_end=20
GET /posts?_start=10&_limit=10

Paginate

  • page
  • per_page (default = 10)
GET /posts?_page=5&_per_page=25
{
  "statusCode": 200,
  "message": "Success",
  "first": 1,
  "first_url": "/posts?_page=1&_per_page=25",
  "prev": 4,
  "prev_url": "/posts?_page=4&_per_page=25",
  "current": 5,
  "next": 6,
  "next_url": "/posts?_page=6&_per_page=25",
  "last": 2,
  "last_url": "/posts?_page=2&_per_page=2",
  "pages": 9,
  "items": 205,
  "data": [
    ...
  ]
}

Sort

  • _sort=f1,f2
GET /posts?_sort=id,-views

Nested and array fields

  • x.y.z...
  • x.y.z[i]...
GET /foo?a.b=bar
GET /foo?x.y_lt=100
GET /foo?arr[0]=bar

Embed Related Records

# one to many: embed "many" side
GET /posts?_embed=comments
GET /posts/1?_embed=comments


# one to many: embed "one" side
GET /comments?_embed=post


# many to many
GET /contacts?_embed=groups
GET /contacts/1?_embed=groups
GET /groups?_embed=contacts
GET /groups/1?_embed=contacts

Delete

## 'many' side related foreign keys will be set to null
DELETE /posts/1

## cascading delete 'many' side of one-to-many
DELETE /posts/1?_dependent=comments

## delete a record of many-to-many on any side
## will remove the relationship automatically

## groups that contact 1 is in will remain, but the relationship 
## to contact 1 will be removed automatically
DELETE /contacts/1

## contacts that is in the group 2 will remain, but the relationship 
## to the group 2 will be removed automatically
DELETE /group/2

Serving static files

If you create a ./public directory, JSON Serve will serve its content in addition to the REST API.

You can also add custom directories using -s/--static option.

also-json-server -s ./static
also-json-server -s ./static -s ./node_modules

Notable differences

  • id is always an integer and will be generated for you if missing
  • use _per_page with _page instead of _limitfor pagination