AWS Lambda golang json body parsing

huangapple go评论104阅读模式
英文:

AWS Lambda golang json body parsing

问题

当使用AWS Lambda(通过AWS控制台访问)运行测试事件时,我能够传入以下请求体并正确解析数据到自定义结构体。

自定义结构体:

type ContactForm struct {
	Phone int `json:"phone"`
	Email string `json:"email"`
	Business string `json:"business"`
	Message string `json:"message"`
	Name string `json:"name"`
	File_data *string `json:"file_data"`
	File_name *string `json:"file_name"`
	Uri *string
}

事件JSON:

{
    "email": "email.com",
    "phone": 80077777,
    "business": "business",
    "message": "message",
    "name": "name"
}

当尝试通过Postman或XHR请求命中Lambda函数的函数URL时,解析后的请求体默认为nil、0和空字符串值,显示无法读取JSON请求体。这是Golang Lambda的入口点,应该传入该对象,但通过函数URL执行时失败。

func HandleRequest(ctx context.Context, contactForm ContactForm) {
	if contactForm.File_data != nil && contactForm.File_name != nil {
		uri := create_file(*contactForm.File_data, *contactForm.File_name)
		contactForm.Uri = &uri
	}

	fmt.Printf("%v", contactForm)

    body := create_email_body(contactForm)
	sendEmail(contactForm.Business, body)
}

在通过端点解析时,是否需要进行其他逻辑以与使用测试事件时相比?

英文:

When running a test event with AWS Lambda (accessed via AWS Console) I am able to pass in the following body and properly parse the data to a custom struct

Custom struct:

type ContactForm struct {
	Phone int `json:"phone"`
	Email string `json:"email"`
	Business string `json:"business"`
	Message string `json:"message"`
	Name string `json:"name"`
	File_data *string `json:"file_data"`
	File_name *string `json:"file_name"`
	Uri *string
}

Event JSON:

{
    "email": "email.com",
    "phone": 80077777,
    "business": "business",
    "message": "message",
    "name": "name"
}

When attempting to hit the lambda via a function URL using postman or an XHR request the body when parsed defaults to nil, 0, and empty string values showing that it is not able to read the json body. This is the entry point of the golang lambda that should pass in the object, but fails when done via function URL

func HandleRequest(ctx context.Context, contactForm ContactForm) {
	if contactForm.File_data != nil && contactForm.File_name != nil {
		uri := create_file(*contactForm.File_data, *contactForm.File_name)
		contactForm.Uri = &uri
	}

	fmt.Printf("%v", contactForm)

    body := create_email_body(contactForm)
	sendEmail(contactForm.Business, body)
}

Is there additional logic that needs to be done when parsing via an endpoint in comparison to using a Test Event?

答案1

得分: 2

根据你将数据发送到函数的方式(例如ApiGatewayProxyRequest或在你的情况下的LambdaFunctionURLRequest),事件可能包含额外的字段和元数据。我建议你记录原始事件,参考https://docs.aws.amazon.com/lambda/latest/dg/golang-logging.html,并根据实际发送到函数的内容来定义你的结构体。当我遇到类似情况时,就是这种情况。

此外,你可以使用预定义的包来定义你的事件:"github.com/aws/aws-lambda-go/events"。我认为events.LambdaFunctionURLRequest是你在处理程序中需要设置的内容。然后你可以解析这个负载的正文中的JSON。参考https://pkg.go.dev/github.com/aws/aws-lambda-go/events#LambdaFunctionURLRequest。

func HandleRequest(ctx context.Context, event events.LambdaFunctionURLRequest) {

    body := []byte(event.Body)

    var contact ContactForm
    json.Unmarshal(body, &contact)

    log.Printf("%v", contact.Email)
}

以下是来自GoPlayground的相同方法/逻辑。

package main

import (
    "encoding/json"
    "fmt"
)

type ContactForm struct {
    Phone     int     `json:"phone"`
    Email     string  `json:"email"`
    Business  string  `json:"business"`
    Message   string  `json:"message"`
    Name      string  `json:"name"`
    File_data *string `json:"file_data"`
    File_name *string `json:"file_name"`
    Uri       *string
}

func main() {
    input := []byte(`{"email": "email.com","phone": 80077777,"business": "programming","message": "hello world","name": "John Doe"}`)

    var contact ContactForm
    json.Unmarshal(input, &contact)

    fmt.Printf("%v", contact.Email)
}

你需要对数据进行一些验证,以确保它实际上是JSON,或者捕获负载不正确的情况。这在一般的编程中是很好的做法,所以我假设你还会处理正文无法序列化为结构体的边缘情况。

英文:

So depending on how you're posting the data to the function e.g ApiGatewayProxyRequest or in your case LambdaFunctionURLRequest, the event might contain extra fields and metadata. I'd suggest you log the raw event, see https://docs.aws.amazon.com/lambda/latest/dg/golang-logging.html and base your struct off of what you see actually posted to the function. This was the case when I've run into circumstances like yours.

Also, there is a predefined package you can use to define your events: "github.com/aws/aws-lambda-go/events". I think events.LambdaFunctionURLRequest is what you need to set in your handler. Then you can parse the JSON from the body of this payload. See https://pkg.go.dev/github.com/aws/aws-lambda-go/events#LambdaFunctionURLRequest.

    func HandleRequest(ctx context.Context, event events.LambdaFunctionURLRequest) {

    body := []byte(event.Body)

	var contact ContactForm
	json.Unmarshal(body, &contact)

	log.Printf("%v", contact.Email)
}

Here is the same method/logic from GoPlayground.

package main

import (
	"encoding/json"
	"fmt"
)

type ContactForm struct {
	Phone     int     `json:"phone"`
	Email     string  `json:"email"`
	Business  string  `json:"business"`
	Message   string  `json:"message"`
	Name      string  `json:"name"`
	File_data *string `json:"file_data"`
	File_name *string `json:"file_name"`
	Uri       *string
}

func main() {
	input := []byte(`{"email": "email.com","phone": 80077777,"business": "programming","message": "hello world","name": "John Doe"}`)

	var contact ContactForm
	json.Unmarshal(input, &contact)

	fmt.Printf("%v", contact.Email)
}

You'll need to do some validation of the data to make sure it's actually json or catch the cases in which the payload is bad. This is good programming in general, so I'm assuming you'd additionally deal with edge cases in which the body didn't serialize into the struct.

huangapple
  • 本文由 发表于 2023年7月22日 07:28:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/76741738.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定