2.2.0 • Published 2 years ago

yandex-cloud-functions-router v2.2.0

Weekly downloads
103
License
MIT
Repository
github
Last release
2 years ago

yandex-cloud-functions-router Build npm.io

yandex-cloud-functions-router is a Node router for Yandex Cloud Function platform. It inspired by aws-lambda-router and simplifies the development of serverless applications for Yandex Cloud.

  • Provides an easy way to create Node-based handlers either for HTTP invocations and standard triggers.
  • Supports almost all supported triggers such as Timer trigger, Message Queue trigger, Object Storage trigger, and others.
  • Handles CORS for HTTP requests.
  • Can filter requests by HTTP method, params, body, queue identifier, and other trigger-specific params.
  • Customizable error mapping to appropriate responses.
  • Zero external dependencies.
  • Supports Typescript out of the box. 🤘

How it works

Once you create a Node application that uses this package, you can assign some routes to the handlers. Next, you publish the Yandex Cloud Functions application and it will handle every request with the corresponding handler.

import { router } from 'yandex-cloud-functions-router';

export.handler = router({
    http: [
      {
        httpMethod: ['GET'],
        handler: (event, context) => {
          // Handle HTTP request
          return {
            statusCode: 200,
            body: 'Hello from Yandex Cloud Functions'
          };
        }
      },
      {
        httpMethod: ['POST'],
        handler: (event, context) => {
          // Handle HTTP request
          return {
            statusCode: 200,
            body: 'Hello again'
          };
        }
      }
    ],
    message_queue: [
      {
        queueId: ['a4wt2lnqwvjwnregbqbb'],
        handler: (event, context, message) => {
          // Handle Message Queue item
        }
      }
    ]
  });

Examples:

Requirements

  • Node 12+

Usage

  1. Install the package using npm:
$ npm install yandex-cloud-functions-router
  1. Create router handler and export it from the main module (for example, in index.js):
import { router } from 'yandex-cloud-functions-router';

export.handler = router({ /* ... */ });
  1. Create a new Yandex Cloud Function in the developer console. Use nodejs12/nodejs12-preview as a runtime environment. Also, don't forget to specify Entrypoint for the function.

yf-create

  1. Now the function is able to handle requests 🎉

HTTP requests

Mark the function as public to be able to make HTTP requests. Once it's done, you can access it by provided URL.

yf-http

To handle incoming HTTP requests, add http key into the routes definition. httpMethod and handler params are mandatory for every route.

import { router } from 'yandex-cloud-functions-router';

export.handler = router({
    http: [
      {
        httpMethod: ['GET'],           /* Filter by HTTP method (required). */
        params: { },                   /* Filter by Query String params (optional). */
        body: { },                     /* Filter by body content (optional). */
        decodeBase64Body: false,       /* Whether to decode base64 requests. */
        validators: { },               /* Additional validator(s) for the event. */
        handler: (event, context) => { /* Handler function (required). */
          // Handle HTTP GET request

          return {
            statusCode: 200
          };
        }
      },
      {
        httpMethod: ['POST'],
        handler: (event, context) => {
          // Handle HTTP POST request

          return {
            statusCode: 200
          };
        }
      }
    ]
  });

handler accepts two params that came from Yandex Cloud. The result that function returns passed directly to Yandex Cloud, so please use Yandex Cloud Function response format.

It is possible to filter requests by HTTP method, query params, and body content.

Filtering by HTTP method

To filter requests by HTTP method, specify httpMethod property for a route. It's an array of HTTP methods that the current handle can process. It is a required property.

import { router } from 'yandex-cloud-functions-router';

export.handler = router({
    http: [
      {
        httpMethod: ['GET'],
        handler: (event, context) => {
          // Handle HTTP GET request

          return {
            statusCode: 200
          };
        }
      },
      {
        httpMethod: ['POST'],
        handler: (event, context) => {
          // Handle HTTP POST request

          return {
            statusCode: 200
          };
        }
      },
      {
        httpMethod: ['PUT'],
        handler: (event, context) => {
          // Handle HTTP PUT request

          return {
            statusCode: 200
          };
        }
      }
    ]
  });

Filtering by Query String params

To filter requests by Query String params, specify params property for a route. It's a key-value dictionary (key is param name).

There are few ways how to hanlde these params - by exact match, substring, or regular expression.

It is an optional property.

import { router } from 'yandex-cloud-functions-router';

