Welcome to this session today. I'm going to show you how to build a Go serverless REST API with AWS I opened my IDE I used Goland and I created a directory which is named serverless-rest-api. The first thing that I'm going to do is that I'm going to initialize my module, my go module. So I'm going to type "go mod init" and then my module path. So it's going to be github.com/maximilienandile/serverless-rest-api github.com/maximilienandile/serverless-rest-api github.com/maximilienandile/serverless-rest-api github.com/maximilienandile/serverless-rest-api github.com/maximilienandile/serverless-rest-api And I'm pressing enter and you can see that we have this message. So it means that a go.mod file has been created and you see you have my module path. And then the go version that I'm using, I'm using go 1.19. The next step is to create a new main file. So I'm creating a new file named main. So it's going to be main.go. And you can see that my IDE has automatically added package main and then the function main. So the function main will be the entry point of our program so I can just do a small Hello World to verify that it works. So fmt.Println("Hello World") So fmt.Println("Hello World") Then I can run that application. I tap "go run main.go" And the application will be compiled and it will be run okay. We might want to do something else than a simple Hello World. The first step will be to install a module which is named Gin. So I'm going to open my internet navigator and then I'm going to search for Gin. So on github you have many modules that are available and one of his name, Gin. So Gin is an HTTP web framework which is written with Go. And this is what we are going to need to develop our application. So I'm going to install it on my application. So you have the installation instructions. So it's "go get -u" -u enables you to download the latest version. So I'm using that. I'm copying that and then I put that into my terminal. So the latest version will be downloaded and my go.mod file will be also updated. And my go.sum file will be also updated and created by the way. So here you can see it here. So I have to go.mod and the go.sum then the next step will be to use that library. So as always when I start a new library, I take a look at the readme in order to see the quick start. So there is usually an example on how to use it and then I'm going to copy that and then paste it. All right. So by the way, you can see that my IDE as detected that I want to use the package Gin that comes from that module. so it has automatically added the import statement here. That's one of the main reason to use an IDE is that you don't have to write it by end. If you're not using an IDE like Goland or VS Code. you might have to write it by yourself. So what it does. The first function that is called is the Default function from the package Gin. So default will return an engine instance with the logger and recovery middleware already attached. So it will return a new default server with logging and recovery. Recovery. It means that when your application will panic (will have a run time failure). It will recover. It will not stop the application but it will allow your application to keep running. So here I am creating a default engine and then I can define my routes. So here it will be GET route so "GET /ping" and here you have the handler that will be executed. So this function will be executed when we will have a request on the /ping route. GET /ping And then r.Run will attach the router to an http server and start listening and serving http requests. So here my server will run let's compile and run this program. So "go run main.go". You can see that you have an alert. Do you allow the application main to accept incoming network connections? You're going to press Allow, This is a security feature of macOS I'm on macOS. I'm going to allow that. So then I have my server that is listening on this port 8080. Take a look at the logs that we have. So we have one route GET /ping and it's going to be linked to the main.main. So Package main inside the main function and the function one Function one. It's a name that is by default because we don't have really a function. We have an anonymous function here. It's still a function but anonymous. Alright. Then I'm going to open my navigator chrome And I'm going to try to pink that seven. So localhost:8080/ping. Alright. So I have a message pong here that is written so when I GET /ping I have this response here so JSON response with "message" and "pong" and so it works as expected and you can see also in the logs that we have the request that is logged and the time it took to handle the request. Alright, good. Alright. So now I have a good application that runs a web server that will accept incoming http requests on the port 8080 and that has one route GET /ping. It runs on my local I want to deploy that to the AWS cloud in the several s mode. So to do that I'm going to use the serverless framework I'm going to show you the homr page of that applications of serverless.com but we need to have NPM installed on our machine, so NPM This is the dependency management soft, that is used in the node.js community. So first, if you don't have node installed on your machine and NPM installed on machine, you will need to install that. So go to nodejs.org and then install the latest version. So here you have the LTS or long time support version, so you install that and you will have node and NPM on your machine because I already have that. I don't have to install it. The next step is to install Serverless and Serverless is instable via NPM. So we're going to have these command "npm install -g serverless" so it's going to install globally serverless on our machines. So I'm going to copy that and I'm going to open a terminal and then I'm going to paste that command and then press enter when the installation of the Serverless framework is finished, you're gonna see this here, you can see that I have notice it means that they have not the latest version of NPM installed. Anyway, serverless has been instead. So in order to check that serverless is installed, I'm going to type serverless and then version and you can see that I have an error because the common version is not found but still I have an error. that is from the Serverless framework so I can run "serveless --version" Maybe it's better. Yes. So "serverless --version" will get you the version of the framework installed here have the version 3.24.1 etc. So now we are ready to initialize our project with the Serverless Framework. Let's go back to your IDE I'm going to add a new file that will be named serverless.yml serverless.yml serverless.yml It's a YAML file. So a YAML file is a particular format of file. And so in that file I'm going to describe what I want to deploy into the cloud and it will be used by the severest remark in order to deploy what we're going to walk on to the cloud. So the first thing that I want to add is service and then I had a colon and I'm going to add my service name. So it's going to be serverless-rest-api like the project name but you can put whatever you want. Then I can define the framework version. So you type from a version and then the colon and then you define the version of the framework that you are going to use (the serverless framework). So here I'm going to type 1.18.0 it brings you compatibility with the previous version of the framework. Then I would have to define the provider that I want to use. And here I have to define the provider by name. So I'm going to say that I want to use AWS. Um so I have a provider key then the name key. It's "aws" after that. I would have to specify the runtime that I want to use. And I'm going to say that I want to use the runtime Go1.x And you can see that I have autocomplete in my IDE That's because I've certainly added a plugin for serverless. Then I define the region where I want my application to be deployed in AWS if you remember this works with regions. So regions are large data centers. So you have many regions. I'm gonna select one which is eu-central-1. Then I will have to provide the stage. Um So here I'm going to say that I want to provide that with the common line interface. So I had a dollar, then curly bracket, then opt. And then stage. And then I close the curly brackets. So I'm going to I'm going to provide the stage by command line. I can also write that hardcoded here But it's better to have that provided by the command line interface. So after the stage we need to define our serverless functions. So we create another key "functions" and then we're gonna define all our functions. So for the moment we will have just one function and we will name that function api when you define a function and we need to define a handler. So for the moment and we'll just put X here, we're going to change that later. And then you need to define the events that will trigger your function. So for the event I'm going to put as well XXX here and we will complete that later. And then I'm going to add a new file in my project and this file will be named Makefile. And be careful with the naming. You have to start with a big M the Makefile will help us to run commands in order to deploy our application to the AWS cloud. So what is a Makefile A Makefile is a textual file where we define rules and each rule has a target, which is equivalent to a name. I'm going to define a first rule and let's call that "build". And in this rule, so I add a tab here a colon and then a tab. And I'm going to define the instructions that I want to run. Um each rule has what we call a recipe which is composed of a set of instructions and do not forget this tab. So here I'm going to put my build command. Um so I'm going to type "env GOOS=linux" So I'm setting an environment variable named GOOS And the value would be linux and this Environment variable will allow us to compile our Go program for the Linux Environment and then I type go build, then I'm going to add some linker flags. So -ldflags And then equal -s and -w. I'm going to explain that later. So what does it mean exactly? So go build. I'm building the program and then I say that I want to build that into the directory bin and my binary will be named main. And what do I want to build? I want to build the file main.go main.go So I want to build for Linux. So um setting GOOS to Linux and then I have this command. So go build and then some linker flags. And I set my binary name So the file that will be created by the compiler, it would be put into the directory bin and it would be named "main". And I want to compile this main.go. It will compile that and put that into the bin director. So I'm going to create a new director here named bin. Okay, so let's test that. So it's control c in order to stop the server. And then I'm going to type make build. So you can see that it displays the command that it runs. And you can see now that we have a new file that has been created in the bin directory and it is our main file. So this is a binary file So let's say that I want to run it. So I'm going to type in my terminal ./bin/main And you can see that we have here an exec format error That's because we have a binary that has been made for Linux and I'm on Mac. So that's normal. That's totally normal. Now that I have my compilation instructions that are on my Makefile and I'm able to compile my program, I need to say to serverless what do you need to put and push into the AWS cloud? So to do that, I'm going to add a key which is named "package" and in this key I'm going to set the things that I want to package and things that I don't want to package. So things that I want to include and things that I want to exclude. So before there was a previous notation with exclude include. Now, it's using this kind of notation. Um so I'm gonna just copy this one And we're gonna put that into our serverless file. So by the way, the serverless framework has a great documentation so you can go on serverless.com/framework/docs. So I'm testing that here. And so I want to exclude everything and then I want to include only what is inside bin and particularly I want to include bin/main So the first line is for exclusion. I said that I want to exclude everything, so note here, the exclamation mark. This is for exclusion and I want to include that. So exclude everything. And I want just to include that bin/main. So this file will be included and pushed into AWS And now there is something that we can define now. So we have a function named api. And this function as an handler which is equal to XXX. We can remove that and put bin/main this is the program that will be executed when your function is called. So we want to execute bin/main And now the next question that we have to answer is what are the events that will trigger our function that will launch our program events is a list because you can have many events that trigger the same function. So I'm going to remove the xxx, then press enter and then have a dash and we will have the first http event and this http event we will need to define here the path so we will define the path "/ping" and then we need to define the method and the method here is GET by the way you can note here that what I've defined here "GET /ping" This is the same as in my main function, you can see here that on my Gin server. I said that I want to have a route that is GET /ping. So now I have my serverless file in that file. I said that I want to use the provider aws and I want to create a function that is named api that use this handler and react to these events. And I also give instruction to package my program. I have everything needed in order to deploy but we need to deploy and to deploy we need to input a command into the terminal in order to make your life easier. We will add another receipt to the Makefile we're gonna name that "deploy_prod" And so we are the colon and then with the Makefile we can say okay please run that before running the command and I'm going to give you so I'm going to say that I want to run first build because I need to build my Go program it to compile it and then I can actually run the command in order to deploy with serverless and so it's serverless deploy. Then I have to specify the stage and I said that I want to deploy in prod you can see "--stage" and then "prod" you can find it here here I have an option command line option that I've set up and this will be replaced by prod when I run this command and then there is something specific to AWS. I want also to say that I want to use a specific AWS profile. If you don't input that your main credentials will be used. But if you have many credentials you can also set up AWS profiles. So to do that you just type "--aws-profile" and so on my computer it's named "maxaldtools" So I say to serverless, please use this profile when you deploy this application. It's pretty useful when you have more than one profile and you have many AWS accounts There is some documentation online that you can find in order to set up those profiles on your computer. Basically you will have to create a new file and then you can set up different AWS profiles. I'm going to put the link to the documentation in the video description. All right. So now we can run our command. So by the way, I opened a new terminal because I think this one is a bit slow. So I'm gonna just type document in that new criminal but it's the same as if I type it here. Don't be confused. So I'm gonna type "make deploy_prod" and we will see what happens. So you can see that the compilation that will take place and then this comment. So the first step is to create a cloud formation stack. We'll see later what it is. So when you see that on your terminal "service deployed to stack ...", it means that your service has been successfully deployed to AWS and you can see that we have the list of endpoints. So for the moment we have just one point is it's this endpoint. So I'm going to copy that and test it to test it. I'm going to use curl. So with that I can type in my terminal curl and then paste the URL to my endpoint. And then I press enter, you can note that we have a bit of latency. So it's not a good news. And then we have this message "internal server error", something wrong happened. We will have to debug that in order to understand what's wrong. We will have to check the logs. So connect to the AWS console. So you look in on your account and then make sure you have selected the right region. So here I select eu-central-1 which is Frankfurt. And then I click on cloudwatch. So you can also search here for cloudwatch and we're gonna click then on log groups and on log groups we should see our log group for our function. So I'm going to type the service name and you can see that I have a log group here. So "serverless-rest-api-prod-api" Let's take a look at one log stream. So you can see here that we have logs from our application and you can notice that we have the same logs that we had in local. So we have GIN DEBUG we have the GET /ping that is created. Um And then the idea is to search for the error that we have uh you will see that in the logs you have some messages that start with START and then request id and here you have a message that is not from our application apparently. And then you have END. So here it means that you will have the message for a specific request. And you can see that our task timed out after six seconds. So that's why we had a little bit of latency, the six seconds latency and the task just timed out. Um So it means that we are not handling requests correctly on our application. Maybe our application is not well formatted and doesn't fit into what AWS expects. Let's take a look at the documentation for the lambda function and specifically the documentation that is written for Go developers. You can see an example here. So we have the package main and inside the function. You can see that they use this package "lambda" that is from this module. github.com/aws/aws-lambda-go and you can see that they are calling the Start function and they give to the Start function another function which is HandleRequest. So here is our mistake, we have to format our code like that. So the first thing to do is to install that. So I'm going to copy that and go back to my IDE and then I type "go get" and that you can see that it has been added to our project now we're going to mimic what they do. Um So because we have some stuff in the main we can put that into a "init" function. So the init function will be run before everything else. So let's put that into our init function. I'm going to remove the run and then I'm going to mimic what is done here. So it's lambda.Start(HandleRequest) let me copy that directly. Um So then I have to say that I want to import context. I'm going to import the package from the standard library so context and you can see that we have to define here an event. So in the example the event is the type that they have created but our event is an http request. So it's not going to be MyEvent. It's not gonna be something that we're going to create. It is going to be a type that is provided by the AWS SDK for go. So there is a package in that SDK that is named "events". And inside that package we have many events you can see we have S3 events, cognito etc... and we will use the APIGatewayProxyRequest as input and the output would be events.APIGatewayProxyResponse Why do I put that here? That's because when we have deployed to AWS serverless has created an API getaway. So whenever my lambda function is called, I will receive this. So an event api gateway proxy request. And I would have to send back an api gateway proxy response response. And so you can see that this is not good because we expect to have an api gateway proxy response. So let's do a quick test and we're gonna send an event proxy response. Let's take a look at that type and you can see that we can define the status code. We can define the eaters, multi evaluators. The body and boolean we says is it a Base 64 encoded or not. Um let's for the moment I'm gonna just send a status code which is equal to 200 and maybe the body as well. And for instance the body will be fmt.Sprintf("Hello World") or just Hello world. Okay then I can leave it like that and we can make a test. So let's deploy again. So because we have modified the application, we're going to deploy again. So we use the make command so "make deploy_prod" we have the application that has been redeployed. So let's try again to do this curl. So by the way the URL has not changed. It's still the same. So I'm going to press enter and you can see that we have the feedback. Hello world. That's good. So that means that our api Gateway is responding and this is our program that is responding. Great. But now we have to wire our Gin web server with this HandleRequest function in order to do that. We will use something that has been developed by the AWS labs and it's called the Gin adapter. So this project is hosted on github so it's github.com/awslabs/aws-lambda-go-api-proxy And you can see that it covers all web frameworks that you have in Go most of them and especially Gin and here you have an adapter that allows you to wire your server with this HandleRequest function Um so let's install that. So I'm going to copy that. So github.com/awslabs/aws-lambda-go-api-proxy And then I go back to my IDE and I type "go get" and that Okay so it has been added to our modules. So now we can use it. Then we can use this module. So let's refer to the README and as you can see in the read me you have a section for Gin. So you can see by the way that they have the same construct as me. So an init function where I created Gin default server then they have the ping (route). Uh but they create here a global viable that is called "ginLambda" of type pointer to "ginadapter.GinLambda" So I'm going to add that to my program and here you can see that they set "ginLambda" which is equal to "ginadapter.New" and it takes the engine as input So we have "ginLambda" that set inside the init function and then inside the handler, I'm going to copy that. So I replaced that by this one and so it takes as input a context then and events.APIGatewayProxyRequest let's rename that input viable from "name" to "req". And then it looks good then we can recompile and deploy. So same as before I use make deploy underscore prod After 43 seconds my service has been deployed to the cloud and now it's time to test it. So I'm using the same curl command and let's see if we have the "pong", that's awesome our API getaway linked to the lambda function is working. Let's take a look at what has been created in the cloud. When you run serverless deploy. So to check that you go to the console and then you select the service, cloudformation. Then you are going to select the appropriate stack. So everything in cloud formation is a stack. Um and you can have many stacks and you will have one stack by service x stage. So here this is my service, "serverless-rest-api" And here this is the stage. So this is the prod stage um and you can see here that what we have is an api getaway deployment. An APIGateway Method and api gateway resource rest api then a lambda function, permissions related to the lambda function, versioning, Lambda Version a log group and IAM role An S3 buckets and an S3 bucket policy. Let's make a brief summary of what has been created in the AWS cloud for this service. So you as a developer you are going to use serverless so when you type in your terminal, "serverless deploy" serverless is going to create a cloud formation stack for you with everything you need in order to deploy your service, then it's going to push your code, your binary, so the result of the compilation of the Go program into an S3 Bucket. and this binary is going to be injected into a new AWS lambda and again everything is handled by CloudFormation. So you will have a lambda that will have your Go program loaded in it. And this lambda might also create some logs and so it will create some logs into a specific log group that will be created in amazon cloudwatch. And so from the point of view of the clients. So when somebody is going to request your api they're going to send an http request to an API Gateway that has also been created by the CloudFormation and this API Gateway will pass the request to the lambda function where you code will execute. There is another thing that we can do in order to make our API perfect is to set up a custom domain name. So instead of having " "execute-xxx..". We can have api.your-domain.com set up. And that will route the traffic from this specific domain name to your api getaway. It requires too much time so I will create another video in order to explain how to do that. Stay tuned. Thanks for watching. I hope that you have learned something from my video. Some of my links, practical-go-lessons.com This is a book about Go and you can read the online version for free. You can also support me by buying the digital or the paper version. I also have a Go course on that website of 32 hours to be a full featured website with Go and VueJs and then my social networks where I try to share content around go and programming. So you can follow me on twitter on linkedin and also on youtube. Thanks again and see you next time