Home

Awesome

<p align="center"> <img src="/images/logo.png" width="350"/> </p> <p align="center"> End-to-end typing for REST APIs with TypeScript </p>

Motivation

Read the blog post

Benefits

How to use it

RESTyped is a specification (see below). You can use these server and client packages along with a RESTyped defintion file to declare and consume APIs in a type-safe manner:

You can help make RESTyped more useful by implementing support in 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:

Also see the spec implementation base defintions.

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 (without 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

<a href="/examples/food-delivery-api.d.ts">food-delivery-api.d.ts</a>

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

  // ...other routes...
}

2. Declare the API via express

import RestypedRouter from 'restyped-express-async'
import { FoodDeliveryAPI } from './food-delivery-api'
import * as express from 'express'

const app = express()

const apiRouter = express.Router()
app.use('/api', apiRouter)

const router = RestypedRouter<FoodDeliveryAPI>(apiRouter)

router.post('/me/orders', async req => {
  // Will not compile if you attempt to access an invalid body property
  const {
    foodItemIds, // number[]
    address, // string
    paymentMethod // 'card' | 'cash'
  } = req.body

  const success = await OrderModel.order(foodItemIds, address, paymentMethod)

  // 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<FoodDeliveryAPI>({
  baseURL: 'https://fooddelivery.com/api/'
})

async function order() {
  // Will not compile if you pass incorrectly typed body params
  const res = await api.post('/me/orders', {
    foodItemIds: [142, 788],
    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

Popular APIs to try out