Skip to content

Commit

Permalink
Merge 349ac6f into b2ccfc0
Browse files Browse the repository at this point in the history
  • Loading branch information
Romakita committed Oct 5, 2020
2 parents b2ccfc0 + 349ac6f commit 6a833c5
Show file tree
Hide file tree
Showing 30 changed files with 700 additions and 130 deletions.
77 changes: 45 additions & 32 deletions docs/tutorials/aws.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,50 +19,53 @@ More information here: [Official AWS Docs](http://docs.aws.amazon.com/lambda/lat

<Projects type="examples"/>

#### Installation
## Installation

First, install the `aws-serverless-express` module:
First, install the `tsed/platform-aws` module:

```bash
npm install --save aws-serverless-express
npm install --save @tsed/platform-aws
```

#### Configuration
## Configuration

You need to create three files:
Create a new `LambdaServer.ts` in `src` directory:

- One for the `Server` configuration,
- One for AWS, named `lambda.ts` (the entry point on AWS Lambda, which contains the function handler),
- One for the local development, for example "index.js" (that you can use to run the app locally with `ts-node local.ts`)
<<< @/docs/tutorials/snippets/aws/lambda.ts

Then create `lambda.js` on your root project:

Create the server and add the AWS middleware:
```javascript
module.exports = require("./dist/LambdaServer.js");
```

<<< @/docs/tutorials/snippets/aws/server-configuration.ts
This file will be used by AWS to forward request to your application.

Then create the lambda.ts:
Finally, [package and create your Lambda function](http://docs.aws.amazon.com/lambda/latest/dg/nodejs-create-deployment-pkg.html),
then configure a simple proxy API using Amazon API Gateway and integrate it with your Lambda function.

<<< @/docs/tutorials/snippets/aws/lambda.ts
See more details on [`aws-serveless-express`](https://github.com/awslabs/aws-serverless-express) project.

## Getting the API Gateway event object

This package includes decorators to easily get the event object Lambda receives from API Gateway:

And finally create an index.ts to run your server in development mode:
```typescript
import {$log} from "@tsed/common";
import {PlatformExpress} from "@tsed/platform-express";
import {Server} from "./Server";

async function bootstrap() {
try {
$log.debug("Start server...");
const server = await PlatformExpress.bootstrap(Server);

await server.listen();
$log.debug("Server initialized");
} catch (er) {
$log.error(er);
}
import {Controller, Get} from "@tsed/common";
import {AwsEvent, AwsContext} from "@tsed/platform-aws";

@Controller('/')
class MyCtrl {
@Get('/')
get(@AwsEvent() event: any, @AwsContext() context: any) {
console.log("Event", apiGateway.event);
console.log("Context", apiGateway.context);

return apiGateway;
}
}

bootstrap();
```

::: tip
You can find a project example with [AWS configuration here](https://github.com/TypedProject/tsed-example-aws).
:::
Expand All @@ -71,6 +74,16 @@ You can find a project example with [AWS configuration here](https://github.com/
You can see an example provided by the AWS Team on this [github repository](https://github.com/awslabs/aws-serverless-express/tree/master/examples/basic-starter).
:::

::: tip Credits
Thanks to [vetras](https://github.com/vetras) for his contribution.
:::
## Author

<GithubContributors :users="['Romakita']"/>

## Maintainers <Badge text="Help wanted" />

<GithubContributors :users="['Romakita', 'vetras']"/>

<div class="container--centered container--padded">
<a href="/contributing.html" class="nav-link button">
Become maintainer
</a>
</div>
21 changes: 13 additions & 8 deletions docs/tutorials/snippets/aws/lambda.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import {PlatformExpress} from "@tsed/platform-express";
import {PlatformAws} from "@tsed/platform-aws";
import "@tsed/platform-express";
import {Server} from "./Server";

const awsServerlessExpress = require("aws-serverless-express");
// or import "@tsed/platform-koa";

// The function handler to setup on AWS Lambda console -- the name of this function must match the one configured on AWS
export const handler = async (event: any, context: any) => {
const platform = await PlatformExpress.bootstrap(Server);
const lambdaServer = awsServerlessExpress.createServer(platform.app.callback());
PlatformAws.bootstrap(Server, {
aws: {
binaryMimeTypes: [ // optional
// mime types list
]
},
// additional Ts.ED options. See https://tsed.io/tutorials/aws.html
});

return awsServerlessExpress.proxy(lambdaServer, event, context, "PROMISE").promise;
};
// Handler used by AWS
export const handler = PlatformAws.callback();
2 changes: 1 addition & 1 deletion examples/aws/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"@tsed/json-mapper": "6.0.0-beta.2",
"@tsed/swagger": "6.0.0-beta.2",
"@tsed/platform-express": "6.0.0-beta.2",
"aws-serverless-express": "3.3.6",
"@tsed/platform-aws": "6.0.0-beta.2",
"body-parser": "1.19.0",
"compression": "1.7.4",
"concurrently": "5.3.0",
Expand Down
40 changes: 8 additions & 32 deletions examples/aws/src/LambdaServer.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,11 @@
import {PlatformExpress} from "@tsed/platform-express";
import * as awsServerlessExpress from "aws-serverless-express";
import {PlatformAws} from "@tsed/platform-aws";
import "@tsed/platform-express";
import {Server} from "./Server";

// NOTE: If you get ERR_CONTENT_DECODING_FAILED in your browser, this is likely
// due to a compressed response (e.g. gzip) which has not been handled correctly
// by aws-serverless-express and/or API Gateway. Add the necessary MIME types to
// binaryMimeTypes below, then redeploy (`npm run package-deploy`)
const binaryMimeTypes = [
"application/javascript",
"application/json",
"application/octet-stream",
"application/xml",
"font/eot",
"font/opentype",
"font/otf",
"image/jpeg",
"image/png",
"image/svg+xml",
"text/comma-separated-values",
"text/css",
"text/html",
"text/javascript",
"text/plain",
"text/text",
"text/xml"
];
PlatformAws.bootstrap(Server, {
aws: {}
// additional Ts.ED options. See https://tsed.io/tutorials/aws.html
});

// The function handler to setup on AWS Lambda console -- the name of this function must match the one configured on AWS
export async function awsHanlder(event: any, context: any) {
const platform = await PlatformExpress.bootstrap(Server);
const lambdaServer = awsServerlessExpress.createServer(platform.app.callback(), null, binaryMimeTypes);

return awsServerlessExpress.proxy(lambdaServer, event, context, "PROMISE").promise;
}
// Handler used by AWS
export const handler = PlatformAws.callback();
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ describe("PlatformBuilder", () => {

// THEN
expect(server.rootModule).to.be.instanceof(ServerModule);
expect(server.name).to.eq("custom");
expect(server.platform.addRoutes).to.have.been.calledWithExactly([
{
route: "/rest",
Expand Down
15 changes: 13 additions & 2 deletions packages/common/src/platform-builder/builder/PlatformBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,15 @@ export interface PlatformType<T = any> extends Type<T> {
providers: IProvider[];
}

export interface PlatformBootstrap {
bootstrap(module: Type<any>, settings?: Partial<TsED.Configuration>): Promise<PlatformBuilder>;
}

/**
* @platform
*/
export abstract class PlatformBuilder {
static currentPlatform: Type<PlatformBuilder> & PlatformBootstrap;
protected startedAt = new Date();
protected PLATFORM_NAME: string = "";
protected _rootModule: any;
Expand All @@ -51,6 +56,10 @@ export abstract class PlatformBuilder {
.add(Platform);
}

get name() {
return this.PLATFORM_NAME;
}

get injector(): InjectorService {
return this._injector;
}
Expand Down Expand Up @@ -160,20 +169,22 @@ export abstract class PlatformBuilder {
}

async listen() {
const {logger, startedAt} = this;
await this.callHook("$beforeListen");

await this.listenServers();

await this.callHook("$afterListen");

await this.ready();
logger.info(`Started in ${new Date().getTime() - startedAt.getTime()} ms`);
}

public async ready() {
const {logger, startedAt} = this;

await this.callHook("$onReady");
await this.injector.emit("$onServerReady");

logger.info(`Started in ${new Date().getTime() - startedAt.getTime()} ms`);
}

callHook(key: string, ...args: any[]) {
Expand Down
11 changes: 6 additions & 5 deletions packages/di/src/services/DIConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,20 +85,21 @@ export class DIConfiguration {
/**
*
* @param propertyKey
* @param defaultValue
* @returns {undefined|any}
*/
get<T = any>(propertyKey: string): T {
return this.resolve(this.getRaw(propertyKey));
get<T = any>(propertyKey: string, defaultValue?: T): T {
return this.resolve(this.getRaw(propertyKey, defaultValue));
}

getRaw(propertyKey: string): any {
getRaw(propertyKey: string, defaultValue?: any): any {
const value = getValue(propertyKey, this.map);

if (value !== undefined) {
return value;
}

return getValue(propertyKey, this.default);
return getValue(propertyKey, this.default, defaultValue);
}

merge(obj: Partial<TsED.Configuration>) {
Expand Down Expand Up @@ -149,6 +150,6 @@ export class DIConfiguration {
this.forEach((value, key) => this.map.set(key, this.resolve(value)));

this.set = this.setRaw;
this.get = this.getRaw = (propertyKey: string) => getValue(propertyKey, this.map);
this.get = this.getRaw = (propertyKey: string, defaultValue?: any) => getValue(propertyKey, this.map, defaultValue);
}
}
4 changes: 4 additions & 0 deletions packages/platform-aws/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
src
test
tsconfig.compile.json
tsconfig.json
59 changes: 59 additions & 0 deletions packages/platform-aws/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"name": "@tsed/platform-aws",
"version": "6.0.0-beta.5",
"description": "Module to support AWS function with Ts.ED",
"main": "./lib/index.js",
"typings": "./lib/index.d.ts",
"private": false,
"keywords": [
"aws",
"lambda",
"functions",
"TypeScript",
"typescript",
"Decorator",
"decorators",
"decorator",
"express",
"koa",
"Controller",
"Inject",
"ioc",
"di",
"mvc",
"swagger",
"swagger ui",
"ES2015",
"ES6",
"server",
"rest",
"api",
"validation"
],
"author": {
"name": "Romain Lenzotti"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/TypedProject/tsed/issues"
},
"homepage": "http://tsed.io/",
"repository": {
"type": "git",
"url": "git+https://github.com/TypedProject/tsed.git"
},
"scripts": {
"build": "tsc --build tsconfig.compile.json"
},
"devDependencies": {
"@types/aws-serverless-express": "3.3.3",
"@tsed/common": "6.0.0-beta.5",
"@tsed/core": "6.0.0-beta.5",
"@tsed/di": "6.0.0-beta.5",
"aws-serverless-express": "3.3.8",
"aws-serverless-koa": "1.0.1"
},
"dependencies": {
"aws-serverless-express": "^3.3.8"
}
}

0 comments on commit 6a833c5

Please sign in to comment.