RESTful and HTTP APIs in Pyramid Transcripts
Chapter: Your first service
Lecture: Adding data
0:02 So we have the web exchange part of our API created this doesn't look like a whole bunch of auto data,
0:10 we need to add some data and that brings us to Kaggle. Kaggle is a data science competition place, they have many different data sets
0:20 so here you can see they've got this used car database with over 370 thousand used cars scraped from Ebay Kleinanzeigen
0:29 so basically Ebay Germany, and it's got a bunch of German cars, including all the Opels that we want to start selling
0:37 through our little dealership in our small town. So what I've done is I've taken this, downloaded it, and basically filtered it down just to the Opels
0:45 and then we're going to use that data in our API. Now, there's no point in you watching me write this,
0:52 so I'm just going to paste a little bit of code here, and this is somewhat big bit of code but let's close these all off,
0:59 now notice, we've got our csv here brand, name, price, year, whether it has damage and when it was last seen for sale.
1:08 And notice they're all Opels because I filtered it down, it doesn't have as many, there's still like tens of thousands of Opels but not as many,
1:16 and then we have this fake in memory database, and basically it's using a dictionary with the id of the car which it generates at runtime
1:24 when it first load s it up, as well as loading in this the file so here you can see it calls load data, and the load data just pulls those in
1:33 creates a little temporary primary key thing that we can exchange in our API
1:38 and stores that car, it's important to note that we're using the dict reader so the things here, this row that it represents an individual car,
1:48 that is a dictionary, that's super important because that means we can serialize it just by straight returning it from our APIs,
1:54 if it weren't the case, then we would run into issues; We'll switch to better a real database with real database entities
2:00 and we'll see to address that, but for now these things get loaded up and returned as dictionaries so that helps us a lot.
2:06 So that's really all I want to talk about this, we're going to come back into a proper database part later,
2:12 but we're just going to look at the two functions get all cars and get a car by id car ids are strings, which is handy
2:18 because that means that no conversion is necessary that's the way they come off our API or of the url.
2:23 Okay, so let's go over here and do this first part here, let's go over here and say we want to get some cars and it's going to be a repository,
2:31 we can import that, thank you PyCharm and we can call all cars and notice that there is a limit, so we want to set the limit
2:37 to 25 cars or something to that effect, so what we're going to get back is a list of car dictionaries
2:43 that are loaded up there and we can just return those cars, ok. So in a real service, where you have ten thousand cars or twenty thousand cars
2:52 however many are in that csv file, you don't want to return all of them we'd want to implement some sort of paging,
2:58 so maybe we'll come back and add paging, you could tweak the url to basically pass like a skip level and a page size level
3:06 or you could hard code the pages size and just do a page number to implement some kind of paging but we probably don't want to return like everything
3:14 so we're limiting it to just the first 25 responses. So let's try the all autos bit, okay it still runs, that's encouraging
3:22 so we can come over here and if I click on all autos it shouldn't be that little test data, instead what do we get- oh that looks real
3:30 see Opel, Opel, Opel, and this is a little parser display thing that Firefox just added,
3:35 let's go look at the raw data, that's not so pretty, it's pretty printed all right so check this out, we've got all of our Opels down here
3:42 I can bet if you count them there's 25 of them you can see the brand, you can see the name, this is basically what was typed into Ebay, what year,
3:50 how much they're asking in euros and importantly the id right here. So this is great, the next thing that we want to implement
3:58 is going to autos/ that id and now it just say it is an auto,
4:06 well it told us that function was called but it doesn't tell us anything that's happening,
4:10 so this was pretty straightforward, right like all we had to do is go to the database and say give me the cars and return it,
4:17 and tell it hey, you serialize that, you return that as json. Now, we got lucky that that is json sterilizable,
4:24 otherwise it would have crashed, we would have to do some work but it's not insurmountable, we can totally fix that.
4:29 This one takes a little bit more work, okay so this one is nice, but I'm supposed to get that car id
4:35 and I can't just do car id that would be nice, Pyramid guys don't do that so the way we're going to get the car ids we have to use the request
4:43 so we'll go to request, and then there's a couple of things that we can get here; here we can basically do a type annotation,
4:56 and now you can see all the stuff that shows up here, this works because it's Python 3, right.
5:01 So I can come over here and I can say well it's got a get, notice this is a dictionary, it's got a post
5:09 which is another dictionary that has the post data, get actually is not the url but this is the query string
5:16 but it also has one called match dict, which is not obvious that that's what you want
5:21 but match dict is where those little route cutout pieces of data go,
5:25 so this is a dictionary, so we can call get on it, and the thing we want is car id, because that's what we called it in our route ok.
5:32 So, then we can come down and we can go to our repository and we can say car=repository
5:40 and it happens to have a get car by id, that's not surprising, is it; so we'll pass the car id, now let's just return the car
5:47 when we make changes to the Python code, we have to re-execute the app so we restarted there, now this is not going to do what we hoped,
5:56 those ids were randomly generated in our little temporary database, it will be permanent in sqlalchemy, but right now they're temporary,
6:03 so restarting the app means that probably comes up as nothing, so if we look at the raw data, it's no, sad face. This is not the desired behavior,
6:12 we definitely don't want to use null as a return value, I'm going to store that there for a second, let's go over and refresh this,
6:18 so that we can get an id, let's go and get this one here and it's going to give us our Opel, but we're going to get Opel Signum 1.3 cdti,
6:30 all right so let's go over here, put that in, now this because this exists in our database
6:37 should come back and boom, there it is, so we took out the raw data pretty printed here is our nice little Opel, and 4700 euros,
6:45 maybe it's in good shape I don't know, I'm not sure if it's a good deal, but there is, it has no damage, that's a good sign.
6:51 Ok, so now we kind of have our API working but as we saw right here, this is not very API friendly,
6:59 we're using the http verbs, we're not using the status codes to communicate that something went wrong, so let's go back and fix this up.
7:09 So we'll come over here and we'll say if not car, so the way the database works and the way sqlalchemy or a mongo engine
7:18 or lots of things would work if I asked for a thing that's not there, it's going to return none, I could have my repository layer raise an exception
7:24 but it doesn't, it just returns none and flows that through. So we're going to come down here and say if there's no car returned
7:30 then we want to somehow send a 404, now we could set the headers and all sorts of funkiness but the thing we really want here is a response,
7:37 we want to import that from pyramid response and notice it takes a couple of things, we can set the body, not interesting
7:45 we can set the status, let's set the status to 404, okay; now by the way, if I go back over here and I look at the headers
7:52 the response headers are, yeah, I don't see where it says whether it's 200 or not but you can bet, it is a 200, okay, even though it's empty.
8:01 So we're going to say this time 404, and what else we want to set, is we want to set the json body, so here we can pass a dictionary
8:08 that has the error, let's say there's an error and this can be the message, so we'll create a message,
8:15 it's going to be the car with id such and such was not found and in case they don't pass one, let's put a little back tick like that,
8:23 so the car id and creating the response is not enough, we have to return it. So if we don't find a car in the database,
8:33 we're going to embrace the http response 404, and we can still send a body by sending some kind of model that represents the error
8:42 so be sure to rerun, refresh, boom- error, the car with id such and such was not found.
8:49 Now if we go over here and look at this, we still don't see the 404, I'll show you in a little bit where we can find that,
8:55 we'll use something other than the browser to pull that up. But if we go over to the raw data, you can see now we've got this error.
9:03 I might be able to do it if I go to the network, here we go, perfect, status 404, method equals get not found
9:11 and even though it's a 404 not found, we're still returning a nice message
9:24 in the front end, something like that. So there you have it, we have our two methods written,
9:29 we don't have our pretty print json we just have the standard minified json renderer but that's ok, we've got our thing that does all the autos
9:36 and the basic sort of hard coded limit and given an id, we can go back here and we can call this function
9:44 by passing / api /auto/id and get an individual car, or not, and get a proper http friendly response or 404 with the error message right there.