An open API service indexing awesome lists of open source software.

https://github.com/davicedraz/serverless-visit-counter

Experimental Serverless Node.js Express API
https://github.com/davicedraz/serverless-visit-counter

aws-lambda clean-architecture dynamodb nodejs serverless

Last synced: 3 days ago
JSON representation

Experimental Serverless Node.js Express API

Awesome Lists containing this project

README

          

## Serverless Node Express API

This project it is being developed to apply serverless concepts using Node.js, the [Serverless](https://www.serverless.com/) framework and AWS platform (Lambda functions).

This a simples API that communicates with the free service [CountAPI](https://countapi.xyz/). This API allows you to create simple numeric counters IaaS (Integer as a Service) and increment/decrement it. This counter will be used to store the number of hits from a website.

API features:

- [x] Increase the number of accesses
- [x] Consult the number of accesses
- [x] Create a user
- [x] View a user's information
- [ ] Increment the hit counter automatically when the site is visited
- [ ] Create a new hit counter when a logged in user visits the site

### Architecture

This project takes advantage of [Services Pattern](https://www.serverless.com/blog/serverless-architecture-code-patterns), where a single Lambda function can handle a few (~4) jobs that are usually related via a data model or a shared infrastructure dependency. In our example app, all operations on the Users data model are performed in a single Lambda function, and multiple HTTP endpoints are created for all CRUD operations.

Benefits of Services Pattern:

- This will result in less Lambda functions that you need to manage.
- Some separation of concerns still exists.
- Teams can still work autonomously.
- Faster deployments.
- Theoretically better performance. When multiple jobs are within a Lambda function, there is a higher likelihood that Lambda function will be called more regularly, which means the Lambda will stay warm and users will run into less cold-starts.

Drawbacks of Services Pattern:

- Debugging gets slightly more complicated, since the Lambda function is handling multiple jobs, and has different outcomes.
- Requires creating a router to call the right logic based on the request method or endpoint.
- Bigger function sizes due to putting multiple operations within the same Lambda function.

![Architecture](https://github.com/davicedraz/serverless-visit-counter/blob/master/docs/images/SVC%20-%20v1.1.0.png?raw=true)

### Project Structure

When we consider DevOps frameworks like [serverless](https://www.serverless.com/) Framework, it expects to point each route to a separate Lambda function. But this project exposes one single function, `api`, in `serverless.yml` which is responsible for handling all incoming requests thanks to configured `http` events. To learn more about `http` event configuration options, please refer to [http event docs](https://www.serverless.com/framework/docs/providers/aws/events/apigateway/). As the events are configured in a way to accept all incoming requests, `express` framework is responsible for routing and handling requests internally. Implementation takes advantage of `serverless-http` package, which allows you to wrap existing `express` applications. To learn more about `serverless-http`, please refer to corresponding [GitHub repository](https://github.com/dougmoscrop/serverless-http). Additionally, it also handles provisioning of a DynamoDB database that is used for storing data about users. The `express` application exposes two endpoints, `POST /users` and `GET /user/{userId}`, which allow to create and retrieve users.

### Deployment

This example is made to work with the Serverless Framework dashboard, which includes advanced features such as CI/CD, monitoring, metrics, etc.

In order to deploy with dashboard, you need to first login with:

```
serverless login
```

install dependencies with:

```
npm install
```

and then perform deployment with:

```
serverless deploy
```

After running deploy, you should see output similar to:

```bash
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
........
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service aws-node-express-dynamodb-api.zip file to S3 (718.53 KB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
....................................
Serverless: Stack update finished...
Service Information
service: aws-node-express-dynamodb-api
stage: dev
region: us-east-1
stack: aws-node-express-dynamodb-api-dev
resources: 13
api keys:
None
endpoints:
ANY - https://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev/
ANY - https://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev/{proxy+}
functions:
api: aws-node-express-dynamodb-api-dev-api
layers:
None
```

### Local development

It is also possible to emulate DynamodB, API Gateway and Lambda locally by using `serverless-dynamodb-local` and `serverless-offline` plugins. In order to do that, execute the following commands:

```bash
serverless plugin install -n serverless-dynamodb-local
serverless plugin install -n serverless-offline
```

It will add both plugins to `devDependencies` in `package.json` file as well as will add it to `plugins` in `serverless.yml`. Make sure that `serverless-offline` is listed as last plugin in `plugins` section:

```
plugins:
- serverless-dynamodb-local
- serverless-offline
```

You should also add the following config to `custom` section in `serverless.yml`:

```
custom:
(...)
dynamodb:
start:
migrate: true
stages:
- dev
```

![DynamodB](https://github.com/davicedraz/serverless-visit-counter/blob/master/docs/images/local-dynamo-db.png?raw=true)

Additionally, we need to reconfigure `AWS.DynamoDB.DocumentClient` to connect to our local instance of DynamoDB. We can take advantage of `IS_OFFLINE` environment variable set by `serverless-offline` plugin and replace:

```javascript
const dynamoDbClient = new AWS.DynamoDB.DocumentClient();
```

with the following:

```javascript
const dynamoDbClientParams = {};
if (process.env.IS_OFFLINE) {
dynamoDbClientParams.region = 'localhost'
dynamoDbClientParams.endpoint = 'http://localhost:8000'
}
const dynamoDbClient = new AWS.DynamoDB.DocumentClient(dynamoDbClientParams);
```

After that, running the following command with start both local API Gateway emulator as well as local instance of emulated DynamoDB:

```bash
serverless offline start
```

To learn more about the capabilities of `serverless-offline` and `serverless-dynamodb-local`, please refer to their corresponding GitHub repositories:
- https://github.com/dherault/serverless-offline
- https://github.com/99x/serverless-dynamodb-local