Converting an AWS Lambda Function in Go into an Azure Function using LLMs
Converting an AWS Lambda into an Azure Function using LLMs in Go
Disclaimer: This article is an experimental implementation about applying LLMs to convert AWS Lambda functions into Azure Functions. It is not intended as a defined guide for the process and does not guarantee successful conversion. The outcome depends on the specific code you intend to convert and the LLM that you are using.
What would it take to convert a Lambda Function into an Azure Function?
How does a Lambda look like?
import (
“context”
“fmt”
“github.com/aws/aws-lambda-go/lambda”
)
type MyEvent struct {
Name string `json:”name”`
}
type MyResponse struct {
Message string `json:”message”`
}
func HandleRequest(ctx context.Context, event *MyEvent) (*MyResponse, error) {
if event == nil {
return nil, fmt.Errorf(“received nil event”)
}
message := fmt.Sprintf(“Hello %s!”, event.Name)
return &MyResponse{Message: message}, nil
}
func main() {
lambda.Start(HandleRequest)
}
func () error
func (TIn) error
func () (TOut, error)
func (context.Context) error
func (context.Context, TIn) error
func (context.Context) (TOut, error)
func (context.Context, TIn) (TOut, error)
What should be the result?
import (
“fmt”
“net/http”
“github.com/gin-gonic/gin”
)
type MyEvent struct {
Name string `json:”name”`
}
type MyResponse struct {
Message string `json:”message”`
}
func HandleRequest(ctx *gin.Context) {
if ctx.Request.Body == nil {
errorMsg := “received nil event”
ctx.JSON(http.StatusBadRequest, gin.H{“error”: errorMsg})
return
}
var event MyEvent
err := ctx.ShouldBindJSON(&event)
if err != nil {
errorMsg := fmt.Sprintf(“error on reading request body: %vn”, err.Error())
ctx.JSON(http.StatusBadRequest, gin.H{“error”: errorMsg})
return
}
message := fmt.Sprintf(“Hello %s!”, event.Name)
ctx.JSON(http.StatusOK, &MyResponse{Message: message})
}
func main() {
r := gin.Default()
r.Handle(http.MethodPost, “/HandleRequest”, HandleRequest)
r.Run()
}
The attempts
Chain-of-Thought (CoT) Prompt
Few shots using an example selector
Fine tuning
The solution
Language agent tree search
Simple prompt
You will be given a lambda function code. Rewrite the code without using lambda code and using a GinGonic server instead.
import (
“fmt”
“net/http”
“github.com/gin-gonic/gin”
)
type MyEvent struct {
Name string `json:”name”`
}
type MyResponse struct {
Message string `json:”message”`
}
func HandleRequest(c *gin.Context) {
var event MyEvent
if err := c.ShouldBindJSON(&event); err != nil {
c.JSON(http.StatusBadRequest, gin.H{“error”: err.Error()})
return
}
message := fmt.Sprintf(“Hello %s!”, event.Name)
c.JSON(http.StatusOK, MyResponse{Message: message})
}
func main() {
router := gin.Default()
router.POST(“/handle-request”, HandleRequest)
router.Run() // By default, it listens on :8080
}
and intuitive unit tests for functions. You will be given a Go AWS Lambda function, that
is being converted to a GinGonic http server. Your job is to generate a comprehensive set
of tests to ensure its functionality remains consistent. The tests should cover all major
functionality of the function, including error handling, input validation, and expected output.
Here is the Go code for the AWS Lambda function:
{{lambdaCode}}
Here is the Go code for the GinGonic http server:
{{azureCode}}
import (
“bytes”
“net/http”
“net/http/httptest”
“testing”
“github.com/gin-gonic/gin”
“github.com/stretchr/testify/assert”
)
func setupRouter() *gin.Engine {
gin.SetMode(gin.TestMode)
r := gin.Default()
r.POST(“/event”, HandleRequest)
return r
}
func TestHandleRequest_Successful(t *testing.T) {
router := setupRouter()
w := httptest.NewRecorder()
body := bytes.NewBufferString(`{“name”:”John Doe”}`)
req, _ := http.NewRequest(“POST”, “/event”, body)
req.Header.Set(“Content-Type”, “application/json”)
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.JSONEq(t, `{“message”:”Hello John Doe!”}`, w.Body.String())
}
func TestHandleRequest_BadRequest(t *testing.T) {
router := setupRouter()
w := httptest.NewRecorder()
body := bytes.NewBufferString(`{“nom”:”John Doe”}`) // Incorrect JSON field name
req, _ := http.NewRequest(“POST”, “/event”, body)
req.Header.Set(“Content-Type”, “application/json”)
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestHandleRequest_EmptyBody(t *testing.T) {
router := setupRouter()
w := httptest.NewRecorder()
body := bytes.NewBufferString(`{}`) // Empty JSON body
req, _ := http.NewRequest(“POST”, “/event”, body)
req.Header.Set(“Content-Type”, “application/json”)
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.JSONEq(t, `{“message”:”Hello !”}`, w.Body.String()) // Expect default behavior for empty name
}
import (
“net/http”
“net/http/httptest”
“strings”
“testing”
“github.com/gin-gonic/gin”
“github.com/stretchr/testify/assert”
)
func TestHandleRequest(t *testing.T) {
type args struct {
request *http.Request
}
tests := []struct {
name string
request func() *http.Request
expectedCode int
expectedBody string
}{
{
name: “success”,
request: func() *http.Request {
req := `{“name”:”Ana”}`
return httptest.NewRequest(http.MethodPost, “/handle”, strings.NewReader(req))
},
expectedCode: http.StatusOK,
expectedBody: `{“message”:”Hello Ana!”}`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
router := gin.Default()
router.POST(“/handle”, HandleRequest)
w := httptest.NewRecorder()
httpHandler := router
httpHandler.ServeHTTP(w, tt.request())
assert.Equal(t, tt.expectedCode, w.Code)
assert.Equal(t, tt.expectedBody, w.Body.String())
})
}
}
Feedback: |
TestsPassed: … <The code for the test I manually added>
TestsFailed: … <The code for the auto-generated one>
ErrorTrace:
C:/Users/XXXXX/AppData/Local/Temp/go-lats/lats_test.go:44
Error: Not equal:
expected: 400
actual : 200
Test: TestHandleRequest_BadRequest
Score: 0.75
series of unit tests. Your goal is to write a few sentences to explain why your
implementation is wrong as indicated by the tests. You will need this as a hint when you
try again later. Only provide the few sentence description in your answer, not the
implementation.
{{examples}}
[function impl]:
{{azure_code}}
[unit test results]:
{{feedback}}
[self-reflection]:”
request (such as wrong field names), the error should be reported with a status code of
`http.StatusBadRequest`. However, the failing unit test `TestHandleRequest_BadRequest`
suggests that this behavior is not occurring as expected. The test sends a JSON body with
an incorrect field name (`”nom”` instead of `”name”`) and expects a
`http.StatusBadRequest` status code due to binding failure, but the test reports receiving
a `http.StatusOK` status code instead. This indicates that the `ShouldBindJSON` method
might not be detecting the discrepancy between the expected and received JSON fields or
the error handling logic after the `ShouldBindJSON` call is not functioning correctly.
You are an AI Go assistant. You will be given your past function implementation, a
series of unit tests, and a hint to change the implementation appropriately. Write your
full implementation, Rewrite the code without using lambda code and using a GinGonic
server instead. Do not by any chance use lambda code.
Use a Go code block to write your response. For example:
“`go
func main() {
fmt.Println(“Hello, World!”)
}
{{examples}}
[user message]:
{{lambda_code}}
[assistant message]:
{{azure_code}}
[user message]:
[unit test results from previous impl]:
{{feedback}}
[assistant message]:
[reflection on previous impl]:
{{self-reflection}}
[user message]:
Try to convert this code again:
{{lambda_code}}
import (
“fmt”
“net/http”
“github.com/gin-gonic/gin”
)
type MyEvent struct {
Name string `json:”name”`
}
type MyResponse struct {
Message string `json:”message”`
}
// HandleRequest processes the event and returns a response
func HandleRequest(c *gin.Context) {
var event MyEvent
// Bind the JSON to the struct; if nil or incorrect, return an error.
if err := c.ShouldBindJSON(&event); err != nil {
c.JSON(http.StatusBadRequest, gin.H{“error”: err.Error()})
return
}
// Check if the event is nil or the name is an empty string
if event.Name == “” {
// Respond with an error message if Name is empty
c.JSON(http.StatusBadRequest, gin.H{“error”: “name field is required”})
return
}
// Constructing the message
message := fmt.Sprintf(“Hello %s!”, event.Name)
response := MyResponse{Message: message}
// Sending back the response as JSON
c.JSON(http.StatusOK, response)
}
func main() {
// Set up Gin router
r := gin.Default()
// Define POST route
r.POST(“/event”, HandleRequest)
// Run the Gin server on a specified port
r.Run(“:8080”)
}
Microsoft Tech Community – Latest Blogs –Read More