The course is part of this learning path
Building Solutions for Google Cloud Platform with App Engine
As developers, the learning never ends. Just when we get used to a certain technology, it goes and changes. We’re always needing to learn new languages, frameworks, APIs, and platforms.
And if you’re also in charge of deploying your code, then you need to understand how to setup and configure web servers, deal with scaling issues and manage databases. Frankly, it can be exhausting!
So, why invest the time in learning yet another set of technologies? That’s the question I find myself asking whenever some new trend comes along. I want to know how it’ll make my job, and the jobs of my peers better or easier.
Throughout my career I’ve been responsible for deploying my own code. And I think that’s why the Google Cloud Platform resonates with me so well. It’s a platform that understands developers.
So, why take the time to learn something like App Engine? I think the answer is simple. Because you can take all your development experience and apply it to a platform as a service that removes most of the obstacles to getting code running in production.
The value of having Google ensure your app is highly available is worth a lot to me. We get a rich set of tools for developing locally, and simple deployments, with application versioning. All while using the same programming languages and frameworks that we’re used to.
If you’re looking for a native cloud platform for building out highly scalable applications, or mobile back-ends, then you’ve come to the right place. App Engine provides all that and more.
This course focuses on teaching you about the tools App Engine provides to build out highly scalable systems.
We’ll be building out Python web applications using Flask, and using Cloud Datastore as our database. There is a bit of a learning curve to getting started. And that’s what this course is for, to minimize the amount of time spent learning the platform, so you can get back to writing code.
The source code lives on: Github so feel free to download it, and follow along.
We’ll cover a lot of data in this 2 hour course. And by the end of it, you should feel comfortable getting started building out App Engine applications of your own.
And if you’re looking to get your Qualified Solutions Developer certification, this is going help you with that too.
So, if this sounds useful to you, let’s get started!
In this course
- We’ll create an App Engine application, and deploy it
- We’ll be Developing a REST API with Cloud Endpoints
- We’ll learn about the different Authentication and Authorization methods available on App Engine.
- We’ll learn about the monitoring and management tools available.
- We’ll cover the different storage options available.
- We’ll review Cloud Datastore more in depth.
- We’ll look into ways to improve application performance.
- And We’ll learn about Task Queues.
This is a intermediate level course because it assumes:
- You have development experience
What You'll Learn
|Lecture||What you'll learn|
|Intro||What will be covered in this course|
|Getting Started||Creating our first App Engine application|
|Cloud Endpoints||How to create RESTful APIs with Endpoints|
|Services||How to break our applications down into separate services|
|Authentication||How can we authenticate users?|
|Managing Applications||How do we manage App Engine apps?|
|Storage||How do we use the different storage options?|
|Datastore||A more in depth look at datastore|
|App Performance||How can we make our apps more responsive?|
|Task Queues||How can we run tasks outside of a user request?|
|What's next?||Where do we go from here?|
Welcome back to Developing Solutions for Google Cloud Platform. I'm Ben Lambert, and I'll be your instructor for this lesson. In this lesson, we're going to talk about cloud endpoints. We'll talk about the features that they provide, and then we're gonna actually create an endpoint. Then we'll deploy our application, and we're gonna test it out with the API Explorer.
Cloud endpoints consist of tools and libraries for creating APIs with Java or Python. These are the only two languages officially supported at the time of this recording, and the only output format is JSON. Endpoints are deployed as an App Engine application, and they're used to create backend APIs for mobile and web apps. The best part is because it's just an App Engine application, we get to use all of the same App Engine features that we need, things like cloud storage, cloud data store, task queues, et cetera. And because endpoints handle versioning for us, we can have multiple versions of our APIs up-and-running, and then our consuming code doesn't have to break every time we deploy a major change because the client code is gonna use the version it was written for.
Let's get our hands dirty and actually build an endpoint. Let's build a very simple API that will do something silly like list off some cartoon characters. We'll start by adding a new file named ep for endpoints, dot py. We're gonna add a few imports starting with the endpoints module. And now from the proto RPC module we'll import message_types, messages, and remote.
Okay, we're gonna create a couple of messages. Messages represent the request and response objects. So if our API is going to accept data, it needs to be represented with a message. And the same goes for responses. If we're gonna send back data, we need to represent that with a message object as well.
So because we're going to create a character API, we're going to need to create a class based on the message representing a single character. So we'll call this Character, and we'll give it just a single property of name, which is going to be a StringField. The one that we're passing in represents the identifier for the field in the underlying protocol.
And now, let's create one more message that will represent multiple characters. It'll start out roughly the same way. We'll call it Characters, we'll give it just one property, we'll call that records, and it's gonna be a MessageField. The first argument is going to be the type of message that this field will hold. The second is going to be our field identifier. And then we're gonna add this repeated=True. And this is what's gonna make this into an iterable field.
Okay. So we now have a couple of messages, and now we can use either of these to send or receive data. Let's create a service and actually test this out. We're gonna start with the endpoints API decorator. This will allow us to set the name of our service and our version. We're going to set this to character, and a version of v1. And now we'll create a class that represents the service, and we'll call that the CharacterApi. And it's a service.
Okay, so at this point we have a service, it's called Character, it has a version of one. However, it doesn't have any methods inside of it. So let's add one now. We'll add a method to list off some characters. So again, we're gonna start off with the decorator, and this is going to describe to cloud endpoints what this method expects for arguments and what it's going to return. We'll use the endpoints method decorator, and the first argument is going to be what message we're expecting to receive. And in this case, we're listing off characters so we don't have any request type. So we're gonna set this to a VoidMessage.
Okay, and we're gonna return a Characters message, which is our message that holds multiple characters. And we're gonna set the path, which is the URL we want this to listen on. The http_method is going to be a GET request, and we'll set the name. We're gonna use the format ServiceName.operation, so in this case it's gonna be Characters.list. And now we'll define our method, which will accept a request, though we don't need any of the request info for this request so it's not really important here.
Okay, now we need to return a Characters message. So let's create that real quick. We'll create a Characters object and populate it with some character objects. And we'll just pick some characters. And now we'll return this in our method. Now in order to run this, we need to add one more line of code to set up the API server. We can do that with the endpoints.api_server method, and we're gonna pass in an array of our services. And we're gonna store that in a variable that our script handler will use, and we'll see that shortly.
Okay, let's stop here, and now we wanna test this. But before we can actually run this, we need to set up our app.yaml file to add a listener for this endpoint. So we're gonna add a new URL and it's gonna have this syntax, /_ah/spi.* And we'll add a script that'll point to our ep module. That's the file we just created, the ep.py. And that app variable, that's the variable that stores the results of our api_server method. Okay, this URL is a reserved URL. Now it may look a bit funny, but if you want to use an endpoint you need to use this exact URL. I want you to burn this into your memory. It says /_ah/spi, and that's not a typo. It's not supposed to say API, it is supposed to say spi. And then it's followed by slash, period, asterisk, which is a wild card regex pattern.
And we also need our App Engine app to use the endpoints library. So we're gonna need to add a library section, and we're gonna add a reference to the endpoints library. And we want make sure we get the version right. There's only version at the moment, it's 1.0. And we wanna make sure that we add it as 1.0 and not just the number one.
Okay, now App Engine will know to make the endpoints library available to our app, and it will map the endpoint to our code. Let's test this out in the browser since it's just a GET request. The URL that we use to test this out is going to be /_ah/api/characters/v1/characters. The URL breaks down into the /_ah/api section, which maps to our endpoint. Now notice here, it uses api and not spi. And then the next part is the API name, and then the version, and then it's the path that we specified for our method.
And if we browse to it, we see a JSON object with our records array, and it's filled with our characters. Okay, so just listing off an object is a good start. However, typically we'll wanna pass in some parameters and maybe even post some data to an API. So let's expand our demo by adding a row that will fetch one of the characters based off of an identifier we pass into the URL.
Remember previously, we set the request object to a VoidMessage? Well, that's still the case. We don't expect anything in the post body. However, we do expect an ID to be passed into the URL. So for that, we're gonna use a ResourceContainer to represent the request object.
We'll call it GET_RESOURCE. Now the first argument is gonna be the type of object that we expect in the post body. That's gonna remain an empty object, so we're gonna say VoidMessage again. And then we're gonna add an ID field, and it's gonna be an Integer. And we'll set the protocol ID for that to one. And then we'll use this variant argument to tell the underlying protocol how to transmit the data in this field. Okay, now we can use this in place of a message for the request object, and it will automatically handle dealing with the request object and the URL parameters. So that's pretty cool.
Let's add the new method, and it will use this resource container. The method will select one of the characters out of the records list based on the index that we pass in to this ID field. So like the other method, we'll set up a decorator. We're expecting our resource container to be passed in. It's gonna return a single character.
And we'll copy and paste the rest of the parameters from the previous method, and we'll just adjust the path. And we'll add the name of the URL parameter in brackets here, and we'll change the name. Perfect, now let's create the method. We're gonna wrap this in a try catch block because maybe these IDs don't exist, they might be out of the bounds of our list. Okay. We're gonna catch an IndexError and a TypeError, and we're gonna raise a NotFound exception. This is gonna cause the result to be a 404 error, and it's gonna include the message that we specify.
Alright, let's test this out. We'll add a number to the end of the URL here. And there we go, we have one character. And if we change it, we get another. And if we set it to an index that's out of bounds, there, we have a 404 status back. So this is becoming really useful because we can use these helper exceptions to make things easier to handle errors in a most REST-friendly way.
Alright, what happens if we want to post some data? Let's say we wanna add new characters to our list. How do we go about doing that? Let's go back and test this out. We're gonna add a new method decorator, it's gonna expect a request to be posted with a Character message, and it's gonna return all of the characters back. We're gonna copy and paste again, we'll change the path here, we'll append /add, and then we're gonna change the method to POST. And we'll change the name. Okay, and now we're gonna create a method. We'll call it add_character, and we'll have it append a new character to the list. And then we'll just return that list. Okay, we've been testing this out with the browser because we've been dealing with GET requests.
So what do we do now? We can use the Google-provided API Explorer. You may remember it from the Fundamentals course. However, we'll use it to test out our own APIs in this case. To access it, we're gonna use this reserved URL. It's gonna be /_ah/api/explorer. And when it loads, we're gonna get this error. Now what's happening is our local dev server doesn't use https, so it's not playing well with the Explorer.
We can fix that by following the advice that Google provides in this link here. What they recommend is that we use a couple of command line flags when starting up Chrome. So we're gonna do that. We're here in the application directory where Chrome lives, and we'll run this command. It's telling Chrome that mixing http and https is okay for a local host on this particular port. And now if we browse to the API Explorer, there it is, there's our API. Let's list off the characters. We're gonna click Authorize and Execute. It'll have us log in, and once we're logged in it's gonna run. It'll take a second and there's our characters. And we can test that the GET returns just a single character. And if we pass in an ID, it'll return just the one character that matches the index.
Okay, let's test out our POST. So this is a really cool feature here, where we can create our request body. And if we run that, it should add them to the list and return that list. And there they are, added to the list. Now this is a fantastic way to quickly create REST APIs for our apps. We can very quickly expose functionality via versioned APIs, which means we can have multiple versions of our API running at the same time. This is really useful for those changes that would cause client code to break if we were to roll out breaking changes in place of the current version.
Let's hack together a demo of this. We're gonna create a better characters version of our API. We'll copy our list of characters, and we're gonna call it better_characters. And we'll just change the names so that they have Better in front of them. This will make it easier to see the difference. And now we'll copy and paste our previous character API class, and we're just gonna make a few changes to fix up the names. And we're gonna use the new better_characters list.
Okay, we'll make sure that we add this to the API server on the last line. Great. Let's test this locally. If we change the URL from v1 to v2, we'll see our characters have the word Better in front of their names. And if we go back, the word Better is gone. Alright, let's deploy this to App Engine and check it out. We'll click Deploy on the launcher, and it's gonna take just a little bit of time to make sure that everything's deployed and running correctly. And once it's happy, it's gonna let us know that it's complete.
So cloud endpoints provide us with a clean and easy-to-us library for building REST APIs on App Engine. And we can use Java or Python to create endpoints that will return JSON objects. Now if we're going to create APIs and web apps, we may want to break them out into their own separate modules. And thankfully, App Engine allows us to do that with the concept of services. And that'll be the topic of our next lesson.
So if you're ready to learn more about services, let's get started.
About the Author
Ben Lambert is the Director of Engineering 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 the first platform to run and measure enterprise transformation initiatives at Cloud Academy, he’s hiking, camping, or creating video games.