Reputation: 1
I am using a serverless lambda datasource for an AppSync API
I tried the following code in my lambda function
package main
import (
"context"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"log"
)
func main() {
lambda.Start(Handler)
}
// Handler is your serverless lambda function
func Handler(ctx context.Context, event events.AppSyncResolverTemplate) error {
log.Println(ctx)
log.Println(event)
return nil
}
When I made a query to the API, the context was logged correctly, but the event was logged as
{ []}
I tried changing the lambda code to use an event that is an empty interface
package main
import (
"context"
"github.com/aws/aws-lambda-go/lambda"
"log"
)
func main() {
lambda.Start(Handler)
}
// Handler is your serverless lambda function
func Handler(ctx context.Context, event interface{}) error {
log.Println(ctx)
log.Println(event)
return nil
}
Querying the API now I can see that there is a map in the logs
map[field:getPerson arguments:map[personId:1]]
My question is what is the valid type that should be used in the handler signature to capture the AppSync event?
Upvotes: 0
Views: 1180
Reputation: 31
If you are using the new Direct Lambda Resolver introduced in August 2020 (https://aws.amazon.com/blogs/mobile/appsync-direct-lambda/) then there is no way to find the event type on the Appsync in the current Golang AWS SDK until today.
They only have AppSyncResolverTemplate, AppSyncIAMIdentity & AppSyncCognitoIdentity struct(https://github.com/aws/aws-lambda-go/blob/v1.16.0/events/appsync.go) so you must decode yourself the incoming request if you are going to use a direct lambda resolver.
The reason they haven't done it so far is because until now you could design your own schema using the Template Resolver (inside appsync) but now that Direct Lambda feature is out I think they must create a new AppSync event type for this.
Until then I am sharing with you the code I wrote extracting the whole event piece by piece for that purpose hoping to save some time for the next person who will be in in my situation.
***You will notice that there is no error handling here just the code needed to decode AWS Event coming from AppSync ;-)
package main
import (
"fmt"
"context"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-lambda-go/lambdacontext"
"log"
"encoding/json"
"bytes"
)
type Event struct {
Arguments map[string]string `json:"arguments"`
Identity string `json:"identity"`
Info struct {
FieldName string `json:"fieldName"`
ParentTypeName string `json:"parentTypeName"`
SelectionSetGraphQL string `json:"selectionSetGraphQL"`
SelectionSetList []string `json:"selectionSetList"`
Variables map[string]string `json:"variables"`
}
Prev string `json:"prev"`
Request struct {
Headers struct {
Accept string `json:"accept"`
AcceptEncoding string `json:"accept-encoding"`
AcceptLanguage string `json:"accept-language"`
CloudfrontForwardedProto string `json:"cloudfront-forwarded-proto"`
CloudfrontIsDesktopViewer string `json:"cloudfront-is-desktop-viewer"`
CloudfrontIsMobileViewer string `json:"cloudfront-is-mobile-viewer"`
CloudfrontIsSmarttvViewer string `json:"cloudfront-is-smarttv-viewer"`
CloudfrontViewerCountry string `json:"cloudfront-viewer-country"`
CloudfrontIsTabletViewer string `json:"cloudfront-is-tablet-viewer"`
ContentLength string `json:"content-length"`
ContentType string `json:"content-type"`
Host string `json:"host"`
Hrigin string `json:"origin"`
Referer string `json:"Referer"`
SecFetchDest string `json:"sec-fetch-dest"`
SecFetchMode string `json:"sec-fetch-mode"`
SecFetchSite string `json:"sec-fetch-site"`
UserAgent string `json:"user-agent"`
Via string `json:"via"`
XAmzCfID string `json:"x-amz-cf-id"`
XAmzUserAgent string `json:"x-amz-user-agent"`
XAmznTraceID string `json:"x-amzn-trace-id"`
XApiKey string `json:"x-api-key"`
XForwardedFor string `json:"x-forwarded-for"`
XForwardedPort string `json:"x-forwarded-port"`
XForwardedProto string `json:"x-forwarded-proto"`
}
}
Source string `json:"source"`
Stash map[string]string `json:"stash"`
}
func main() {
lambda.Start(HandleLambdaEvent)
}
func HandleLambdaEvent(ctx context.Context, event interface{}) error {
fmt.Printf("---------------{LAMBDA ctx Start}---------------\n")
// Event context
lc, _ := lambdacontext.FromContext(ctx)
//fmt.Println("Context:",ctx)
fmt.Println("AwsRequestID:",lc.AwsRequestID)
fmt.Println("Identity:",lc.Identity)
fmt.Println("InvokedFunctionArn:",lc.InvokedFunctionArn)
fmt.Println("ClientContext:",lc.ClientContext)
fmt.Println("ClientContext.Client:",lc.ClientContext.Client)
fmt.Println("CognitoIdentityID:",lc.Identity.CognitoIdentityID)
fmt.Println("CognitoIdentityPoolID:",lc.Identity.CognitoIdentityPoolID)
deadline, _ := ctx.Deadline()
fmt.Println("ContextDeadline:",deadline)
fmt.Printf("---------------{LAMBDA AWS Event Start}---------------\n")
log.Println(event)
fmt.Printf("---------------{Marshal Event Start}---------------\n")
//eventJsonm, _ := json.Marshal(event)
eventJsonm, _ := json.MarshalIndent(event, "", " ")
log.Printf("EVENT Marsal: %s", eventJsonm)
fmt.Printf("---------------{Decode Start}---------------\n")
var Event Event
r := bytes.NewReader([]byte(eventJsonm))
json.NewDecoder(r).Decode(&Event)
fmt.Println("Arguments:",Event.Arguments)
fmt.Println("Identity:",Event.Identity)
fmt.Println("Info.FieldName:",Event.Info.FieldName)
fmt.Println("Info.ParentTypeName:",Event.Info.ParentTypeName)
fmt.Println("Info.SelectionSetGraphQL:",Event.Info.SelectionSetGraphQL)
fmt.Println("Info.SelectionSetList:",Event.Info.SelectionSetList)
fmt.Println("Info.Variables:",Event.Info.Variables)
fmt.Println("Prev:",Event.Prev)
// fmt.Println("Event.Request.Headers:",Event.Request.Headers)
// fmt.Println("Event.Request.Headers.Accept:",Event.Request.Headers.Accept)
// fmt.Println("Event.Request.Headers.AcceptEncoding:",Event.Request.Headers.AcceptEncoding)
// fmt.Println("Event.Request.Headers.AcceptLanguage:",Event.Request.Headers.AcceptLanguage)
// ...
fmt.Println("Source:",Event.Source)
fmt.Println("Stash:",Event.Stash)
return nil
}
Enjoy ;-)
Upvotes: 3
Reputation: 1
I have solved this now.
It turns out that the shape of data passed into a serverless lambda datasource is user defined.
In the SamTemplate I looked at the resolver for this query and it looked like
getPersonQueryResolver:
Type: "AWS::AppSync::Resolver"
Properties:
ApiId: !GetAtt accountApi.ApiId
TypeName: "Query"
FieldName: "getPerson"
DataSourceName: !GetAtt PersonDatasource.Name
RequestMappingTemplate: |
{
"version" : "2017-02-28",
"operation": "Invoke",
"payload": {
"field": "getPerson",
"arguments": $utils.toJson($context.args)
}
}
ResponseMappingTemplate: |
$utils.toJson($context.result)
I changed this resolver to
getPersonQueryResolver:
Type: "AWS::AppSync::Resolver"
Properties:
ApiId: !GetAtt accountApi.ApiId
TypeName: "Query"
FieldName: "getPerson"
DataSourceName: !GetAtt PersonDatasource.Name
RequestMappingTemplate: |
{
"version" : "2017-02-28",
"operation": "Invoke",
"payload": $utils.toJson($context.args)
}
ResponseMappingTemplate: |
$utils.toJson($context.result)
and then I changed the lambda code to
package main
import (
"context"
"log"
"github.com/aws/aws-lambda-go/lambda"
)
type GetPerson struct {
PersonID string `json:"personId"`
}
func main() {
lambda.Start(Handler)
}
// Handler is your serverless lambda function
func Handler(ctx context.Context, event GetPerson) error {
log.Println(ctx)
log.Println(event)
return nil
}
This successfully marshalled the event and logged it as {1}
Upvotes: 0
Reputation: 366
I don't believe that the events.AppSyncResolverTemplate
is the proper value that should exist in an events object passed to the Datasource.
I may be wrong but I believe what you are seeing in the logs where the events is printed is your context.info which shows your query and the arguments you are passing.
query {
getPerson(personId: "1")
}
This can be used for various reasons within the lambda.
Can you provide more information in what you mean by the AppSync event you want to capture?
What do you expect to see in that event?
Upvotes: 0