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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@json-express/api-rest

v2.0.0

Published

REST API Generator plugin for JSON Express

Readme

@json-express/api-rest

REST API generator plugin for JSONExpress v2. Automatically generates a full CRUD REST API for every collection registered in the active database adapter—including a universal cross-collection search endpoint.


What It Does

This plugin implements the IApiGenerator interface. When the JSONExpress Kernel boots, it calls generate(collections) and this plugin returns a complete set of RouteDefinition objects — one for each standard CRUD operation per collection, plus a global /search endpoint.

The Transport layer (e.g., @json-express/transport-express) then binds these abstract definitions to real HTTP routes.


Generated Endpoints

For every collection (e.g., users, posts) that declares fields:

| Method | Path | Description | |---|---|---| | GET | /{collection} | Get all records. Supports flat key-value filtering via query string. | | GET | /{collection}/:id | Get a single record by ID. | | POST | /{collection} | Create a new record. Auto-generates an id if not provided. | | PATCH | /{collection}/:id | Partially update a record by ID. | | DELETE | /{collection}/:id | Delete a record by ID. |

Fieldless models (defineRoutes(...) or defineModel({ ... }) without a fields block) are skipped from CRUD codegen — they declare behavior only. Their custom endpoints (see below) are still mounted.

Plus a global endpoint across all collections:

| Method | Path | Description | |---|---|---| | POST | /search | Universal cross-collection search with a Mongo-style JSON query body. |


The /search Endpoint

Why POST?

Unlike GET, POST allows sending a rich JSON body — enabling complex nested queries, arbitrary payload sizes, and keeping sensitive query parameters out of server access logs.

Request Body

{
  "collections": ["users", "posts"],
  "query": {
    "status": "active"
  }
}

| Field | Type | Required | Description | |---|---|---|---| | collections | string[] | No | Target specific collections. Omit to search across all active collections. | | query | object | No | Key-value filter pairs. Delegated to the active IDatabaseAdapter.search(). |

Response

Returns a map of collection names to their matched records. Empty collections are omitted.

{
  "users": [
    { "id": "1", "name": "Alice", "status": "active" }
  ],
  "posts": [
    { "id": "42", "title": "Hello World", "status": "active" }
  ]
}

Future Database Support

The query object is passed directly to db.search(collection, query). Each adapter is responsible for translating it:

| Adapter | Translation | |---|---| | adapter-memory | JavaScript .filter() on flat key-value equality | | adapter-mongodb (future) | Passed natively as a Mongo query object | | adapter-postgres (future) | Translated to SQL WHERE clauses via Knex.js |


Custom Endpoints

Models can extend the generated CRUD with their own routes via the endpoints block. Two forms are supported:

Bare-function form — quickest:

endpoints: {
    'POST /:id/play': async (req, res, ctx) => { /* ... */ },
}

Object form { handler, validation } — adds per-endpoint body/query validation (read by @json-express/middleware-validation):

endpoints: {
    'GET /search': {
        validation: {
            query: z.object({ q: z.string().min(2) }),
        },
        handler: async (req, res, ctx) => { /* ... */ },
    },
}

The plugin also picks up a top-level endpoints export from routes/*.ts files for global, non-resource routes.


Model-Driven Validation

When a schema declares a validation block, this plugin attaches the validation middleware to the matching CRUD route(s) and pins the relevant op block in route.metadata.validation:

| Slot | Route | route.metadata.validation shape | | ---------------------------- | ---------------------- | --------------------------------------- | | validation.create | POST /{collection} | { create: { body } } | | validation.update | PATCH /{collection}/:id | { update: { body } } | | validation.list | GET /{collection} | { list: { query } } | | custom endpoint validation | the route key | { body?, query? } (no create wrap) |

The middleware itself reads the resolved schemas at boot via setSchemas and compiles its own rule table. This plugin's job is purely to attach the middleware to the right routes and stamp the metadata so downstream consumers (e.g. docs-swagger) can introspect the validators.

The legacy validation.rules array config ({ method, path, body, query }) has been removed. Validation now lives next to the entity in models/*.ts.


Configuration

All options are set via .env using the jex or JEX namespace:

# Global URL prefix for all generated routes
jex.api.rest.prefix=/api/v1

# Disable the /search endpoint entirely
jex.api.rest.search=false

With prefix /api/v1, routes become /api/v1/users, /api/v1/search, etc.


Installation

This plugin is bundled as the default API generator in the JSONExpress CLI. To use explicitly:

npm install @json-express/api-rest

Architecture Note

Kernel.boot(collections)
  └─ apiGenerator.generate(collections)
       ├─ POST /search   ← registered first to prevent route shadowing
       ├─ GET /users
       ├─ GET /users/:id
       ├─ POST /users
       ├─ PATCH /users/:id
       └─ DELETE /users/:id

The /search route is registered before per-collection routes. This is critical in Express — registering it after POST /users would result in Express matching POST /search as a request to create a record in a search collection.