DEPLOY MỘT REST API SỬ DỤNG SERVERLESS, EXPRESS VÀ NODE.JS
Bài đăng này đã không được cập nhật trong 5 năm
MỞ ĐẦU
- Lý do bạn tìm hiểu serverless là gì?
- Vì nghe nó nổi có nhiều công ty lớn sử dụng nên tìm hiểu?
- Vì nó là sản phẩm của AWS?
- Hay lý do nào khác?
- Cá nhân mình thì do muốn làm quen với các dịch vụ cloud của AWS, và trong project hiện tại có sử dụng Lambda function. Nên mình chọn serverless để bắt đầu luôn .
- Các phần dưới đây sẽ trình bày về cách deploy một API lên AWS sử dụng serverless, express và Nodejs.
OK LET GO!!!
DEPLOY REST API
Cài đặt serverless Framework
-
Trước khi bắt đầu chúng ta cần cài đặt môi trường đã:
-
Nếu bạn gặp khó khăn trong việc cài
serverless CLI
khi cónvm
hãy thử gỡ bỏnvm
xem sao.
Create API
-
Tạo thư mục với file
package.json
.mkdir my-first-serverless && cd my-first-serverless npm init -f
-
Cài đặt các gói phụ thuộc cần thiết:
npm install --save express serverless-http
-
Để khởi tạo một REST API ngoài sử dụng
Express
chúng ta sẽ sử dụng thêmserverless-http
như một middleware giao tiếp giữa NodeJS và API Gateway của AWS. -
Implement code file
index.js
như dưới:// index.js const serverless = require('serverless-http'); const express = require('express') const app = express() app.get('/', function (req, res) { res.send('Hello World!') }) module.exports.handler = serverless(app);
Config Serverless
-
Trong cùng thư mục với hai file
index.js
vàpackage.json
ở trên chúng ta tạo fileserverless.yml
với nội dung:# serverless.yml service: my-first-serverless provider: name: aws runtime: nodejs6.10 stage: dev region: us-east-1 functions: app: handler: index.handler events: - http: ANY / - http: 'ANY {proxy+}'
-
Nói qua một chút:
- my-first-serverless: là tên service.
- Khai báo một function
app
của serverless. app
sử dụng function handler trong fileindex.js
như là một handler của mình:handler: index.handler
để xử lý các sự kiện(events
):http
Deploy
-
Dùng lệnh:
serverless deploy
hoặc ngắn gọn hơnsls deploy
. Thêm-v
(verbose) nếu bạn muốn xem chi tiết tất cả các tiến trình.my-first-serverless$ sls deploy ... endpoints: ANY - https://8gagnsxxnl.execute-api.us-east-1.amazonaws.com/dev ANY - https://8gagnsxxnl.execute-api.us-east-1.amazonaws.com/dev/{proxy+} functions: app: my-first-serverless-dev-app layers: None
-
Nếu code của bạn sai, deploy có thể vẫn trả về một public link, nhưng truy cập có thể trả về message internal server error. Hãy dùng
sls logs
để xem log của các function. -
Thử truy cập chúng ta thấy server đã hoạt động:
-
Dùng serverless deploy một API chỉ đơn giản vậy thôi! Ngoài ra:
- Trong file
serverless.yml
có thể khai báo nhiều function thay vì chỉ có một functionapp
như trong demo phía trên. - Function
app
đang xử lý các request đến server. Tuy nhiên có thể làm hoàn toàn ngược lại đó là dùng function để call tới một API khác. Lúc này function có thể đóng vai trò như một trigger.
- Trong file
-
Hiện tại API chưa có gì. Phần tiếp theo chúng ta sẽ cùng thử thêm DynamoDB như nơi lưu trữ dữ liệu cho API.
THÊM DYNAMODB CHO REST-API
Cập nhật cấu hình serverless
-
Cùng thay đổi cấu hình một chút như dưới:
# serverless.yml service: my-first-serverless custom: tableName: 'users-table-${self:provider.stage}' provider: name: aws runtime: nodejs6.10 stage: dev region: us-east-1 iamRoleStatements: - Effect: Allow Action: - dynamodb:Query - dynamodb:Scan - dynamodb:GetItem - dynamodb:PutItem - dynamodb:UpdateItem - dynamodb:DeleteItem Resource: - { "Fn::GetAtt": ["UsersDynamoDBTable", "Arn" ] } environment: USERS_TABLE: ${self:custom.tableName} functions: app: handler: index.handler events: - http: ANY / - http: 'ANY {proxy+}' resources: Resources: UsersDynamoDBTable: Type: 'AWS::DynamoDB::Table' Properties: AttributeDefinitions: - AttributeName: userId AttributeType: S KeySchema: - AttributeName: userId KeyType: HASH ProvisionedThroughput: ReadCapacityUnits: 1 WriteCapacityUnits: 1 TableName: ${self:custom.tableName}
-
Cấu hình trên chúng ta sẽ có:
- Do
provider.stage: dev
nêncustomer.tableName
sẽ là:users-table-dev
. - Cung cấp cho function một
table
trong phầnresource
sử dụng cú pháp CloudFormation. - Thêm phân quyền IAM trong phần
iamRoleStatements
.
- Do
Cập nhật code
-
Để app sử dụng table đã thêm ở trên. Chúng ta sẽ thêm 2 phương thức: POST và GET cho phép người dùng tạo: user và lấy thông tin user.
-
Đầu tiên cài đặt
aws-sdk
vàbody-parser
:npm install --save aws-sdk body-parser
-
Cập nhật lại code:
// index.js const serverless = require('serverless-http'); const bodyParser = require('body-parser'); const express = require('express') const app = express() const AWS = require('aws-sdk'); const USERS_TABLE = process.env.USERS_TABLE; const dynamoDb = new AWS.DynamoDB.DocumentClient(); app.use(bodyParser.json({ strict: false })); app.get('/', function (req, res) { res.send('Hello World!') }) // Get User endpoint app.get('/users/:userId', function (req, res) { const params = { TableName: USERS_TABLE, Key: { userId: req.params.userId, }, } dynamoDb.get(params, (error, result) => { if (error) { console.log(error); res.status(400).json({ error: 'Could not get user' }); } if (result.Item) { const {userId, name} = result.Item; res.json({ userId, name }); } else { res.status(404).json({ error: "User not found" }); } }); }) // Create User endpoint app.post('/users', function (req, res) { const { userId, name } = req.body; if (typeof userId !== 'string') { res.status(400).json({ error: '"userId" must be a string' }); } else if (typeof name !== 'string') { res.status(400).json({ error: '"name" must be a string' }); } const params = { TableName: USERS_TABLE, Item: { userId: userId, name: name, }, }; dynamoDb.put(params, (error) => { if (error) { console.log(error); res.status(400).json({ error: 'Could not create user' }); } res.json({ userId, name }); }); }) module.exports.handler = serverless(app);
Deploy
-
Deploy để cập nhật lại cấu hình và code:
sls deploy
-
Sau khi có public link chúng ta thử tạo user:
$ curl -H "Content-Type: application/json" -X POST https://8gagnsxxnl.execute-api.us-east-1.amazonaws.com/dev/users -d '{"userId": "FRAMGIA", "name": "SUN*"}'
-
Trước khi deploy hãy chắc chắn bạn đã save code nếu không sẽ nhận được kết quả:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Error</title> </head> <body> <pre>Cannot POST /dev/users</pre> </body> </html>
-
Sau khi save code deploy chúng ta đã có thể thêm mới user:
$ curl -H "Content-Type: application/json" -X POST https://8gagnsxxnl.execute-api.us-east-1.amazonaws.com/dev/users -d '{"userId": "FRAMGIA", "name": "SUN*"}' {"userId":"FRAMGIA","name":"SUN*"}
-
Thử GET lại thông tin user đã add.
May quá GET được:
$curl -H "Content-Type: application/json" -X GET https://8gagnsxxnl.execute-api.us-east-1.amazonaws.com/dev/users/FRAMGIA {"userId":"FRAMGIA","name":"SUN*"}
Path specific routing
-
API đã được deploy sử dụng serverless framework. Tuy nhiên nhìn lại có thể thấy chúng ta đang forward tất cả traffic và để Express xử lý toàn bộ các request này. Hãy sử dụng lợi thế của kiến trúc serverless bằng cách chia các route được handle bởi các Lambda function khác nhau, và khi đó bạn có thể biết:
- Mỗi route đã được gọi bao nhiêu lần.
- Có bao nhiêu lỗi đã xảy ra cho mỗi route.
- Mỗi route mất bao lâu để có response(và bạn sẽ tiết kiệm được bao nhiêu tiền nếu tối ưu route đó có thời gian phản hồi nhanh hơn).
-
Cấu hình có dạng như dưới:
# serverless.yml functions: app: handler: index.handler events: - http: ANY / - http: 'ANY {proxy+}' getUser: handler: index.handler events: - http: 'GET /users/{proxy+}' createUser: handler: index.handler events: - http: 'POST /users'
Options
- Để hiểu kĩ hơn về serverless bạn nên tìm hiểu qua một lượt User Guide
- Để cấu hình serverless linh hoạt hơn, bạn nên xem kĩ các cách sử dụng
variable
của serverless. Một số cách sử dụng nên ưu tiên xem trước:- Environment variables.
- CLI options
- External YAML/JSON files
- CloudFormation stack outputs
- Properties exported from Javascript files (sync or async)
Billing
-
Lưu ý đoạn sau
While in the AWS Free Tier, you can build an entire application on AWS Lambda, AWS API Gateway, and more, without getting charged for 1 year... As long as you don't exceed the resources in the free tier, of course.
-
Bạn sẽ được dùng miễn phí một năm miễn sao không sử dụng tài nguyên vượt ngưỡng. Còn nếu vượt ngưỡng sẽ ra sao thì không nói ^^. Và cái account của bạn chắc chắn có link tới một thẻ có thể bị trừ tiền. Vậy nên hãy lưu tâm đến vấn đề này.
-
Việc đầu tiên sau khi test thử dịch vụ đã ok mà không cần duy trì hãy
remove
ứng dụng bạn đã vừa deploy với lệnh:sls remove
-
Nếu bạn muốn để ứng dụng public để test. AWS có mục liên quan billing mục này sẽ cho bạn biết đang sử dụng tài nguyên hết bao nhiêu % của mức free .
-
Hết! Cảm ơn bạn đã theo dõi tới phần này!
All rights reserved