Sunday, 8 March 2020
Building Serverless CRUD services in Go with DynamoDB - Part 2
In the previous post, we've created ``createHandler``. In this post, we'll create ``listHandler``.
# Getting started
First, let's add the config under ``functions`` in ``serverless.yml``
```
list:
handler: bin/handlers/listHandler
package:
include:
- ./bin/handlers/listHandler
events:
- http:
path: iam
method: get
cors: true
```
Create a file ``listHandler.go`` under src/handlers
Similarly, we have the below structure.
```
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
)
// TODO1: Define User Struct
// TODO2: Define User Response Struct
var svc *dynamodb.DynamoDB
func init() {
region := os.Getenv("AWS_REGION")
// Initialize a session
if session, err := session.NewSession(&aws.Config{
Region: ®ion,
}); err != nil {
fmt.Println(fmt.Sprintf("Failed to initialize a session to AWS: %s", err.Error()))
} else {
// Create DynamoDB client
svc = dynamodb.New(session)
}
}
func List(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
var (
tableName = aws.String(os.Getenv("IAM_TABLE_NAME"))
)
// TODO3: Add DynamoDB retrival logic
}
func main() {
lambda.Start(List)
}
```
For TODO1, this time we don't need omitempty tags because we want to retrieve every field. Ths struct would be
```
type User struct {
ID string `json:"id"`
UserName string `json:"user_name"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Age int `json:"age"`
Phone string `json:"phone"`
Password string `json:"password"`
Email string `json:"email"`
Role string `json:"role"`
IsActive bool `json:"is_active"`
CreatedAt string `json:"created_at"`
ModifiedAt string `json:"modified_at"`
DeactivatedAt string `json:"deactivated_at"`
}
```
We also need another struct for holding our user response. Let's create a new one and remove TODO2 comment.
```
type Response struct {
Response []User `json:"response"`
}
```
By doing so, our response should look like
```json
{
"response": [
{
// user record #1
},
{
// user record #2
}
// and so on
]
}
```
When I was coding the response part, one mistake I made was I accidentally added an extra space after ``json:`` like
```
type Response struct {
Response []User `json: "response"`
}
```
and I got the below result
```json
{
"Response": [
{
// user record #1
},
{
// user record #2
}
// and so on
]
}
```
If there is no json tag or the tag cannot be read, it will reflect the json field name instead.
This time we need to use ``svc`` to retrieve the users from DynamoDB. First of all, we need to build the query input parameters
```
params := &dynamodb.ScanInput{
TableName: tableName,
}
```
Make the DynamoDB Query API call
```
result, err := svc.Scan(params)
if err != nil {
fmt.Println("Query API call failed:")
fmt.Println((err.Error()))
// Status Bad Request
return events.APIGatewayProxyResponse{
Body: err.Error(),
StatusCode: 400,
}, nil
}
```
Construct users from response
```
var users []User
for _, i := range result.Items {
user := User{}
if err := dynamodbattribute.UnmarshalMap(i, &user); err != nil {
fmt.Println("Got error unmarshalling:")
fmt.Println(err.Error())
return events.APIGatewayProxyResponse{
Body: err.Error(),
StatusCode: 400,
}, nil
}
users = append(users, user)
}
```
Marshal the user response and return APIGatewayProxyResponse
```
body, _ := json.Marshal(&Response{
Response: users,
})
return events.APIGatewayProxyResponse{
Body: string(body),
StatusCode: 200,
}, nil
```
Let's deploy and test it
```
./scripts/deploy.sh
```
# Testing
If you go to AWS Lambda Console, you should see there is a function called ``serverless-iam-dynamodb-dev-get``
![image](https://user-images.githubusercontent.com/35857179/76139045-a008bc80-6087-11ea-9eea-3654773ef36c.png)
You can test your code either in Lambda or API Gateway.
Since this is a GET method, a request body is not supported. The response should look like
```json
{
"response": [
{
"id": "bd6fde14-3f6a-4551-95f3-349077a5501f",
"user_name": "wingkwong",
"first_name": null,
"last_name": null,
"age": null,
"phone": null,
"password": "$2a$14$iwyLz8DOnbcolxXezZGXG.uXN9kCxJ8aYzMFftYZ06j1Ybb4uThC2",
"email": "wingkwong@gmail.com",
"role": "user",
"is_active": true,
"created_at": "2019-12-28 13:16:41.09607401 +0000 UTC m=+0.077451001",
"modified_at": "2019-12-28 13:16:41.096188175 +0000 UTC m=+0.077565137",
"deactivated_at": null
}
]
}
```
That's it for part 2. In the next post, we'll create ``updateHandler.go``.
Subscribe to:
Post Comments (Atom)
A Fun Problem - Math
# Problem Statement JATC's math teacher always gives the class some interesting math problems so that they don't get bored. Today t...
-
SHA stands for Secure Hashing Algorithm and 2 is just a version number. SHA-2 revises the construction and the big-length of the signature f...
-
Contest Link: [https://www.e-olymp.com/en/contests/19775](https://www.e-olymp.com/en/contests/19775) Full Solution: [https://github.com/...
No comments:
Post a Comment