1.0.35 • Published 1 year ago

verdad v1.0.35

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

verdad

Verdad

Verdad lets you:

  • ✅ write your API once, with support for multiple base URLs and fully typed parameters & bodies (using io-ts)
  • ✅ implement and deploy your API to any infrastructure using built-in or custom extensions
  • ✅ call your API from the client with zero duplication and no synchonization headaches

Step 1

Define your backend API in Verdad:

import * as t from 'io-ts'

import { StatusCodes } from "http-status-codes";
import { NumberFromString } from 'io-ts-types';

import { VerdadRESTAPI } from "verdad";

export const musicAPI = VerdadRESTAPI.api({
  name: 'my New Music Startup',
  servers: {
    prod: 'https://api.music.com',
    test: 'https://test-api.music.com',
  },
  builder: (ctx) => ({
    playlists: VerdadRESTAPI.resource(ctx, ['users', { parameter: 'userID' }, 'playlists'], {

      get: (ctx) => VerdadRESTAPI.method(ctx, {
        pathParametersType: t.type({ userID: t.string }),
        queryParametersType: t.partial({ pageNumber: NumberFromString }),
        headerParametersType: t.type({ 'authorization-token': t.string, }),
        requestBodyType: t.null,
        successResponse: {
          statusCodes: [
            StatusCodes.OK as const
          ],
          bodyType: t.array(PlaylistModel)
        },
        errorResponse: {
          statusCodes: [
            StatusCodes.UNAUTHORIZED as const,
            StatusCodes.BAD_REQUEST as const,
            StatusCodes.INTERNAL_SERVER_ERROR as const,
          ],
          bodyType: t.type({ errorDetails: t.string }),
        }
      }),

      post: () => undefined,
      delete: () => undefined,
      patch: () => undefined,
      put: () => undefined,
    }),

    // albums: ...,
  })
})

Step 2

Use an extension to deploy this API to your infrastructure of choice:

For example, to deploy to AWS Lambda:

  1. Call VerdadCloudFormation.makeServerlessFunctions() from your serverless.ts file:
import type { AWS } from '@serverless/typescript';
import { VerdadCloudFormation } from 'verdad/lib/extensions';

const serverlessConfig: AWS = {
  service: 'music-api',
  provider: { name: 'aws' },
  functions: VerdadCloudFormation.makeServerlessFunctions(musicAPI),
};

module.exports = serverlessConfig;
  1. Implement each of your API methods. makeServerlessFunctions() looks for the implementations under src/resources/<path>/<method>. For the users/*/playlists GET method example above, it would look for an implementation in src/resources/users/playlists/get.ts:
export const { verdadMain } = implement(
  musicAPI.resources.playlists.get,
  async (input) => {
    const playlists = retrievePlaylists(
      input.pathParameters.userID,
      input.headerParameters['authorization-token'],
      input.queryParameters.pageNumber,
    )

    return E.right({
      statusCode: StatusCodes.OK,
      body: {
        value: playlists,
        type: t.array(PlaylistModel)
      }
    })
  },
  (error: LambdaRuntimeError) => {
    error // <-- access error
    // Error is a discriminated union; use switch to handle specific error scenarios
    return {
      statusCode: StatusCodes.INTERNAL_SERVER_ERROR,
      body: {
        value: { errorDetails: 'Details hidden for security' },
        type: t.type({ errorDetails: t.string }),
      }
    }
  }
)

Step 3

Use a client extension to call the APIs:

For example, to make calls using Axios:

import { VerdadAxios } from './extensions/axios/Axios';

async function getPlaylists(userID: string, authToken: string) {

  const musicAPIAxios = new VerdadAxios.RESTAPI({
    api: musicAPI,
    server: 'prod',
    debug: {} // Permits logger and custom HTTP agent to support MitM intercepts
  })

  const playlists = await musicAPIAxios.callMethod(api => api.playlists.get, {
    pathParameters: { userID },
    queryParameters: {},
    headerParameters: {
      'authorization-token': authToken
    },
    body: null,
  })

  if (E.isRight(playlists)) {
    displayToUser(playlists.right.successResponse)

  } else {
    playlists.left // <-- access error
    // Error is a discriminated union; use switch to handle specific error scenarios
    console.log("Could not load playlists from backend API")
  }
}
1.0.29

2 years ago

1.0.28

2 years ago

1.0.33

2 years ago

1.0.32

2 years ago

1.0.31

2 years ago

1.0.30

2 years ago

1.0.35

1 year ago

1.0.34

2 years ago

1.0.27

2 years ago

1.0.22

2 years ago

1.0.21

2 years ago

1.0.20

2 years ago

1.0.26

2 years ago

1.0.25

2 years ago

1.0.24

2 years ago

1.0.23

2 years ago

1.0.19

2 years ago

1.0.18

2 years ago

1.0.17

2 years ago

1.0.16

2 years ago

1.0.15

2 years ago

1.0.14

2 years ago

1.0.13

2 years ago

1.0.12

2 years ago

1.0.11

2 years ago

1.0.10

2 years ago

1.0.9

2 years ago

1.0.8

2 years ago

1.0.7

2 years ago

1.0.0

2 years ago