Throughout all the changes in web development over the years, the server has been a constant. Regardless of the languages, tools, and frameworks used, there’s always a server running the code. And that’s something that hasn’t changed. What has changed is that cloud providers now make it easy for software engineers to focus on writing their code, without having to focus on the underlying server.
In this course, you'll build a serverless web application using Python 3.6. You'll use Lambda, API Gateway, S3, DynamoDB, and Cognito to create a multi-user to-do list application based on Vue.js.
- Outline the architecture of a serverless web application
- Set up the AWS services required for the app
- Create and deploy an API using Python 3.6
- Explain the value of creating unit tests
- Use a Cognito User Pool within your app
- DevOps Engineers
- Site Reliability Engineers
- Familiar with AWS
- Development experience
- Familiar with the CLI
Welcome back. In this lesson we're going to use SAM Local to deploy the API Gateway and Lambda functions and we'll configure the authorizer in API Gateway so that it can decode the authorization token on our behave. So, let's start with the template. yaml. This should look kind of familiar if you're used to CloudFormation.
Let me just expand this. This is the YAML version of CloudFormation, only this is a subset. This is the SAM Local functionality, so this is built on top of CloudFormation and it has some extensions for things like serverless function, so we can set our properties. We have a handler api. get_handler, we have our runtime, python3.
6. We have our policies, so if you recall, I mentioned the way that you should be working with SAM which is a serverless application model is one function does one thing, so here we have our TodoGet. It is a serverless function. It has a handler which is api. get_handler. Do you remember in the code we have everything under this API, so it looks here, it says api, and then it wants to use the entry point of get_handler.
Well, technically that's this get. py file and this handler here. And the way that it's kind of being masked is we're just imported from get, set the handler as get_handler, set the create handler as create_handler etc. This allows us one entry point, so we can say api. and then whatever the name of the handler is, and it just makes it a little bit easier.
If we go back to our template, so api. get_handler. Runtime is python3. 6. The CodeUri is . /todo. We're using SAM Local. SAM Local knows how to reference local files, so it's going to be able to help us transform this CodeUri into an S3 bucket and you'll see that in a little bit. So, one of the cool things with following this kind of SAM methodology is that you get very granular permissions.
We don't need to have one function that does absolutely everything, it does all of our CRUD and then it maybe has like 10 other functions. It's not a microservice in itself, it's a component of a microservice. So, because of that, we don't need to have that function, have all the permissions under the sun, he can hone in on just what we need it to do.
In this case, we need it to get an item from Dynamo and we need to be able to query. If we come down to the create function, we need to be able to get and put. If we come down to the update, again get and update and for delete, get and delete. So, being able to zero in on just the functionality that we should allow our function access to is going to help us secure whatever application we're building.
So, we have our environment variables. Remember, I mentioned you'll want to use environment variables for things that are like table names, database strings, stuff like that. This is where you can set that in your template. yaml. So, TodoList is the name of the table. That's the name of the table we created earlier if you recall and then we set up this event of API Gateway.
Now, you can have multiple events. You could have things being triggered from all sorts of different locations that kick off a Lambda function. The point of this course is to talk about using API Gateway. So, this is going to create an API Gateway for us and it's going to set up the path and it's going to set up the method.
So, anytime a request comes into our APIT Gateway with /todo and it is a get request, it is going to kick off this handler, api. get_handler which comes from api, comes from this get_handler and that is pulled from our get file. This is the handler here. Let's go back. Okay. So, SAM Local it's going to allow us to upload all of that code to an S3 bucket.
It's then going to create a new template that has the CodeUri pointing to that S3 bucket and then we can deploy our Lambda functions and our API Gateway with that new template. So, let's look in deploy_api. sh. We need a few variables here. First, we'll need to set a bucket. We'll need to set our region, our account_ID and then the stack_name because this again, is just CloudFormation.
Then on the command line we're going to create a new bucket, that's the bucket that we've defined here in the region we've specified. This is a policy for it. It's going to write that to file and then it will use it here to set that policy and then this is where SAM Local is going to take that localized template, it's going to grab our code, it's going put it in the S3 bucket and then it's going to set up an output template, package.
yaml and then you come down to your SAM deploy which is going to allow us to deploy a stack based on the packaged YAML. So, let's set this up and see how it works. Let's start with a bucket. We'll call it CA, python-serverless and we'll quote todo just to make sure that it is unique. We'll set a region east-2 and we need to get the account_ID.
In the console click on IAM. See this link here? We want this ID. You could also access that under the Account Settings. I'm not gonna click on it. It has more information there than you really need to see, so I'll just copy this whole thing and we'll copy individually and we'll copy that out and paste that in.
This stack_name is the stack that it's going to create in this region. TodoServerlessAPI and we'll just say stack just to make it clear in this what it is. Okay. So, those are the only variables we need. Now, let's save this. Okay, so with these variables set, now we just need to edit this template. We need to set our region and our account_ID.
So, we can pull those again from here to copy our account_ID and let's just do a quick find and replace. Okay, do the same thing for region. And I'm just going to copy to make sure that I don't introduce any mistakes. Let's go back to our template. Okay. Let's scroll through and make sure our ARNs are correct.
East-2, that's the correct ID, east-2- east-2, alright. So, this looks good. So, there's nothing else that we need to set in order for SAM Local to wrap up our code and get it deployed. Before we do that I want to jump into the console. I wanna show you that none of this is already set up, so let's look at API Gateway and you can see because we have this Getting Started, we haven't already done anything in this region of east-2, so let's go back to get Lambda.
Again we don't have anything already created, so we're ready to test out our deployment and make sure that everything is working. So, now we can actually run our build script and this is going to make that S3 bucket, it's going to set the policy, it's going to turn our local template into something that knows how to find the code on S3 and then it's going to run the deployment on that based on the code that's in S3.
So now it's running through the stack creation. If we jump into the console and we go to CloudFormation, you can see that there's a create in progress. Clicking on that is going to show what's actually happening. There we go, if I refresh this, you can see that it's just going through setting all the permissions, it's creating everything that we need to get our API Gateway set up, to get our Lambda functions set up and get them all wired up together.
Okay, so this should be done. Great, it's successfully created. Now, let's go back. We want to go to API Gateway. Notice we have a new API Gateway here. This is our TodoServerlessAPIStack. We named it that here in this deployment, TodoServerlessAPIStack. If we drill in, you can see we have our individual HTTP verbs, so we have our get, and it's going to end up kicking off this Lambda function here.
If you're not familiar with API Gateway, it's going to allow you to kind of see the visual flow of a request. The request comes in from the client here. You can even test it with this. It hits this method request. This method request has some information about the mappings for things like headers. It sends it over to this integration request.
This says I want to kick off a Lambda function though there is additional functionality. And then it's setting the proxy request, so it's basically just going to be a proxy for our request, it's not gonna do anything to the request, it's going to take whatever it gets sent, pass it on and then whatever we send back, will get passed back.
If you don't want to use proxy integration you have a little bit more control over how things get mapped into the event, for example, if you wanted to have a specific header that gets mapped to something in the event, you could do that, so a little bit more control but proxy integration works well for this sort of very simplistic web app.
So, you can see the Lambda region, the Lambda function and if we go back, once it hits this integration request, it then calls that Lambda function and then the response just comes back and gets passed back to the client. So, if we click here, we can actually see the function itself. First I'll just show these are our four individual functions.
Clicking on this, you can see there's a little bit of configuration set up. Since we've uploaded this to S3 and are using it from there, you're not going to actually see the code as you would if you just started a new project with a in-line editor. You can see there's no option there for code entry type.
We have our runtime set, our handler set, our environment variable, our todo_table is set to TodoList. Little bit of information about the role that this executes as. So, that allows you to set the permissions for this. Can also set active tracing for debugging and a VPC if you wanted to. Notice the triggers, API Gateway, this is our only trigger.
Our response is going to come in on the path /todo of a method type get and it's going to kick off this function. For monitoring you have some basic monitoring functionality including viewing an X-ray and checking out the logs and you can also kick off some tests if you want to make sure that your code is working here.
So, we have our code in Lambda. We have our API Gateway set here but it's not yet configured properly because we set up Cognito pools for our user authentication. We haven't done anything with those. So, let's do that. Let's set up an authorizer that is going to take a token from the authorization header and it's going to grab the claims from that for us, so click New Authorizer.
We'll say CognitoAuthPool. The type will be Cognito. The only value in the dropdown here is our only pool. Now, this may not be clear, what this is is a token source. It wants to know the name of the header property to grab the token from. So, we're going to set that to authorization. Token validation is a regex that you can use to make sure that the token is kind of the structure it should be.
That's if you're using something more custom. This doesn't really apply to us, so we're going to leave that blank and let's click Create and we don't have a token to test yet, so we're going to leave that. Let's go back to our Resources and we're going to go through each one of these. Start with our get, actually let's start with our delete at the top of the list.
We're going to set the authorization now. Notice here there's only none and AWS_IAM. That's because this is a single-page app that hasn't yet caught these changes. We set an authorizer but we need to reload before we're going to see that in our dropdown. Back to the delete and notice now there's our pool.
So, let's set that, click on this little check mark here. It's not very obvious but that's how it saves and we're going to do this for the rest of the methods. And we'll set our post and finally, our put. Great, so now what we have is functionality that's going to grab the token from the authorization header and it's automatically going to de-serialize that into our claims so that we have access to things like the Cognito username, the email address etc.
Okay, so we've made these changes but this just to our resource. We haven't actually deployed it. If you look at here, we have two stages, we have our staged environment and our production environment. We need to actually deploy this before we'll see it on either of these URLs. If I click on these, notice each has its own unique URL, prod and stage.
This allows you to make changes independently and deploy them to one or another. So, let's go back to our resources and we're going to deploy this API to production. So, what that did was deploy the changes to our off to our production environment, so now they are all set up and ready to go. Okay, now, there are more changes we're going to have to make to this, however, let's stop here because what we've done is we've got our code all uploaded and deployed.
We've created our Lambda functions, we've created our API Gateway, so we've done a lot but we're going to make a few tweaks is as we go. In the next lesson, we're going to focus on the front end, we're going to focus on getting the URL here in this invoke URL set on the front end, we're going to focus on getting the authentication piece to work locally and once it works locally, we're going to be able to then deploy that out to our S3 bucket and test the whole thing holistically.
So, if you're ready to keep diving in, then I'll see you in the next lesson.
About the Author
Ben Lambert is a software engineer and was previously the lead author for DevOps and Microsoft Azure training content at Cloud Academy. His courses and learning paths covered Cloud Ecosystem technologies such as DC/OS, configuration management tools, and containers. As a software engineer, Ben’s experience includes building highly available web and mobile apps. When he’s not building software, he’s hiking, camping, or creating video games.