Create a REST API integrated with Amazon DynamoDB using AWS Amplify and Vue

Setting up a new project with the Vue CLI

Before moving to the next section, please complete the steps described in “Build your first full-stack serverless app with Vue”. Here you will set up the initial project, familiarise with Amplify CLI and add an authorisation flow so users can register themselves via an automated verification code sent to their email and login.

Creating a REST API with Amplify CLI

The Amplify CLI provides a guided workflow to easily add, develop, test and manage REST APIs to access your AWS resources from your web and mobile applications.

Architecture diagram for the Todo App

Creating a new REST API

In this post, you are going to create a REST API to service a todo app with a single endpoint /todos using Amazon DynamoDB as a data source. To create it, use the following command:

amplify add api
  • Please select from one of the below mentioned services: REST
  • Provide a friendly name for your resource to be used as a label for this category in the project: todosApi
  • Provide a path (e.g., /book/{isbn}): /todos
/                        
|_ /todos Main resource. Eg: /todos
ANY Methods: DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT
OPTIONS Allow pre-flight requests in CORS by browser
|_ /{proxy+} Eg: /todos/, /todos/id
ANY Methods: DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT
OPTIONS Allow pre-flight requests in CORS by browser
  • Choose a Lambda source Create a new Lambda function
  • Provide a friendly name for your resource to be used as a label for this category in the project: todosLambda
  • Provide the AWS Lambda function name: todosLambda
  • Choose the runtime that you want to use: NodeJS
  • Choose the function template that you want to use: CRUD function for Amazon DynamoDB
GET /todos         List all todos
GET /todos/1 Load a todo by id
POST /todos Create a todo
PUT /todos Update a todo
DELETE /todos/1 Delete a todo by id
  • Do you want to access other resources in this project from your Lambda function? No
  • Do you want to invoke this function on a recurring schedule? No
  • Do you want to configure Lambda layers for this function? No
  • Do you want to edit the local lambda function now? Yes
  • Press enter to continue
  • Restrict API access Yes
  • Who should have access? Authenticated and Guest users
  • What kind of access do you want for Authenticated users? create, read, update, delete
  • What kind of access do you want for Guest users? read
  • Do you want to add another path? No

Implementing CRUD operations with Amazon DynamoDB

In order to manage your todo app you want to implement all CRUD operations, these are: create, read, update and delete. The template we picked in the last section uses AWS Serverless Express. Amazon API Gateway will proxy incoming requests to your todosLambda.

REST API mapping between HTTP requests, AWS Serverless Express and Document Client calls.
cd /amplify/backend/function/todosLambda/src
npm i --save uuid
const AWS = require('aws-sdk')var awsServerlessExpressMiddleware = require('aws-serverless-express/middleware')
var bodyParser = require('body-parser')
var express = require('express')
const { v4: uuidv4 } = require('uuid')
AWS.config.update({ region: process.env.TABLE_REGION });
const dynamodb = new AWS.DynamoDB.DocumentClient();
let tableName = "todosTable";
if (process.env.ENV && process.env.ENV !== "NONE") {
tableName = tableName + '-' + process.env.ENV;
}
var app = express()
app.use(bodyParser.json())
app.use(awsServerlessExpressMiddleware.eventContext())
app.use(function (request, response, next) {
response.header("Access-Control-Allow-Origin", "*")
response.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
next()
});

Fetching todos (GET, /todos)

In the client, we use the Amplify JavaScript library aws-amplify to consume the REST API. In order to fetch the todos useAPI.get with the todosApi followed by the path /todos and an empty payload. The result is an array with the todos as part of the body. Remember to use JSON.parse as the result.body needs to be in plain text due to HTTP transport. The result object also contains the statusCode and path as url.

// client request: fetching todos
import { API } from 'aws-amplify';
API.get('todosApi', '/todos', {}).then(result => {
this.todos = JSON.parse(result.body);
}).catch(err => {
console.log(err);
})
// todosLambda route handler: fetching todosapp.get("/todos", function (request, response) {
let params = {
TableName: tableName,
limit: 100
}
dynamodb.scan(params, (error, result) => {
if (error) {
response.json({ statusCode: 500, error: error.message });
} else {
response.json({ statusCode: 200, url: request.url, body: JSON.stringify(result.Items) })
}
});
});

Fetching a todo by id (GET, /todos/:id)

Let’s quickly see the code necessary on the client below.

// client request: fetching a todo by idimport { API } from 'aws-amplify';API.get('todosApi', `/todos/${id}`, {}).then((result) => {
this.todo = JSON.parse(result.body);
}).catch(err => {
console.log(err);
})
// todosLambda route handler: fetching a todo by idapp.get("/todos/:id", function (request, response) {
let params = {
TableName: tableName,
Key: {
id: request.params.id
}
}
dynamodb.get(params, (error, result) => {
if (error) {
response.json({ statusCode: 500, error: error.message });
} else {
response.json({ statusCode: 200, url: request.url, body: JSON.stringify(result.Item) })
}
});
});

Creating a new todo (POST, /todos)

In order to create a new todo, use API.post and set the payload to include the new todo description text within the request body.

