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 is very modular. This is because the lambda functions have to be lightweight. You can use the projects you need in your web application.
- Core
- AWS Lambda implementation
- Google Cloud Functions implementation
- DustJS template engine implementation
- Examples
- Configurable
- HTTP requests routing
- Other events requests routing
- HTTP helpers (redirection, etc)
- Templating
- Error handling
- For any serverless provider
- Extensible with modules
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);
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) => {
...
});
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
});
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
});
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");
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();
});
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.
const reviver = (key: string, value: string): any => {
if(key === "KEY" && value === "VALUE") {
return 0;
} else {
return value;
}
};
app.use(new JsonParser().create(reviver));
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));
const options: {[name: string]: any} = {};
options.type = "multipart/form-data"; // By default
app.use(new MultipartParser().create(options));
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");
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.putHeader("key", "value");
response.putHeaders({
key1: "value1",
key2: "value2"
});
const previousPutHeader: string = response.header("key");
response.appendHeader("key", "value 2");
response.removeHeader("key2");
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");
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);
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);
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.