export.handler = router({
    http: [
      {
        httpMethod: ['GET'],
        params: {
            type: {
                type: 'exact',
                value: 'get'
            }
        },
        handler: (event, context) => {
          // Handle /?type=get requests

          return {
            statusCode: 200
          };
        }
      },
      {
        httpMethod: ['GET'],
        params: {
            type: {
                type: 'substring',
                value: 'qwerty'
            }
        },
        handler: (event, context) => {
          // Handle requests where "type" param contains "qwerty"

          return {
            statusCode: 200
          };
        }
      },
      {
        httpMethod: ['GET'],
        params: {
            type: {
                type: 'regexp',
                pattern: /[0-9]+/i
            }
        },
        handler: (event, context) => {
          // Handle requests where "type" param contains numbers

          return {
            statusCode: 200
          };
        }
      },
      {
        httpMethod: ['GET'],
        params: {
            type: {
                type: 'exact',
                value: 'find'
            },
            context: {
                type: 'exact',
                value: '1'
            }
        },
        handler: (event, context) => {
          // Handle /?type=find&context=1 requests

          return {
            statusCode: 200
          };
        }
      }
    ]
  });

Filtering by Body content

To filter requests by Body content, specify body property for a route. For the moment, only JSON content is supported. So to use the filter the request must contain Content-Type: application/json header and body should contain valid JSON object. If these criteria aren't met, the route will be ignored. It is an optional property.

import { router } from 'yandex-cloud-functions-router';

export.handler = router({
    http: [
      {
        httpMethod: ['POST'],
        body: {
          json: {
            type: 'add',
          },
        },
        handler: (event, context) => {
          // Handle requests with the following body content
          // { "type": "add", ... }

          return {
            statusCode: 200
          };
        }
      },
      {
        httpMethod: ['POST'],
        body: {
          json: {
            type: 'update',
          },
        },
        handler: (event, context) => {
          // Handle requests with the following body content
          // { "type": "update", ... }

          return {
            statusCode: 200
          };
        }
      }
    ]
  });

Validators

Validators supposed to validate the event's content. In contrast to filtering, the route won't be skipped if the validator fails. Instead, exception will be thrown (and could be handled as a final HTTP 400 error). It is useful to use validators, when you're sure that it's the right route, but want to ensure that incoming request contains the correct data. For instance, if an incoming request doesn't contain the required field, it will fail.

import { router } from 'yandex-cloud-functions-router';

export.handler = router({
    http: [
      {
        httpMethod: ['POST'],
        validators: [
          (event, context) => {
              if (/* check something in the event */) {
                  return true;
              }

              return false;
          }
        ],
        handler: (event, context) => {
          // Here you are sure that the request contains the correct data

          return {
            statusCode: 200
          };
        }
      }
    ]
  });

CORS

To handle CORS requests add second param to the router function:

import { router } from 'yandex-cloud-functions-router';