// client request: creating a new todoimport { API } from 'aws-amplify';API.post('todosApi', '/todos', {
body: {
text: "todo-1"
}

}).then(result => {
this.todo = JSON.parse(result.body);
}).catch(err => {
console.log(err);
})
// todosLambda route handler: creating a new todoapp.post("/todos", function (request, response) {
const timestamp = new Date().toISOString();
let params = {
TableName: tableName,
Item: {
...request.body,
id: uuidv4(), // auto-generate id
complete: false, // default for new todos
createdAt: timestamp,
updatedAt: timestamp,
userId: getUserId(request) // userId from request
}
}
dynamodb.put(params, (error, result) => {
if (error) {
response.json({ statusCode: 500, error: error.message, url: request.url });
} else {
response.json({ statusCode: 200, url: request.url, body: JSON.stringify(params.Item) })
}
});
});
// todosLambda route handler: helper functionconst getUserId = (request) => {
try {
const reqContext = request.apiGateway.event.requestContext;
const authProvider = reqContext.identity.cognitoAuthenticationProvider;
return authProvider ? authProvider.split(":CognitoSignIn:").pop() : "UNAUTH";
} catch (error) {
return "UNAUTH";
}
}

Updating a todo (PUT, /todos)

At this point you should know how to use the Amplify API. In order to update a todo use API.put and the /todos path. As you did creating a new todo provide the todo changes including its id as part of the body. As in the code below, change both the description and the complete values. The result contains any fields that were changed and their new values.

// client request: updating a todoimport { API } from 'aws-amplify';API.put('todosApi', `/todos`, { 
body: {
id: id,
text: "todo-2",
complete: true
}

}).then(result => {
this.todo = JSON.parse(result.body);
}).catch(err => {
console.log(err);
})
// todosLambda route handler: updating a todoapp.put("/todos", function (request, response) {
const timestamp = new Date().toISOString();
const params = {
TableName: tableName,
Key: {
id: request.body.id,
},
ExpressionAttributeNames: { '#text': 'text' },
ExpressionAttributeValues: {},
ReturnValues: 'UPDATED_NEW',
};
params.UpdateExpression = 'SET ';
if (request.body.text) {
params.ExpressionAttributeValues[':text'] = request.body.text;
params.UpdateExpression += '#text = :text, ';
}
if (request.body.complete) {
params.ExpressionAttributeValues[':complete'] = request.body.complete;
params.UpdateExpression += 'complete = :complete, ';
}
if (request.body.text || request.body.complete) {
params.ExpressionAttributeValues[':updatedAt'] = timestamp;
params.UpdateExpression += 'updatedAt = :updatedAt';
}
dynamodb.update(params, (error, result) => {
if (error) {
response.json({ statusCode: 500, error: error.message, url: request.url });
} else {
response.json({ statusCode: 200, url: request.url, body: JSON.stringify(result.Attributes) })
}
});
});

Deleting a todo by id (DELETE, /todos/:id)

Let’s implement the request to delete a todo. On the client, use API.del with a path including the id as a route parameter. If successful, the result body will be {} with statusCode:200.

// client request: deleting a todo by idimport { API } from 'aws-amplify';API.del('todosApi', `/todos/${id}`, {}).then(result => {
console.log(result);
}).catch(err => {
console.log(err);
})
// todosLambda route handler: deleting a todo by idapp.delete("/todos/:id", function (request, response) {
let params = {
TableName: tableName,
Key: {
id: request.params.id
}
}
dynamodb.delete(params, (error, result) => {
if (error) {
response.json({ statusCode: 500, error: error.message, url: request.url });
} else {
response.json({ statusCode: 200, url: request.url, body: JSON.stringify(result) })
}
});
});

Pushing your new REST API to the cloud

Let’s deploy the new REST API in the cloud by running this command in the root of your project:

amplify push
REST
|_ /todos (path)
|_ todosApi (Amazon API Gateway)
|_ todosLambda (AWS Lambda)
|_ Logs (Amazon CloudWatch)

Publishing your app via the AWS Amplify Console

The first thing you need to do is create a new repo for this project. Once you’ve created the repo, copy the URL for the project to the clipboard and initialise git in your local project:

git init
git remote add origin repo@repoofyourchoice.com:username/project-name.git
git add .git commit -m 'initial commit'git push origin master
AWS Amplify Console deployment steps.

Cleaning up cloud services

If at any time, you would like to delete the services from your project and your AWS Account, you can do this by running:

amplify delete

Conclusion

Congratulations! You successfully created a REST API using AWS Amplify, implemented all CRUD operations using Amazon DynamoDB and created a client to consume it restricting access to both registered users and guests using Vue. Thanks for following this tutorial.

Thanks for reading!

Have you got any questions about this tutorial or AWS Amplify? Feel free to reach me anytime at @gerardsans.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Gerard Sans

Gerard Sans

Helping Devs to succeed #AI #web3 / ex @AWSCloud / Just be AWSome / MC Speaker Trainer Community Leader @web3_london / @ReactEurope @ReactiveConf @ngcruise