-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
127 lines (109 loc) · 3.67 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package main
import (
"context"
"encoding/json"
"log"
"net/http"
"os"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue"
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
)
type foodieBuckRequest struct {
PK string `json:"pk"`
SK string `json:"sk"`
TableName string `json:"tableName"`
}
// FoodieBuckProfile should have all pk USER# sk PROFILE#
// that would be expected to return from the DDB Table
// aws-sdk-go-v2 requires the struct to use dynamodbav type
type FoodieBuckProfile struct {
PK string `dynamodbav:"pk"`
SK string `dynamodbav:"sk"`
Name string `dynamodbav:"displayName"`
Available int `dynamodbav:"foodieBucksAvailable"`
Used int `dynamodbav:"foodieBucksUsed"`
Increment int `dynamodbav:"foodieBuckIncrement"`
}
var tableName = "dev.glennmeyer.dev-foodiebucks"
var errorLogger = log.New(os.Stderr, "ERROR ", log.Llongfile)
// Helper function to convert API Body to JSON Request
func unmarshalAPIRequest(r events.APIGatewayV2HTTPRequest) (foodieBuckRequest, error) {
fbr := foodieBuckRequest{}
err := json.Unmarshal([]byte(r.Body), &fbr)
return fbr, err
}
// Helper function to return custom error response
func clientError(sc int) (events.APIGatewayV2HTTPResponse, error) {
return events.APIGatewayV2HTTPResponse{
StatusCode: sc,
Body: http.StatusText(sc),
}, nil
}
// Helpers for error handling; logs to os.Stderr
func serverError(err error) (events.APIGatewayV2HTTPResponse, error) {
errorLogger.Println(err.Error())
return events.APIGatewayV2HTTPResponse{
StatusCode: http.StatusInternalServerError,
Body: http.StatusText(http.StatusInternalServerError),
}, nil
}
// We can only pass one func to Lambda, so we switch on METHOD
func router(r events.APIGatewayV2HTTPRequest) (events.APIGatewayV2HTTPResponse, error) {
fbr, err := unmarshalAPIRequest(r)
if err != nil {
clientError(http.StatusUnprocessableEntity)
}
switch r.RequestContext.HTTP.Method {
case "GET":
return getProfile(fbr)
default:
return clientError(http.StatusMethodNotAllowed)
}
}
// GetProfile queries DDB and returns marshalled response
func getProfile(r foodieBuckRequest) (events.APIGatewayV2HTTPResponse, error) {
// Using the SDK's default configuration, loading additional config
// and credentials values from the environment variables, shared
// credentials, and shared configuration files
cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion("us-east-2"))
if err != nil {
log.Fatalf("unable to load SDK config, %v", err)
}
// Using the Config value, create the DynamoDB client
svc := dynamodb.NewFromConfig(cfg)
// Build the request with its input parameters
data, err := svc.GetItem(context.TODO(), &dynamodb.GetItemInput{
Key: map[string]types.AttributeValue{
"pk": &types.AttributeValueMemberS{Value: r.PK},
"sk": &types.AttributeValueMemberS{Value: r.SK},
},
TableName: aws.String(tableName),
})
if err != nil {
log.Fatalf("failed to get item, %v", err)
}
// Write response data to AttributeValue map and unmarshal
p := FoodieBuckProfile{}
err = attributevalue.UnmarshalMap(data.Item, &p)
if err != nil {
log.Printf("Couldn't unmarshal response. Here's why: %v\n", err)
}
// Marshal profile back into JSON
json, err := json.Marshal(p)
if err != nil {
return serverError(err)
}
// Return response data as proper type
return events.APIGatewayV2HTTPResponse{
StatusCode: http.StatusOK,
Body: string(json),
}, nil
}
func main() {
lambda.Start(router)
}