mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 17:02:49 +03:00
add golang examples for aws lambda (#602)
This commit is contained in:
parent
963d86464f
commit
e2817b1b1b
@ -0,0 +1,37 @@
|
||||
# Go Echo Example for AWS Lambda
|
||||
|
||||
### Setup tables
|
||||
1. Create table:
|
||||
|
||||
```
|
||||
notes:
|
||||
id: Integer (auto-increment)
|
||||
note: Text
|
||||
|
||||
Primary key: id
|
||||
```
|
||||
|
||||
### Setup AWS Lambda
|
||||
Create a Lambda function in AWS. This will be our webhook.
|
||||
|
||||
1. Sign in to the AWS Management Console and open the AWS Lambda console.
|
||||
2. Choose "Create a function" under the **Get Started** section.
|
||||
3. Select "Author from scratch".
|
||||
4. Specify the **Name** for your lambda.
|
||||
5. Select go 1.x as the **Runtime**.
|
||||
6. In **Role** choose **Create new role from template(s)**
|
||||
7. In **Role name**, enter a name for your role, leave the **Policy Templates** field blank.
|
||||
8. Build and upload the code to AWS Lambda:
|
||||
|
||||
i. Run the bash script provided
|
||||
|
||||
`bash build.sh`
|
||||
|
||||
ii. Upload *echo.zip* in the lambda console.
|
||||
10. Click the **save** button for the changes to take effect.
|
||||
11. Create an API with a lambda proxy integration as specified in the [AWS Documentation](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html#api-gateway-create-api-as-simple-proxy-for-lambda-build).
|
||||
|
||||
### Add the trigger in Hasura GraphQL
|
||||
1. In events tab, add a trigger
|
||||
2. Select all insert, update, delete operations for the trigger.
|
||||
3. Paste the API endpoint of your AWS lambda as the webhook.
|
@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Fetching dependencies"
|
||||
|
||||
go get .
|
||||
|
||||
echo "Building binary"
|
||||
|
||||
env GOOS=linux GOARCH=amd64 go build
|
||||
|
||||
echo "Binary build complete. Zipping output."
|
||||
|
||||
zip -j ./mutation.zip mutation
|
||||
|
||||
echo "Zip complete. You can now upload the zip file"
|
@ -0,0 +1,83 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/aws/aws-lambda-go/events"
|
||||
"github.com/aws/aws-lambda-go/lambda"
|
||||
)
|
||||
|
||||
type TableStruct struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type EventData struct {
|
||||
Old map[string]interface{} `json:"old"`
|
||||
New map[string]interface{} `json"new"`
|
||||
}
|
||||
|
||||
type EventStruct struct {
|
||||
Operation string `json:"op"`
|
||||
Data EventData `json:"data"`
|
||||
}
|
||||
|
||||
type HasuraEvent struct {
|
||||
Table *TableStruct `json:"table"`
|
||||
Event *EventStruct `json:"event"`
|
||||
Op string `json:"op"`
|
||||
}
|
||||
|
||||
// Handler for the Lambda function to echo back the data
|
||||
func Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
|
||||
|
||||
// stdout and stderr are sent to AWS CloudWatch Logs
|
||||
log.Printf("Processing Lambda request %+v\n", request.Body)
|
||||
|
||||
// parse json body
|
||||
body := &HasuraEvent{
|
||||
Table: &TableStruct{},
|
||||
Event: &EventStruct{},
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(request.Body), body)
|
||||
|
||||
if err != nil {
|
||||
message := map[string]string{
|
||||
"message": "Unable to parse Hasura Event",
|
||||
}
|
||||
|
||||
responseBody, _ := json.Marshal(message)
|
||||
|
||||
return events.APIGatewayProxyResponse{
|
||||
Body: string(responseBody),
|
||||
StatusCode: 400,
|
||||
}, nil
|
||||
}
|
||||
|
||||
var message = "cannot process request"
|
||||
var data = body.Event.Data
|
||||
|
||||
if body.Table.Name == "notes" {
|
||||
switch body.Event.Operation {
|
||||
case "INSERT":
|
||||
message = fmt.Sprintf("New note %v inserted, with data: %v", data.New["id"], data.New["note"])
|
||||
case "UPDATE":
|
||||
message = fmt.Sprintf("New note %v updated, with data: %v", data.New["id"], data.New["note"])
|
||||
case "DELETE":
|
||||
message = fmt.Sprintf("New note %v delete, with data: %v", data.Old["id"], data.Old["note"])
|
||||
}
|
||||
}
|
||||
|
||||
resposeBody, _ := json.Marshal(message)
|
||||
|
||||
return events.APIGatewayProxyResponse{
|
||||
Body: string(resposeBody),
|
||||
StatusCode: 200,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
lambda.Start(Handler)
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
# Golang Mutation Example for AWS Lambda
|
||||
|
||||
This example trigger updates (executes a mutation) when an event occurs on
|
||||
another table, written in Golang.
|
||||
|
||||
### Create tables
|
||||
|
||||
```
|
||||
Table name: note
|
||||
|
||||
Columns:
|
||||
|
||||
id Integer auto-increment
|
||||
note Text
|
||||
|
||||
Primary key: id
|
||||
```
|
||||
|
||||
```
|
||||
Table name: note_revision
|
||||
|
||||
Columns:
|
||||
|
||||
id Integer auto-increment
|
||||
note Text
|
||||
note_id Integer
|
||||
update_at Timestamp, default: now()
|
||||
|
||||
Primary key: id
|
||||
```
|
||||
|
||||
### Setup AWS Lambda
|
||||
Create a Lambda function in AWS. This will be our webhook.
|
||||
|
||||
1. Sign in to the AWS Management Console and open the AWS Lambda console.
|
||||
2. Choose "Create a function" under the **Get Started** section.
|
||||
3. Select "Author from scratch".
|
||||
4. Specify the **Name** for your lambda.
|
||||
5. Select go 1.x as the **Runtime**.
|
||||
6. In **Role** choose **Create new role from template(s)**
|
||||
7. In **Role name**, enter a name for your role, leave the **Policy Templates** field blank.
|
||||
8. Build and upload the code to AWS Lambda:
|
||||
|
||||
i. Run the bash script provided
|
||||
|
||||
`bash build.sh`
|
||||
|
||||
ii. Upload *mutation.zip* in the lambda console.
|
||||
9. In the Designer pane, add an environment variable `HGE_ENDPOINT` which is the Hasura GraphQL Engine endpoint.
|
||||
10. Click the **save** button for the changes to take effect.
|
||||
11. Create an API with a lambda proxy integration as specified in the [AWS Documentation](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html#api-gateway-create-api-as-simple-proxy-for-lambda-build).
|
||||
|
||||
### Add the trigger in Hasura GraphQL
|
||||
1. In events tab, add a trigger
|
||||
2. Select all insert, update, delete operations for the trigger.
|
||||
3. Paste the API endpoint of your AWS lambda as the webhook.
|
||||
|
||||
### Test the trigger
|
||||
|
||||
Goto `Data` tab on Hasura console, browse to `note` table and to the Browse rows
|
||||
tab. Edit an existing note and check if the `note_revision` entry has been
|
||||
created. Also, checkout the trigger request and response.
|
||||
|
||||
Trigger payload (request):
|
||||
```json
|
||||
{
|
||||
"event": {
|
||||
"op": "UPDATE",
|
||||
"data": {
|
||||
"old": {
|
||||
"note": "note1",
|
||||
"id": 1
|
||||
},
|
||||
"new": {
|
||||
"note": "note1 updated",
|
||||
"id": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"created_at": "2018-10-02T06:38:22.67311Z",
|
||||
"id": "f57a1c79-72ba-4c19-8791-37d1b9616bcf",
|
||||
"trigger": {
|
||||
"name": "note_revision_trigger",
|
||||
"id": "5d85cbd1-c134-45ce-810c-7ecd3b4fc1ee"
|
||||
},
|
||||
"table": {
|
||||
"schema": "public",
|
||||
"name": "note"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Webhook response:
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"insert_note_revision": {
|
||||
"affected_rows": 1,
|
||||
"returning": [
|
||||
{
|
||||
"id": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Fetching dependencies"
|
||||
|
||||
go get .
|
||||
|
||||
echo "Building binary"
|
||||
|
||||
env GOOS=linux GOARCH=amd64 go build
|
||||
|
||||
echo "Binary build complete. Zipping output."
|
||||
|
||||
zip -j ./mutation.zip mutation
|
||||
|
||||
echo "Zip complete. You can now upload the zip file"
|
@ -0,0 +1,155 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/aws/aws-lambda-go/events"
|
||||
"github.com/aws/aws-lambda-go/lambda"
|
||||
)
|
||||
|
||||
type HasuraEvent struct {
|
||||
ID string `json:"id"`
|
||||
Event `json:"event"`
|
||||
Table `json:"table"`
|
||||
Trigger `json:"trigger"`
|
||||
}
|
||||
|
||||
type Event struct {
|
||||
Op string `json:"op"`
|
||||
Data `json:"data"`
|
||||
}
|
||||
|
||||
type Data struct {
|
||||
Old map[string]interface{} `json:"old "`
|
||||
New map[string]interface{} `json:"new"`
|
||||
}
|
||||
|
||||
type Table struct {
|
||||
Name string `json:"name"`
|
||||
Schema string `json:"schema"`
|
||||
}
|
||||
|
||||
type Trigger struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
const MUTATION_UPDATE_NOTE_REVISION = `
|
||||
mutation updateNoteRevision ($object: note_revision_insert_input!) {
|
||||
insert_note_revision (objects: [$object]) {
|
||||
affected_rows
|
||||
returning {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
func constructErrorResponse(responsePayload map[string]string) (events.APIGatewayProxyResponse, error) {
|
||||
var responseBody []byte
|
||||
|
||||
responseBody, err := json.Marshal(responsePayload)
|
||||
var statusCode int = 200
|
||||
|
||||
if err != nil {
|
||||
responseBody, _ = json.Marshal(map[string]string{
|
||||
"message": "Internal error ocurred while constructing error response",
|
||||
})
|
||||
statusCode = 500
|
||||
}
|
||||
|
||||
return events.APIGatewayProxyResponse{
|
||||
Body: string(responseBody),
|
||||
StatusCode: statusCode,
|
||||
}, nil
|
||||
}
|
||||
|
||||
var HGE_ENDPOINT = os.Getenv("HGE_ENDPOINT")
|
||||
|
||||
// Handler for the Lambda function to echo back the data
|
||||
func Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
|
||||
// stdout and stderr are sent to AWS CloudWatch Logs
|
||||
log.Printf("Processing Lambda request %+v\n", request.Body)
|
||||
|
||||
if len(HGE_ENDPOINT) == 0 {
|
||||
return constructErrorResponse(map[string]string{
|
||||
"message": "HGE Endpoint not defined in environment variable",
|
||||
})
|
||||
}
|
||||
|
||||
// parse json body
|
||||
var body HasuraEvent
|
||||
|
||||
err := json.Unmarshal([]byte(request.Body), body)
|
||||
|
||||
event := body.Event
|
||||
|
||||
if err != nil {
|
||||
return constructErrorResponse(map[string]string{
|
||||
"message": "Unable to parse Hasura Event",
|
||||
})
|
||||
}
|
||||
|
||||
note_id, ok := event.Data.Old["id"]
|
||||
if !ok {
|
||||
return constructErrorResponse(map[string]string{
|
||||
"message": "invalid payload: note id not found",
|
||||
})
|
||||
}
|
||||
note, ok := event.Data.New["note"]
|
||||
if !ok {
|
||||
return constructErrorResponse(map[string]string{
|
||||
"message": "invalid payload: note not found",
|
||||
})
|
||||
}
|
||||
|
||||
// execute the mutation
|
||||
payload := map[string]interface{}{
|
||||
"query": MUTATION_UPDATE_NOTE_REVISION,
|
||||
"variables": map[string]interface{}{
|
||||
"object": map[string]interface{}{
|
||||
"note_id": note_id.(float64),
|
||||
"note": note.(string),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
json.NewEncoder(b).Encode(payload)
|
||||
res, err := http.Post(HGE_ENDPOINT, "application/json; charset=utf-8", b)
|
||||
if err != nil {
|
||||
return constructErrorResponse(map[string]string{
|
||||
"message": err.Error(),
|
||||
})
|
||||
}
|
||||
defer res.Body.Close()
|
||||
var response map[string]interface{}
|
||||
|
||||
err = json.NewDecoder(res.Body).Decode(&response)
|
||||
if err != nil {
|
||||
return constructErrorResponse(map[string]string{
|
||||
"message": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
responseBody, err := json.Marshal(response)
|
||||
|
||||
if err != nil {
|
||||
return constructErrorResponse(map[string]string{
|
||||
"message": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
return events.APIGatewayProxyResponse{
|
||||
Body: string(responseBody),
|
||||
StatusCode: 200,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
lambda.Start(Handler)
|
||||
}
|
Loading…
Reference in New Issue
Block a user