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

@microgamma/apigator

v2.1.0

Published

typescript decorators for api development

Downloads

3,129

Readme

@microgamma/apigator npm version

Annotate a class with @Endpoint its methods with @Lambda with metadata that can be retrieved at runtime to bind them to providers such as AWS Lambda, Express.js, Google Functions, Azure Function and potentially any.

Right now the only providers available are: AWS with their Lambda service and Express.js see use with express.js A serverless plugin is provided. It uses the metadata within the classes to create at runtime the serverless configuration. In other words the developer won't need to worry about adding/editing serverless.yml functions section. See serverless-apigator

How to use it

Install

yarn add @microgamma/apigator

Create the app container

Create a service file.

// my-first.service.ts
import { Endpoint, Lambda } from '@microgamma/apigator';

@Endpoint({
  cors: true,
  name: 'my-first-service',
  private: false
})
export class MyFirstService {

  @Lambda({
    method: 'GET',
    path: '/'
  })
  public index() {
    return `Hello world! Today is ${new Date().toISOString()}`;
  }
}

Now you can retrieve the metadata at run time:

import { getEndpointMetadataFromClass, getLambdaMetadataFromClass } from '@microgamma/apigator';
import { MyFirstService } from './my-first.service';

const endpointMetadata = getEndpointMetadataFromClass(MyFirstService);
console.log({endpointMetadata});
const lambdas = getLambdaMetadataFromClass(MyFirstService);

lambdas.forEach((lambda) => console.log({lambda}));

/*
{
  endpointMetadata: { cors: true, name: 'my-first-service', private: false }
}
{
  lambda: { method: 'GET', path: '/', integration: 'lambda', name: 'index' }
}
*/

Usually you won't need to do the above though.

@Lambda

The @Lambda decorator stores the provided metadata and wraps the annotated method inside an asynchronous function. At runtime the function's real arguments may vary: i.e.: if it's called as an Aws Lambda its arguments will be event, context whether if called within express they will be request, response. To handle the differences between environments we use a service called LambdaDefaultHandler. By default, the AwsEventHandler is used. To use a different handler it must be specified in the @Endpoint decorator (see below).

Valid values are:

interface LambdaOptions {
  name?: string;  // name of the function, MUST not be set!
  path: string;  // the sub path which the lambda will be available.
  method: string;  // http method. can be any of the http verbs
  integration?: string; // only when using serverless: the integration to use. This is equivalent to set the integration into serverless.yml (Default: 'lambda')
  private?: boolean;  // only when using serverless: equivalent to set private in serverless.yml (Default: false)
  cors?: boolean;  // only when using serverless: equivalent to set cors in serverless.yml defaults to false
  authorizer?: string | {};  // only when using serverless: equivalent to providing an authorizer function in serverless.yml
  description?: string;
}

@Endpoint

The endpoint decorator stores the provided metadata and sets the implementation of the LambdaDefaultHandler to use. Valid values are:

interface EndpointOptions {
  readonly name: string;  // name of the endpoint
  readonly basePath?: string;  // base path that will be prepended to the path defined in each lambda.
  readonly private?: boolean;  // Default: false. Setting this field is equivalent to add its value to every @Lambda. If any @Lambda as private set then that will have precedence
  readonly cors?: boolean;  // Default: false. Same as private.
}

I.e. when using it with express.js ExpressEventHandler needs to be used.


@Endpoint({
  cors: true,
  name: 'my-first-service',
  private: false,
  providers: [{
    provide: LambdaDefaultHandler,
    implementation: ExpressEventHandler
  }]
})

@Path

Retrieves a value from the path and assign it to the annotated argument

@Lambda({
  method: 'GET',
  path: '/me/{name}'
})
public me(@Path('name') user) {
  return `Hello ${user}`;
}

@Body

Retrieves the body and assign it to the annotated argument

@Lambda({
  method: 'POST',
  path: '/me'
})
public me(@Body() user) {
  return `Hello ${user}`;
}

@Header

Retrieves a value from the http headers and assign it to the annotated argument

@Lambda({
  method: 'GET',
  path: '/me'
})
public me(@Header('name') user) {
  return `Hello ${user}`;
}

Use with express.js

Install express.js

yarn add express @types/express

Set ExpressEventHanlder as described above.

Be aware that express uses the :param notation for path parameters so the lambda path need to be such as

@Lambda({
  method: 'GET',
  path: '/me/:name'
})
public me(@Path('name') user) {
  return `Hello ${user}`;
}

Create server.ts file:

import { bootstrap, getEndpointMetadataFromClass, getLambdaMetadataFromClass, LambdaOptions } from '@microgamma/apigator';
import express, { Application } from 'express';
import { MyFirstService } from './my-first.service';

const app: Application = express();
const port = 3000;

const service = bootstrap(MyFirstService);

function createExpressHandler(lambda: LambdaOptions, app: Express.Application) {
  app[lambda.method.toLowerCase()](lambda.path, service[lambda.name]);
}

lambdas.forEach((lambda) => createExpressHandler(lambda, app));

app.listen(port, () => console.log(`Example app listening on port ${port}!`));

Run after transpile or with ts-node

yarn ts-node server.ts

You can hit your lambda at localhost:3000

Use with Serverless Framework

See serverless-apigator for more information.