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 the last lesson, we got our API Gateway and our lambda functions deployed. So now we have an endpoint that we can actually call to interact with our functions. We have here our production todo application. However, we need to work on getting our front end set up so that it understands how to communicate with that.
And to do that, we're going to copy this URL from the stage editor and we're going to head into Visual Studio Code and edit the config file here. So we're gonna set our app URL. We'll paste that. Notice we have a little space there. Make sure it's all cleaned out. Okay. So this is the URL for our function.
Okay, while we're here we also need to set the information for the Cognito user pool. This is just some dummy information that's not actually going to work. So let's go back into the console. And we're going to head into Cognito, manage your user pools, the TodoUserPool. We need a copy of this pool ID here.
And we'll paste this into this first field here, and we need the client ID, which is under app clients. And it says app client ID. So we'll copy that. Paste it, and save this file. OK so now our configuration for our front end is complete. There wasn't much too it. Just a few values that we needed to set.
So now let's test this out locally to make sure everything works before we go and deploy it to S3. So the first thing we need to do is cd into the front end. Directory. OK. We're going to start up a very simplistic web server that's going to allow us to test this locally. So let's run python -m http. server, and then the port will be 3000 because that's the port that we have already bound in this vagrant machine so it's already open.
OK, now that's running. If we copy this, if you're on a Mac, you can right click and open URL, otherwise you'll have to open your browser and paste it. Let's use Command, Option, I to open up our DevTools. I want you to see the workflow as it happens. I want you to see the different calls that are being made.
So if we jump back into our user pool, under users and groups, we have no users, so we have to create one. That's where this register comes into play. Let's register a new user. Ben. lambert@cloudacademy. com. Now we need a password that meets the minimum requirements. OK, and submit that. Perfect. So, notice we have our verification.
Say not now. The verification shows because we need to actually verify that this worked. To do that, I'm going to go into my email. I'm gonna grab the verification code. OK, so here's just a zoomed-in version. You can see this is the code. I'm going to copy that. And now, username again. ben.lambert@cloudacademy.
com. And I'll paste in the verification code and click submit. OK. Now I just have to re-log in. ben.lambert. OK. So, notice we get this kind of error that actually isn't telling us anything, but you can see by this little icon here, we have some errors in the console. See what's happening. OK, this may not be obvious.
Response to preflight request does not pass access control check. What this means is, we haven't set up our cross origin requests. We need to set up another method in our API Gateway so that we can get our cross origin requests working. So this was expected. And the way we solve it is by going into API Gateway and we're going to go to Resources and we'll click on our todo and then under this Actions menu, we're going to create a new method.
Now, notice this Enable CORS. This will work if you created all of this by hand. You can click on this, it's going to set up everything for you. I have not found it to be 100% reliable when you do this after you've created this with a template and to show you exactly what happens, I'm going to click on Enable CORS and I'm going to click Enable CORS and replace existing CORS headers.
What this is doing is going to offer to create an options method. It's going to add a 200 method to that response, it's gonna set it up as a mack and it's gonna go through the rest of these and set the headers. By saying yes, notice that there are several failures. So, it didn't do exactly what I needed to do.
I'm not sure why this is. I just want you to be aware that this is a thing. So, it did create this options method here, however, I want to delete this and manually create it so that you can see it from start to finish, so I'm going to focus on that, click on Actions and select Delete Method. Don't select Resource.
The Resource is our todo item and it has all of the methods so you don't want to delete all of that. Make sure select Delete Method and just to verify, do you want to delete options and yes. Okay, there it is. So, let's go to Actions, Create Method. In this dropdown here we'll select Options. Select the little checkbox and what we're going to use is a mock.
So, previously the lambda function was used because we want the API Gateway method of say get or delete to map to a function. In this case why run a function when you really don't have to? All we wanna do is some preflight, we want to send back some specific headers, so we're going to select mock. Okay, we don't need off because we want this to be able to run unauthenticated and we want to set a method, so for 200.
Click the check and now we need to add some headers. To find these headers, I've set these up in the read me file, so if you go to the README. markdown you can see the headers that we'll need. We're going to copy the header name, paste that in, we'll add another one for the methods and one more for our allowed origins.
Okay, notice you don't set the values here, so let's hit this integration response, expand it with this arrow here and go to header mappings. So, this our allowed headers, our allowed methods and our allowed origins and let's start with the headers. These are the headers that we're going to allow to be passed through, copy the value I have here in the markdown, paste it in.
It has to be in single quotes. The single quotes need to be included otherwise you're going to get an error. Here's what that error will look like. Invalid mapping expression and then it references the specific error. So, if we add the single quote back on, and click, there we go. So, let's set the method next.
And let's paste that and click the check and finally we can just type this one out, single quote, asterisk, single quote and click check. Alright, perfect. So, now what's going to happen? The client is going to make a request, it's going to hit this method request, it's going to determine what type of integration request this is, it's a mock, so all it's going to do is send back this integration response, it's going to send this back with our headers of our allowed headers, our allowed methods and our allowed origins.
This is our cross origin requests here. So, now we're able to have our cross origin requests set up to allow for any origin without having to actually use a lambda function. Okay, we have not actually deployed this. We need to deploy this before it's going to work, so let's click on Deploy. Let's select prod because that's the particular endpoint we're using in our app.
Okay, let's go back to our app and click Refresh. Okay, so here's our app. We've made a successful call. If you notice here, let's look at the headers, it uploaded, it called this URL with a get, we got a 200 and if we look at the response, we simply got back an empty array. That's legit. We don't have anything there yet, so I wanna do two things.
First, I wanna jump back into the console. I want to show you in DynamoDB, so let's type in Dynamo. I wanna show you that there are no records yet. Click on Tables, TodoList, Items, we have nothing. Now let's test out our post. And we can do that by typing something in here. We'll say we need to test the API and we'll click enter.
Great. So, let's go to the headers of this. I wanna make this a little bit larger. So, you can see we hit our options here, so that's our preflight. It determines which methods are allowed and then we kick off our post. Let's look at what we're posting. We're posting an object with a property of item and the value that we just set.
Let's check out the response. It's a little more involved because, use preview, it's a little easier to see, it's a little more involved because now we actually have this is the completed flag, it's not completed. It was created on 10-10. You can see the item itself. You can see the todoId and the userId, so now we have a bit of information coming back based on what was sent to our API.
If we go back to Dynamo and we refresh this, notice here, here's our record. Okay, next, let's try and test the functionality for updates by first marking it complete and notice we get the 200 here. Let's jump into the database and verify that it actually marked it complete and there we have a true, so now if we reload the page, it should come back and it should be already checked.
Perfect. Let's uncheck this and again, let's just verify and it's set to false right here on our completed flag. Now let's try and edit this by double clicking on this. We can say test the API. Now, let's change it to test the delete because that's the only method we haven't tested. Clicking enter should set that.
It says that it hit this route for put and it received a 200 status. Let's look at the database and make sure that it reflects that, so this should say test the delete when I refresh and there it is, so our update is working. Now let's see if we can't delete this by clicking on this X here. Okay, this is a little bit different.
Notice it actually passed in this ID that it wants to delete, so it's a 200 response. If we look at the response here, you can see deleted equals true. If we head back to Dynamo and refresh, we have nothing left. So, now let's try and add a few things. Thing 1, thing 2, and thing 3. If we head over to Dynamo, there we go.
We have our three things and they're all false. So, we've shown that the UI is working locally when wired up to our API running on AWS. That means if you set the values in the config. js file to the correct values and the API is deployed properly, and you've correctly configured CORS, then the UI should work correctly.
Alright, let's wrap up here. In the next lesson we're going to take a slight detour and dive into the off process. So, if you're ready to learn a little bit more about the off process, then let's get started 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.