RESTful and HTTP APIs in Pyramid Transcripts
Chapter: Customer Renderers
Lecture: Adapting non-standard types
0:01 So we have this csv renderer working super well right here. However, one thing that is really not nice about it is this bit about, if it's a car right,
0:12 we should not have to embed into the renderer knowledge about these types, they should be separate they should be disjoint.
0:20 So, how do we do that? Well let me comment this out for a second and just show that it's not going to be so much, okay, let's accept the csv type,
0:29 you can see that that is not great, right there, right no attribute keys car has no attribute keys we saw this before;
0:37 so how do we address that problem? Well,one would be you could just say look the csv only takes dictionaries
0:43 so in our api here, I could say all right, well instead of returning cars what I'm going to return is we'll just do a little list comprehension here
0:52 and the list comprehension will convert a list of cars to a list of dictionaries, so we'll say car for car in cars, what are we going to do the car
0:59 we're going to say to dict, right, that would actually work; so if a rerun this, and re-request it, things should be back to good.
1:05 So that's one possibility, like you tell the renderer, like the renderer just has these limitations
1:10 it only takes dictionaries and lists of dictionaries; on the other hand this is also sort of polluting our api
1:16 how did we solve this with the json renderer— what we did was we added an adapter, so adding an adapter that given a car it knows how to transform it.
1:25 Let's go and add that here, like this. Let's tell it that it has an adapter and you know what, it's probably going to use exactly the same type, okay,
1:35 so obviously this method doesn't exist, but PyCharm is happy to write it for us,
1:39 this will be type, let's just call it class like we're going to adapt from this and this will be a method, okay,
1:49 so let's go and say this object is going to have initializer, and in here it's going to have a dictionary of things that it can use called adapters.
2:01 And down here, we'll just say into this adapter by the type of the object that we're going to pass in
2:08 so car or whatever, we want to use that as the hash and we got to put in the method.
2:13 So you give me a car here's the method to call and get the car back out, you're going to give me some other type, you know, a customer or a user
2:21 here's the thing to call to convert it to something we can deal with which is either straight up dictionaries or a list of dictionaries.
2:29 Now, the next thing we need to do is somehow take this general stuff that we're doing or this specific stuff
2:35 and make this more general, let's select all of this and make this a method so we'll call this adapt type, it's going to take the value
2:44 and it's going to return back something and maybe this looks like that's kind of part of this adaptation stuff here
2:51 ok so we want to come in and we want to say well if it's one of these things now how do we generalize this, right, we have this adapter dictionary
2:58 and somehow we need to convert it so here this question basically says is that a type that you know how to adapt
3:04 and then this will say okay we'll convert it to a list of that thing adapted all right let's try to create a generalized equivalent,
3:12 so we'll say if type of value is in our adapters, that means there is a function that we know how to change this
3:20 right, so than we'll say value equals now we just need to adapt the value so we'll say self.adapters, make this little simpler up here,
3:28 like we don't want to keep typing that and keep computing that, so we'll give that, and the adapter takes—
3:35 actually I think that adapter takes two values and it returns back the adapted value. Okay, so before we had it hard coded to just the car,
3:45 and now we have this dictionary of adapters which have a bunch of types, not just car potentially and they have functions which we can call
3:54 their value is a function which we can call that returns the adapted thing, this is because we want to get everything into a list of stuff.
4:04 And then, we are going to do this and now we're going to come here and say okay, same thing, but really this value is basically the same
4:11 so we want to create the type of the first item and we could even maybe say
4:15 alright, we're just going to assume the type is the first one and not recompute this
4:18 but we're not worried about performance, yet, let's just get this working. So then we're going to ask is the type in there
4:24 and then how did we have this before, we had a value of index and then we ran the adapter function on item, like so.
4:32 All right, so if we run this now and we undo this, just return cars again, what are we going to get, not something amazing, car has no item keys;
4:46 why did this happen— well just maybe you know in our minds we're like oh we could have an adapter for cars right
4:52 did we add it, oh it looks like I made a super small mistake here look on line 50, what do you think that comes back as—
5:01 well on line 48 we know it's a list, and a list is not what we're looking for,
5:04 we just really wanted to have the first value like what does the list contain so let's make this and call this first, just so it's really clear
5:12 and let's actually move that outside of the list here that will also be better for performance and we could also say adapter equals, put this up here
5:25 we'll stay if not, I'll say if adapter, I think that's a little nicer. No reason to compute that over and over and over again, right,
5:32 just once and then call it on every item in the list; okay, let's try this again. Send, key error list, where are we getting this list error?
5:47 Oh I just copied this, this should be type of first and we don't need that again, like this, ok try one more time,
6:03 yes, okay they do want to value there but obviously this is not none, alright, look at that how cool, sorry about the little glitch there
6:14 but this is working beautifully, if we go over here you can see down here we've got our csv coming through
6:22 and in the api side, remember what we did was we are just now returning a list of cars
6:30 we kind of fixed it by letting the renderer be dumber at the beginning but then we said no no let's actually let it return arbitrary objects
6:38 and long as somewhere in the system we tell it like hey if you have a car
6:42 here's how you get to a dictionary and once you have dictionaries or lists of dictionaries you can totally deal with that, and the way we taught it was
6:49 we added this adapter, just like we did for json, in fact, it's highly inspired by the way the built in one works
6:57 that you can add this adapter it looks it up by type and so on. We'll see that this is really nice because while you might look at this and say
7:05 you know this is no big deal, like we can just do that, right, I don't need all this complexity of adapting types and whatnot;
7:11 it turns out that sometimes you really do need it, it's great to just do it on line 15 but any time you return to car down here, down here,
7:20 all of these will have to do like this translation and then what if you want to change how that works or something,
7:26 it becomes you know, sort of something that works its way through all the parts of your api and it's better to just have this one place,
7:32 right here we say if you need to take a car to a dictionary teach a renderer to do it, it goes there, just like it was really nice to do this here,
7:42 and then we could return arbitrary objects involving cars or lists of cars and so on and the json renderer would deal with it, same thing here.
7:49 So let's just review our adapt type function here. We're given some type and we may need to change it into another type right,
7:57 we saw we're given an individual car we need to convert that into a list of cars; if we're giving a list and it's not a list of dictionaries
8:06 we need to convert it to a list of dictionaries. So we set up this adapter concept, we can register many things
8:11 that can be converted to dictionaries, and then we just go through and say look if the type of this thing that we're working with,
8:18 if it's an individual instance not a list and we could convert it, then we're going to convert it to a list of one item by adapting that value.
8:26 But if it's a list, let's go through every item in the list and make sure that it is something we can work with,
8:31 so here we get the first one and we say do we have an adapter in this case it's a list of cars, and it says yep I know how to convert cars
8:40 so it just goes through the list assuming the list is homogenous, one thing I suppose would be fun to test is if we go up here to the top again
8:48 and just show that we can still return other types still show that we can return this list of dictionaries
8:54 and that somehow won't break the system, I don't think it will, let's find out. Yes, yes it did break it; where did it break— all right,
9:01 yes, this seems to be a get, so what do we do wrong here— on this one, we are basically assuming it is in here
9:11 and of course, why would we test for it, if we were doing that so let's do the more gentle friendly get me this type
9:17 and then we're already testing for it. So one more time, boom, we're returning dictionaries and so it's you know, I don't need to adapt dictionaries,
9:25 you already can work with those. If we change this to say no, no, return cars, we go return cars, okay.
9:32 So now, we have or csv entirely built in a general way right, the csv as far as its work goes, all it really cares or knows about are dictionaries
9:44 and maybe we want to put some kind of test in here and say you know, I was given some type, I don't know about it
9:50 and it should raise some type of exception, right, so we have this, maybe let's go ahead and say first equals value of zero
9:58 say if not is instance first dict, well then we have a problem, it could not convert type or something like that
10:09 and maybe we'll just say what the type was here all right, a little better error message, we'll do a type of first, so it should still work
10:21 and then maybe we can send it something that it doesn't expect just to show you know, it's going to be able to detect this
10:29 so let's return a list of tuples let's say, it shouldn't know what to do with that, let's try this— built in error could not convert type class tuple.
10:39 Perfect, so now I think we've got a pretty good system here make sure l put it back for you in a way that works, excellent.
10:46 Okay, so we've built this custom csv renderer, we've used this adapter concept to give it lots of flexibility
10:54 to take many, many different types and not force all the ways in which we use it through our application to know that that transformation is required
11:02 we just add the adapter in the site setup and we're golden. So while this is fun, let's actually add one more type, let's work with images as well,
11:10 so we'll be able to go to the car and say hey car I would like your image.