Skip to content

A framework to create serverless web applications with any provider.

License

Notifications You must be signed in to change notification settings

rogelio-o/lambda-framework

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Lambda Framework

CII Best Practices Coverage Status Build Status npm version

A framework to create serverless web applications with any provider.

This is the core project, you can use it with an official implementation of a provider or you can implement your own provider. For more information, please keep reading.

The idea behind Lambda Framework is that you can use the features of the framework forgetting the provider you are using. Thus, you can change the provider without change your code base. The only thing you have to do for change the provider is change the lib that implements the one provider for other, but the core will be the same.

Lambda Framework projects

Lambda Framework is very modular. This is because the lambda functions have to be lightweight. You can use the projects you need in your web application.

Features

  • Configurable
  • HTTP requests routing
  • Other events requests routing
  • HTTP helpers (redirection, etc)
  • Templating
  • Error handling
  • For any serverless provider
  • Extensible with modules

How to use it?

Initialize the App

The main object is the App. You have to instantiate a new App object and then you can do what you need with it.

import { App, IApp } from "lambda-framework";

const app: IApp = new App();

A event handling is started passing that event to the App method handle.

app.handle(event, callback);

You don't need to care about passing the event to the App handler, you can use the AWS Lambda implementation, Google Cloud Functions implementation or another provider implemented by yourself. These will manage the creation of the raw event and passing it to the handler.

import { App, IApp } from "lambda-framework";
import { AWSHandler } from "lambda-framework-aws";

const app: IApp = new App();
...
const handler: AWSHandler = new AWSHandler(app);
export const handle = handler.handle.bind(handler);

Event handling

A handler can be related with an event type or with a event that fulfil a predicate. When the event happens, the handler is executed.

app.event("eventType", (req: IEventRequest, next: INext, error: Error) => {
  ...
});

const predicate: IEventRoutePredicate = (req: req: IEventRequest) => {
  return req.event.original.param1 === "value1";
};
app.event(predicate, (req: IEventRequest, next: INext, error: Error) => {
  ...
});

HTTP Routing

use

Handlers can be executed when a request is received for a specified path.

app.use((req: IHttpRequest, res: IHttpResponse, next: INext) => {
  ... // Do something
  next();
}, "/blog/*");

app.use((req: IHttpRequest, res: IHttpResponse, next: INext, error: Error) => {
  ... // Error handling
});

route

Also, a final controller action can be executed when a request is received with a specified path and method (POST, GET, PUT or DELETE).

app.route("/blog/:id")
  .get((req: IHttpRequest, res: IHttpResponse) => {
    ... // Do something
  })
  .put((req: IHttpRequest, res: IHttpResponse) => {
    ... // Do something
  });

mount

The app has a default router. The router can have subrouters with more routes. The subrouters can have a prefix in order to execute its routes only when the path starts with the prefix.

const subrouter: IRouter = new Router();

subrouter.route("/:id")
  .get(...)
  .put(...);

app.mount(subrouter, "/blog");

param

Handlers can be related also with the apparition of a param in a request. For example, each time the user param appears, a handler loading the user is executed.

app.param("user", (req: IHttpRequest, res: IHttpResponse, next: INext, placeholderValue: any) => {
  ... // Load user
  next();
});

HTTP body parsers

There is a few body parsers that can be used. The body parsers have to be added as a handler to the path in which you want to use it.

JSON

const reviver = (key: string, value: string): any => {
  if(key === "KEY" && value === "VALUE") {
    return 0;
  } else {
    return value;
  }
};

app.use(new JsonParser().create(reviver));

UrlEncoded

const options: {[name: string]: any} = {};
options.type = "application/x-www-form-urlencoded"; // By default
options.extended = false; // By default

app.use(new UrlEncodedParser().create(options));

Multipart

const options: {[name: string]: any} = {};
options.type = "multipart/form-data"; // By default

app.use(new MultipartParser().create(options));

Others HTTP features

Response body

To response with a plain body:

response.send("RESPONSE");

To response with a JSON body:

response.json({key: "value"});

To response with a HTTP status and a body with a description:

response.sendStatus(400);

To set the Content-Type of the response:

response.contentType("text/html");

Format

To do things according to the Accept header of the request:

response.format({
  "text/html": (req: IHttpRequest, res: IHttpResponse) => {
    ... // Do things
  },
  "application/json": (req: IHttpRequest, res: IHttpResponse) => {
    ... // Do things
  }
});

Response headers

response.putHeader("key", "value");

response.putHeaders({
  key1: "value1",
  key2: "value2"
});

const previousPutHeader: string = response.header("key");

response.appendHeader("key", "value 2");

response.removeHeader("key2");

Cookies

Cookies can be added creating a Cookie object and adding it to the response. The cookies can be configured with the expiration date and the path.

const cookie: ICookie = new Cookie("cookie-name", "value", new Date(1, 1, 2020), "/", false);

response.addCookie(cookie);

response.addCookies([cookie]);

Signed cookies can be added configuring the secret key in the app and configuring the cookie object on creation.

app.set(configuration.COOKIE_SECRET, "SIGNED KEY");

const cookie: ICookie = new Cookie("cookie-name", "value", new Date(1, 1, 2020), "/", true);
response.addCookie(cookie);

Added cookies can be get from the response.

const cookie = response.cookie("cookie-name");

Redirection

Redirections can be done in the response with location or redirect. The passed URL can be back, so the user will be redirected to Referrer or Referer headers (or to / if there is no referrer header). In the method redirect, the HTTP status code can be specified.

response.location("back");

response.redirect("back");

response.redirect("/new-location", 301);

Templating

There is a render method for rendering HTML templates. The methods can have the following parameters:

  • view: the template name.
  • options: the params that will be injected into the view.
  • callback: optional. If no callback is given, the resulting HTML will be returned as response body with 200 HTTP status. If callback is given, the resulting HTML will be passed as callback param.
response.render("template1", {param: "value"});

response.render("template1", {param: "value"}, (html: string) => {
  doSomethingWithTemplate(html);
});

IMPORTANT: in order to use the render method, a template engine has to be added to the app or to the subrouter in which it is used. Check the project to know more about the DustJS template engine.

app.addTemplateEngine(templateEngine);

Contributions

All contributors will be welcome. You can contributing by implementing/fixing/answering one open issue, by suggesting new features for the framework,... For more info about contributing, you can read this.

Make it happen.