RESTful and HTTP APIs in Pyramid Transcripts
Chapter: Content negotiation
Lecture: Realistic accept headers
0:01 So it looks like we have our negotiate renderer working just perfectly. If you look down here, one of the key steps was
0:08 we add an adapter, we add a renderer, we map the content type down here
0:15 to that particular renderer, and that works perfectly, nothing needs to change here. However, this part right here
0:22 turns out to be more complicated, let me show you why. So as we saw if, I come over here and I do a get,
0:28 it's working great, content type equals text/ csv and let's go over here and try this in Firefox.
0:35 Look at this, that's not so amazing, is it? What went wrong? It says could not find a renderer for the content type text/HTML
0:46 application xHTML, application xml and some other stuff. Well then, that's a little bit weird right, and then notice down here */*
0:54 this is the accept all, like okay, fine if you don't have any of those I'll take that.
0:58 But the way this really works is for the header you can say I would prefer this,
1:02 if you don't have that, I'd prefer this, if you don't have either of those I prefer this and I would prefer that with like a certainty of 90 percent ;
1:10 and then finally, at certainty of 80 percent I would prefer this, right. So it's going to say like between these two server you can decide
1:21 you can send me either of those equally, and then this and then this, I think that's how you read it.
1:27 So we can't just take the straight text, we basically need to parse this string into something that's better, right, so let's go here, let's say this
1:37 accept_headers = parse_accept_headers, plural, this function doesn't exist, but let's go ahead and write it.
1:49 Ooops, not function, method, so I'll just write it down here if PyCharm won't help me so deaf parse_accept_headers, header value, okay
1:57 so I'll put this here just to remind you of hey this is what it could look like and what we're going to return, we could even be explicit here and say
2:04 this is going to return a list, so the system up here knows hey you have a list. That means this needs to be self
2:15 and if I had said self, PyCharm would have saved me, but if I go over here now and say this, you can see
2:19 append, copy, like list behaviors, to remind me of that, so we could do regular expressions, we could do all sorts of stuff,
2:27 but let's just do a little bit of low end string work here, so we'll say first of all, if not header value return nothing,
2:34 or empty list I guess is probably a safer thing. Then, we'll say values= header_value.split and we'll split on the comma.
2:45 So we'll get like text/HTML, but we'll also get say */* ;q =such and such. So then say for value in values, let's make a list here,
3:00 so accept types, right, so for each one of these we'll come down here and we'll say parts= value.split on this,
3:12 if length of parts is one, accept types.add, parts zero or just part. Let's do a strip, add this lower, right,
3:33 that's what we're looking for before in our dictionary so let's make sure we do that, so if it's one, but if it's actually two,
3:39 say else, let's be a little bit careful here, if it's two, then what do we want to put in here, not the value, but parts of zero;
3:49 and we're just going to use the order in which they are specified like you can use this q and you can do some sorting,
3:55 but I am just going to say that one first, then that one, then that one, and so on, and we're going to do that by the order in which we add here,
4:02 okay so now we just got to return this accept type and we should be golden, almost, ok.
4:08 So we're up here, we don't want this to be static, I guess we could make it static, but we're not going to, okay, so let's come up here,
4:16 now this bit is not going to work, right, we can't get an accept header by a list those are supposed to be strings, so we'll say this instead
4:24 for header or more accept type in accept headers, plural we'll do this, we'll set the renderer=this and I think I need to change this
4:38 let's change this to be if there's a renderer, we're going to grab the first one and return its value.
4:44 And now, if we make it all the way to the end, and nobody, let's be a little careful here, still use this type,
4:52 so we're going to go through each one of these text, HTML whatever and if we can find one, the first one we find, that's the one we're going to use.
5:01 If we go through all of the options, and we don't find one then obviously, that's a problem I think we got this working, let's try this now.
5:08 So, does it work like it did before— attribute has no value spit, I should hope not where is that— where did I write spit, sorry about that
5:20 you're probably watching it, oh it's spit, it's spit, it's not going to work, no, it's not going to work, alright, try again.
5:25 Okay, there we go, we give it text/ csv, it works fine and we give it json it works fine, we give it images, this is plural it should just crash
5:32 but that's okay, now the problem that we actually ran into, it's over here the browsers can pass more, but now they don't
5:41 it says I'll take all bunch of different things, which one did it use—
5:44 remember it had a whole bunch of stuff, and actually copied it so we can look down here, it said I want text HTML, we say no, don't have that,
5:51 it said okay, I'll take this, next time do the loop, do we have this, next time do the loop, do you have this, no
5:56 and then, next time do the loop we said */*, yes, I have */* and the reason I have */* is we've set the accept all renderer to be json,
6:06 if I set that to the csv one and I run it again, and I do this request we should have csv, and we do,
6:12 tries to download it, sort of annoying, works fine. Alright, let's put that back I don't want csv to be the default, but you get the idea, right.
6:19 So we went through that list and got the different things. All right, now I think we have a very solid negotiating renderer factory
6:26 and I'm pretty comfortable with how it works.