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

@riao/rest

v2.1.1

Published

Riao REST API framework

Downloads

7

Readme

@riao/rest

Build production-ready REST APIs in minutes with pre-configured CRUD endpoints and intelligent routing.

Features

  • Ready-to-use CRUD endpoints - Create, read, update, and delete operations out of the box
  • Type-safe - Full TypeScript support with generic types
  • Database agnostic - Works with any database through @riao/dbal
  • Built-in validation - Integrate valsan validators seamlessly
  • Self-documenting - Automatically servers Swagger/OpenAPI docs from your code
  • Flexible & extensible - Override any behavior to match your requirements
  • Error handling - Standard REST error responses included

Installation

npm install @riao/rest api-machine valsan

Requirements

Quick Start

src/users.ts

import { RestServer } from 'api-machine';
import {
    RiaoRouter,
    RiaoCreateEndpoint,
    RiaoGetListEndpoint, 
    RiaoGetOneEndpoint,
    RiaoUpdateEndpoint,
    RiaoDeleteEndpoint
} from 'riao-rest';
import { ObjectValSan, LengthValidator } from 'valsan';

import { maindb } from '../database/main';

// Define your model
interface User {
  id: string;
  name: string;
  email: string;
}

const userRepo = maindb.getQueryRepository<User>({
    table: 'users',
});

const userValidators = {
    id: new ComposedValSan([
        new LengthValidator({ min: 1, max: 36 })
    ]),
    name: new ComposedValSan([
	    new TrimSanitizer(),
	    new LengthValidator({ minLength: 1, maxLength: 100 }),
    ]),
    email: new ComposedValSan([
        new TrimSanitizer(),
        new LengthValidator({ minLength: 10, maxLength: 100 }),
        new EmailValidator(),
    ])
};

// Create endpoints by extending base classes
class CreateUserEndpoint extends RiaoCreateEndpoint<User> {
  override body = new ObjectValSan({
    schema: {
      name: userValidators.name,
      email: userValidators.email,
    }
  });

  override response = new ObjectValSan({
    schema: {
      id: userValidators.id
    }
  });
}

class ListUsersEndpoint extends RiaoGetListEndpoint<User> {}

class GetUserEndpoint extends RiaoGetOneEndpoint<User> {
  override params = new ObjectValSan({
    schema: {
      id: userValidators.id
    }
  });
}

class UpdateUserEndpoint extends RiaoUpdateEndpoint<User> {
  override params = new ObjectValSan({
    schema: {
      id: userValidators.id
    }
  });

  override body = new ObjectValSan({
    schema: {
      name: userValidation.name.copy({ isOptional: true }),
      email: userValidation.email.copy({ isOptional: true })
    }
  });
}

class DeleteUserEndpoint extends RiaoDeleteEndpoint<User> {
  override params = new ObjectValSan({
    schema: {
      id: userValidators.id
    }
  });
}

// Set up the router
class UsersRouter extends RiaoRouter<User> {
  override repo = yourDatabaseRepository;
  override path = '/users';

  protected override async routes() {
    return [
      CreateUserEndpoint,
      GetUserEndpoint,
      ListUsersEndpoint,
      UpdateUserEndpoint,
      DeleteUserEndpoint,
    ];
  }
}

// Start the server
class Server extends RestServer {
  override router = UsersRouter;
}

This creates a fully functional REST API with the following endpoints:

  • POST /users - Create a user
  • GET /users - List all users
  • GET /users/:id - Get a specific user
  • PUT /users/:id - Update a user
  • DELETE /users/:id - Delete a user

Available Endpoints

RiaoCreateEndpoint

Creates new records with automatic validation and conflict checking.

class CreateEndpoint extends RiaoCreateEndpoint<YourModel> {
  override body = new ObjectValSan({ schema: { /* validators */ }});
  
  // Optional: Check for conflicts before creating
  override async checkConflict(request: ApiRequest): Promise<void> {
    // Your conflict logic
  }
}

RiaoGetListEndpoint

Retrieves records from the database with pagination & sorting.

class ListEndpoint extends RiaoGetListEndpoint<YourModel> {}

RiaoSearchEndpoint

Powerful search and filtering with support for complex queries, aggregations, and advanced filtering operators.

The search endpoint supports:

  • Advanced filtering with multiple operators (equality, comparison, LIKE, INARRAY, BETWEEN)
  • Aggregations (COUNT, SUM, AVG, MIN, MAX) with grouping
  • Flexible column selection with security through column mapping
  • Sorting and pagination for large result sets

For detailed documentation on all query capabilities, see the Search Endpoint Guide.

class SearchEndpoint extends RiaoSearchEndpoint<YourModel> {
  override responseExample = {
    records: [
      {
        id: 1,
        name: 'Example',
        email: '[email protected]'
      }
    ],
    count: 148,
  };

  override response = new ObjectValSan({
    schema: {
      records: new ArrayValSan({
        schema: new ObjectValSan({ schema: userValidators }),
      }),
      count: new ComposedValSan([
        new StringToNumberValSan()
      ]),
    },
  });

  protected override getColumnMap() {
    return {
      id: { column: 'users.id' },
      name: { column: 'users.name' },
      email: { column: 'users.email' },
    };
  }
}

RiaoGetOneEndpoint

Retrieves a single record by ID with automatic 404 handling.

class GetEndpoint extends RiaoGetOneEndpoint<YourModel> {
  override params = new ObjectValSan({ schema: { /* validators */ }});
}

RiaoUpdateEndpoint

Updates existing records with partial data support.

class UpdateEndpoint extends RiaoUpdateEndpoint<YourModel> {
  override params = new ObjectValSan({ schema: { /* validators */ }});
  override body = new ObjectValSan({ schema: { /* validators */ }});
}

RiaoDeleteEndpoint

Deletes records by ID.

class DeleteEndpoint extends RiaoDeleteEndpoint<YourModel> {
  override params = new ObjectValSan({ schema: { /* validators */ }});
}

RiaoRouter

The router manages your endpoints and injects the database repository.

class YourRouter extends RiaoRouter<YourModel> {
  override repo = yourRepository;
  override path = '/your-path';

  protected override async routes() {
    return [
      /* Your endpoint classes */
    ];
  }
}

Customization

Every endpoint can be customized by overriding methods:

class CustomCreateEndpoint extends RiaoCreateEndpoint<User> {
  // Custom path
  override path = '/custom-path';
  
  // Custom status code
  override statusCode = 201;
  
  // Custom description for API docs
  override description = 'Create a new user';
  
  // Add custom error types
  override getErrors() {
    return {
      ...super.getErrors(),
      conflict: new ConflictError('User already exists'),
    };
  }
  
  // Override the main handler
  override async handle(request, response, next) {
    // Your custom logic
  }
}

Contributing & Development

See contributing.md for information on how to develop or contribute to this project!