1.2.2 • Published 5 months ago

@tiny-type-api/universal v1.2.2

Weekly downloads
-
License
MIT
Repository
github
Last release
5 months ago

tiny-type-api

library for defining api interface server/client by TypeScript

@tiny-type-api/universal

npm version

@tiny-type-api/client

npm version

how to use

// universal.ts
import { defineApis, define } from '@tiny-type-api/universal'

// define apis
export const { apis } = defineApis({
  '/api/@me': {
    GET: {
      request: {
        headers: define<{
          Authorization: `Bearer ${string}`
        }>()
      },
      response: {
        200: {
          body: define<{ id: string; name: string, email?: string }>()
        }
      }
    }
  },
  '/api/user/:user_id': {
    GET: {
      request: {},
      response: {
        200: {
          body: define<{ id: string; name: string }>()
        }
      }
    },
    POST: {
      request: {
        body: define<{ name: string }>()
      },
      response: {
        200: {
          body: define<{
            id: string;
            name: string;
            email?: string;
          }>()
        },
        400: {
          body: define<{
            status: 400,
            reason: 'no body'
          }>()
        },
        404: {
          body: define<{
            status: 404,
            reason: 'no user_id'
          }>()
        }
      }
    },
    PUT: {
      request: {
        // FormData
        form: define<{ icon: Blob }>()
      },
      response: {
        200: {
          body: define<void>()
        }
      }
    }
  }
})

---

// client.ts
import { createClients, type Fetcher } from '@tiny-type-api/client'
import { apis } from './universal.js'

const clients = createClients(apis, 'http://localhost:8000')

clients['/api/user/:user_id'].POST.client({
  params: { user_id: 'user-id' },
  body: {
    name: 'user-name'
  }
}).then((res) => {
  if (res.status === 400) {
    console.error(res.status, res.body.status, res.body.reason)
    return
  }
  if (res.status === 404) {
    console.error(res.status, res.body.status, res.body.reason)
    return
  }
  if (!res.ok) {
    return
  }
  console.log(res.status, res.body.id, res.body.name, res.body.email)
})

// send FormData
clients['/api/user/:user_id'].PUT.client({
  params: { user_id: 'user-id' },
  form: {
    icon: new Blob()
  }
}).then(console.log)

// use custom fetcher
const fetcher: Fetcher = async <T>(options: Parameters<Fetcher>[0]) => {
  const init: Parameters<typeof fetch>[1] = {
    method: options.method
  }

  if (options.body) {
    init.body =
      typeof options.body === 'string'
        ? options.body
        : JSON.stringify(options.body)
  }

  const res = await fetch(options.url, init)
  return res as T
}

clients['/api/user/:user_id'].POST.client({
  params: { user_id: 'user-id' },
  body: {
    name: 'user-name'
  },
  fetcher: fetcher
}).then(console.log)

---

// server.ts
import { apis } from './universal.js'

async function handler(req: Request, res: Response) {
  const api = apis['/api/user/:user_id']['POST']

  // parse req.params
  if (!req.params.user_id) {
    const error = api.response[404].body({ status: 404, reason: 'no user_id' })
    return res.status(404).json(error)
  }
  const params = req.params as ReturnType<typeof api.request.params> // @todo create parser

  // parser req.body
  if (!req.body) {
    const error = api.response[400].body({ status: 400, reason: 'no body' })
    return res.status(400).json(error)
  }
  const body = req.body as ReturnType<typeof api.request.body> // @todo create parser

  // get email from database...
  const email = `${params.user_id}@example.jp`

  // check response body type
  const resBody = api.response[200].body({ id: params.user_id, name: body.name, email })
  return res.status(200).json(resBody)
}

how to exec example

$ npm install
$ npm run start -w @tiny-type-api/examples
1.2.2

5 months ago

1.2.1

5 months ago

1.2.0

5 months ago

1.1.2

8 months ago

1.1.1

8 months ago

1.1.0

8 months ago

1.0.1

8 months ago

1.0.0

8 months ago