export.handler = router({
    http: [
      {
        httpMethod: ['POST'],
        handler: (event, context) => {
          return {
            statusCode: 200
          };
        }
      }
    ]
  },
  {
    cors: {
      enable: true,                               /* Whether CORS support is enabled (required). */
      allowedOrigins: ['http://localhost:5000'],  /* Origins that allowed to request the function (optional). */
      allowedMethods: ['GET', 'POST', 'PUT'],     /* Allowed methods that will be put into Access-Control-Allow-Methods (optional). */
      allowedHeaders: ['X-Test'],                 /* Allowed custom headers that will be put into Access-Control-Allow-Headers (optional). */
      allowCredentials: true                      /* Whether to add Access-Control-Allow-Credentials to the response (optional). */
    }
  );

Timer trigger

To handle Timer trigger events, add the timer key into the routes definition. The only handler param is mandatory for the route.

import { router } from 'yandex-cloud-functions-router';

export.handler = router({
    timer: [
      {
        triggerId: ['a4wt2lnqwvjwnregbqbb'],     /* Filter by trigger identifier (optional). */
        handler: (event, context, message) => {  /* Handler function (required). */
          // Handle Timer trigger event
        }
      }
    ]
  });

handler accepts three params that came from Yandex Cloud.

It is possible to filter events by trigger ID.

Filtering by Trigger ID

To filter events by Trigger ID, specify triggerId property for a route. It is an optional property.

import { router } from 'yandex-cloud-functions-router';

export.handler = router({
    timer: [
      {
        triggerId: ['a4wt2lnqwvjwnregbqbb'],
        handler: (event, context, message) => {
          // Handle Timer trigger event
          // for a4wt2lnqwvjwnregbqbb timer
        }
      },
      {
        triggerId: ['b4wt2lnqwvjwnregbqbb'],
        handler: (event, context, message) => {
          // Handle Timer trigger event
          // for b4wt2lnqwvjwnregbqbb timer
        }
      },
    ]
  });

Message Queue trigger

To handle Message Queue trigger events, add the message_queue key into the routes definition. The only handler param is mandatory for the route.

import { router } from 'yandex-cloud-functions-router';

export.handler = router({
    message_queue: [
      {
        queueId: ['a4wt2lnqwvjwnregbqbb'],       /* Filter by queue identifier (optional). */
        body: { },                               /* Filter by body content (optional). */
        validators: { },                         /* Additional validator(s) for the event. */
        handler: (event, context, message) => {  /* Handler function (required). */
          // Handle Message Queue trigger event
        }
      }
    ]
  });

handler accepts three params that came from Yandex Cloud.

It is possible to filter events by queue ID or body content.

Filtering by Queue ID

To filter events by Queue ID, specify queueId property for a route. It is an optional property.

import { router } from 'yandex-cloud-functions-router';

export.handler = router({
    message_queue: [
      {
        queueId: ['a4wt2lnqwvjwnregbqbb'],
        handler: (event, context, message) => {
          // Handle Message Queue trigger event
          // for a4wt2lnqwvjwnregbqbb queue
        }
      },
      {
        queueId: ['b4wt2lnqwvjwnregbqbb'],
        handler: (event, context, message) => {
          // Handle Message Queue trigger event
          // for b4wt2lnqwvjwnregbqbb queue
        }
      }
    ]
  });

Filtering by Body content

To filter events by Body content, specify body property for a route. You can filter by JSON object properties or regular expression.

To use JSON filtering the request must contain Content-Type: application/json header and body should contain valid JSON object. If these criteria aren't met, the route will be ignored.

It is an optional property.

import { router } from 'yandex-cloud-functions-router';

export.handler = router({
    message_queue: [
      {
        body: {
            json: {
                type: 'add'
            }
        },
        handler: (event, context, message) => {
          // Handle Message Queue trigger event
          // that has JSON object in body with type=add property.
        }
      },
      {
        body: {
            json: {
                type: 'update'
            }
        },
        handler: (event, context, message) => {
          // Handle Message Queue trigger event
          // that has JSON object in body with type=update property.
        }
      }
    ]
  });
import { router } from 'yandex-cloud-functions-router';

export.handler = router({
    message_queue: [
      {
        body: {
            pattern: /add/i
        },
        handler: (event, context, message) => {
          // Handle Message Queue trigger event
          // whose body contains "add" word
        }
      },
      {
        body: {
            pattern: /update/i
        },
        handler: (event, context, message) => {
          // Handle Message Queue trigger event
          // whose body contains "update" word
        }
      }
    ]
  });

Validators

Validators supposed to validate the event's content. In contrast to filtering, the route won't be skipped if the validator fails. Instead, exception will be thrown. It is useful to use validators, when you're sure that it's the right route, but want to ensure that incoming request contains the correct data. For instance, if an incoming request doesn't contain the required field, it will fail.

import { router } from 'yandex-cloud-functions-router';

export.handler = router({
    message_queue: [
      {
        validators: [
          (event, context) => {
              if (/* check something in the event */) {
                  return true;
              }

              return false;
          }
        ],
        handler: (event, context, message) => {
          // Here you are sure that the request contains the correct data
        }
      }
    ]
  });

Object Storage trigger

To handle Object Storage trigger events, add the object_storage key into the routes definition. The only handler param is mandatory for the route.

import { router } from 'yandex-cloud-functions-router';

export.handler = router({
    object_storage: [
      {
        type: ['create'],                        /* Filter by operation type (optional). */
        bucketId: ['s3'],                        /* Filter by bucket identifier (optional). */
        objectId: ['1.jpg'],                     /* Filter by object identifier (optional). */
        handler: (event, context, message) => {  /* Handler function (required). */
          // Handle Object Storage trigger event
        }
      }
    ]
  });

handler accepts three params that came from Yandex Cloud.

It is possible to filter events by type, bucket identifier, and object identifier.

Filtering by Type

To filter events by type, specify type property for a route. Possible values for this filter are create, update, or delete. It is an optional property.

import { router } from 'yandex-cloud-functions-router';
export.handler = router({
    object_storage: [
      {
        type: ['create'],
        handler: (event, context, message) => {
          // Handle creating new object in Object Storage
        }
      },
      {
        type: ['update'],
        handler: (event, context, message) => {
          // Handle updating new object in Object Storage
        }
      },
      {
        type: ['delete'],
        handler: (event, context, message) => {
          // Handle deleting new object in Object Storage
        }
      }
    ]
  });

Filtering by Bucket ID

To filter events by bucket identifier, specify bucketId property for a route. It is an optional property.

import { router } from 'yandex-cloud-functions-router';
export.handler = router({
    object_storage: [
      {
        bucketId: ['s3'],
        handler: (event, context, message) => {
          // Handle event in "s3" bucket
        }
      }
    ]
  });

Filtering by Object ID

To filter events by object identifier, specify objectId property for a route. It is an optional property.

import { router } from 'yandex-cloud-functions-router';
export.handler = router({
    object_storage: [
      {
        objectId: ['1.jpg'],
        handler: (event, context, message) => {
          // Handle event in "1.jpg" object
        }
      }
    ]
  });

IoT Core trigger

To handle IoT Core message trigger events, add the iot_message key into the routes definition. The only handler param is mandatory for the route.

import { router } from 'yandex-cloud-functions-router';

export.handler = router({
    iot_message: [
      {
        registryId: ['arenou2oj4ct42eq8g3n'],               /* Filter by Registry ID (optional). */
        deviceId: ['areqjd6un3afc3cefcvm'],                 /* Filter by Device ID (optional). */
        mqttTopic: ['$devices/areqjd6un3afc3cefcvm/events'],/* Filter by MQTT Topic (optional). */
        handler: (event, context, message) => {             /* Handler function (required). */
          // Handle IoT Core message trigger event
        }
      }
    ]
  });

handler accepts three params that came from Yandex Cloud.

It is possible to filter events by registry identifier, device identifier, and MQTT topic.

Filtering by Registry ID

To filter events by the registry, specify registryId property for a route. It is an optional property.

import { router } from 'yandex-cloud-functions-router';
export.handler = router({
    iot_message: [
      {
        registryId: ['arenou2oj4ct42eq8g3n'],
        handler: (event, context, message) => {
          // Handle IoT Core message trigger event
          // for arenou2oj4ct42eq8g3n registry
        }
      }
    ]
  });

Filtering by Device ID

To filter events by the device, specify deviceId property for a route. It is an optional property.

import { router } from 'yandex-cloud-functions-router';
export.handler = router({
    iot_message: [
      {
        deviceId: ['areqjd6un3afc3cefcvm'],
        handler: (event, context, message) => {
          // Handle IoT Core message trigger event
          // for areqjd6un3afc3cefcvm device
        }
      }
    ]
  });

Filtering by MQTT Topic

To filter events by MQTT topic, specify mqttTopic property for a route. It is an optional property.

import { router } from 'yandex-cloud-functions-router';
export.handler = router({
    iot_message: [
      {
        mqttTopic: ['$devices/areqjd6un3afc3cefcvm/events'],
        handler: (event, context, message) => {
          // Handle IoT Core message trigger event
          // by $devices/areqjd6un3afc3cefcvm/events topic
        }
      }
    ]
  });

Error mapping

In case of any exceptions during the request processing, it is possible to map these exceptions to specific output response. To do that specify errorHandling property in router options. There are standard exceptions as well as custom exception handling.

import { router } from 'yandex-cloud-functions-router';

export.handler = router({
    http: [/* ... */]
  },
  {
    errorHandling: {
      http: {
          notFound: (error) => ({
            statusCode: 404
          })
      },
      unknownEvent: (error) => ({
          statusCode: 404
      })
    }
  });

The following types of standard errors are supported:

  • http / messageQueue / objectStorage / iot:
    • notFound — throws when there are no matching route for the current request.
    • invalidRequest — throws when the route is found, but there is validation error (during validation process).
  • timer:
    • notFound — throws when there are no matching route for the current request.
  • unknownEvent — throws when the router is unable to determine the type of processed event.
  • unknownMessage — throws when the router started to process trigger event, but unable to determine the message type.
  • triggerCombinedError — if the function processes few messages at the time, and during the processing few exceptions are thrown, they will be combined into TriggerRouteError and could be handled with triggerCombinedError.

In addition, it is possible to handle errors that came from the handler's logic. To do that add custom section which is an array of definitions for error handling.

import { router } from 'yandex-cloud-functions-router';

export.handler = router({
    http: [/* ... */]
  },
  {
    errorHandling: {
      custom: [
        {
          error: 'Something happened',
          result: (error) => ({
            statusCode: 500
          })
        },
        {
          error: /error/i,
          result: (error) => ({
            statusCode: 500
          })
        }
      ]
    }
  });

Every definition contains two mandatory properties - error and result.

  • error could be either string and RegExp object that match the message of the exception.

  • result is a handler similar to normal (non-error) handler.

You can skip to define errorHandling option. In this case default set of error handlers will work, that will return HTTP 404 for notFound, and HTTP 400 for invalidRequest types. Default error handlers are defined only for HTTP events.

License

yandex-cloud-functions-router is released under the MIT License.

2.2.0

2 years ago

2.1.1

2 years ago

2.1.0

3 years ago

2.0.3

3 years ago

2.0.2

4 years ago

2.0.1

4 years ago

2.0.0

4 years ago

1.3.2

4 years ago

1.3.1

4 years ago

1.3.0

4 years ago

1.2.2

4 years ago

1.2.1

4 years ago

1.2.0

4 years ago

1.1.1

4 years ago

1.1.0

4 years ago

0.1.0

4 years ago

1.0.0

4 years ago

0.0.1-1

4 years ago

0.0.0

4 years ago