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 🙏

© 2024 – Pkg Stats / Ryan Hefner

restyped

v1.1.0

Published

End-to-end typing for REST APIs with TypeScript

Downloads

6,589

Readme

Motivation

Typescript is a one-way street: Once you start using it, it's hard to go back to plain JS. In fact, you'll probably want to write your entire application in TypeScript.

After happily typing all of your models, you notice that there's a disconnect: Your types don't make it over the wire! The server doesn't check types before it sends an HTTP response, and the client doesn't know what types it's receiving. Conversely, the server doesn't know what types it should receive, and the client doesn't know what to send.

RESTyped was designed to brige the gap by creating an easy way to share types across your API server and any public or private clients.

Benefits

  • End to end typing. Share request and response types between your client and server for ease of use and peace of mind
  • Unopinionated. Works with any new or existing REST API
  • Universal. Can support any server framework or REST client
  • Lightweight. Most server and client implementations don't even add any code--just types
  • Use existing syntax. Write your REST routes and clients the same way you always have
  • Great for private APIs. Keep API clients across your organization in sync with the latest changes
  • Great for public APIs. Create an API definition so TypeScript users can consume your API fully typed
  • Easy to learn and use. Start using RESTyped in typically less than one minute per route

How to use it

RESTyped is a specification. Once you spend a few minutes typing your API using the spec below, you can use these server and client typings to declare and consume your API in a type-safe manner:

You can help make RESTyped more useful by typing your favorite server framework or HTTP client!

RESTyped requires TypeScript 2.4 or higher.

Specification

It's very easy to get started with RESTyped. Just follow a few steps to type your existing API or create a new typed API:

  • Your API should be defined in one interface, exported as {my_api_name}API from a file ending in .d.ts
  • Each route is a top level key in the interface. You should exclude any prefixes like /api/.
  • Each route can have up to one key per valid HTTP method:
    • GET, POST, PUT, PATCH, DELETE, HEAD or OPTIONS
  • Each HTTP method can have one or more of the following keys:
    • params: Route params in the URL (e.g. /users/:id would have id as a param)
    • query: Query string params, typically used in GET requests (e.g. req.query in express)
    • body: JSON body object (e.g. req.body in express or data object in an axios request)
    • response: The route's JSON response

Example: my-social-api.d.ts

interface User { // Model inteface--could be imported from another file
  email: string
  name: string
  gender: 'Male' | 'Female' | 'Other'
}

export interface MySocialAPI {
  '/users': { // Route name (wihout prefix, if you have one)
    GET: { // Any valid HTTP method
      query: { // Query string params (e.g. /me?includeProfilePics=true)
        includeProfilePics?: boolean
      }
      response: User[] // JSON response
    }
  }

  '/user/:id/send-message': {
    POST: {
      params: { // Inline route params
        id: string
      }
      body: { // JSON request body
        message: string
      }
      response: { // JSON response
        success: boolean
      }
    }
  }
}

Full-Stack Example

1. Define your API (food-delivery-api.d.ts)

export interface FoodDeliveryAPI {
  '/me/orders': {
    POST: {
      body: {
        foodItemIds: string[]
        address: string
        paymentMethod: 'card' | 'cash'
        paymentCardId?: string
      }
      response: {
        success: boolean
        eta?: string
      }
    }
  }

  // ...other routes...
}

2. Declare the API via express

import {AsyncRouter} from 'restyped-express'
import {FoodDeliveryAPI} from './food-delivery-api'

import OrderModel from './controllers/order'

const route = AsyncRouter<FoodDeliveryAPI>('/api/')

route.post('/me/orders', async (req) => {
  // Will not compile if you attempt to access an invalid body property
  const {foodItemId, address} = req.body
  const success = await OrderModel.order(foodItemId, address)

  // Will not compile if returned value is not of type {success: boolean}
  return {success}
})

3. Consume the API via axios

import axios from 'restyped-axios'
import {FoodDeliveryAPI} from './food-delivery-api'

const api = axios.create({baseURL: 'https://fooddelivery.com/api/'})

async function order() {
  // Will not compile if you request an invlid route or pass incorrect body params
  const res = await api.post(
    '/me/orders',
    {
      foodItemIds: ['QbY7Nmx1', '34YthU3m'],
      address: '1601 Market St, Phiadelphia, PA 19103',
      paymentMethod: 'cash'
    }
  )

  // TypeScript knows that res.data is of type {success: boolean, eta?: string}
  const {success, eta} = res.data
}

What RESTyped isn't

  • A replacement for API docs. A RESTyped spec will help you get the routes and types right, but doesn't provide the context or say anything about the content of API requests and responses.

Popular APIs to try out