Heads up! To view this whole video, sign in with your Courses account or enroll in your free 7-day trial. Sign In Enroll
Preview
Start a free Courses trial
to watch this video
The last step in creating a working API is controlling what data comes out of your API. You may need to take different data in than goes out or you might want to change how certain fields are created before they're sent to the client. Flask-RESTful's marshalling function and field definitions are the key here.
We have resources,
we have routes and ACDP methods.
0:00
We have input validation.
0:03
Our basic API only needs
one more piece added to it
0:04
before we can start experimenting with it.
0:08
We need to finish out
the request response cycle and
0:10
create some useful
responses from our methods.
0:13
We'll do this through marshalling,
which is similar to serializing.
0:16
Basically we wanna take a Python object,
like a string or integer, and
0:20
turn it into something that we can
send safely over the Internet.
0:23
Most of the time this is
really straightforward,
0:27
but you wouldn't need me if there
weren't a few twists and turns.
0:29
Let's check it out.
0:32
So first of all, this video uses a new
workspace because of the review arguments.
0:35
So be sure and relaunch it if
you haven't done that already.
0:41
I wanna show these real quick.
0:44
So for ReviewList,
we have an argument called course which
0:46
is of type inputs.positive cuz
it has to be a positive number.
0:50
It's required and there's the help.
0:54
For rating I did an input of
type int_range from 1 to 5.
0:57
It's also required so like that.
1:03
You can check out all
of these in the docs.
1:05
I have put a link in the previous
video to the inputs and
1:08
I'll put one in this one as well.
1:12
And then we also have comment which
is not required is nullable and
1:13
has a default of an empty string, so cool.
1:18
The last thing the API needs for
1:22
right now at least, is a way to send
back real actual data from the database.
1:24
And to create and update actual database
records, and delete them of course.
1:29
So basically, well, everything.
1:34
But none of that is that difficult.
1:37
Before I can send back data
I have to tell Flask RESTful
1:40
what the data should look like.
1:43
I have to specify how the input
looks with reqparse and
1:45
how the output looks with, this is
actually a little bit disappointing.
1:48
But just with a dictionary.
1:53
First though, I have to come up here and
import this fields module.
1:55
And then I do a thing on here.
2:00
So this dictionary is going to describe
all of the fields that I want to include
2:02
when my API gives a resource.
2:07
I'm doing this inside of courses because
that's the one I like to start with.
2:09
So I'm gonna say the course_fields, these
are all the fields that describe a course.
2:12
So we're gonna have the id and
that's gonna be an integer.
2:19
We're gonna have the title
which is a string,
2:23
we're gonna have the url
which is a string.
2:27
And that one's a little surprising and
I'll talk about that in just a second.
2:30
And we're gonna have reviews
which is a list of strings.
2:33
Now you might be wondering
about a couple of these,
2:39
why did I use fields.String for
the url instead of fields.url?
2:42
Fields.url totally exists, you can look
through the docs which again, I will link.
2:47
It's totally there, it exists.
2:51
But fields.url usually represents
an internal URL in the API, so
2:54
it's a point to another record.
2:58
I want to just return whatever
URL was saved for the course and
3:00
so that's why we're using string.
3:04
And this last one review is a list,
yeah, it's a list of strings.
3:07
But why a list of strings when I just
said that I can use the url field
3:14
to reference another endpoint.
3:18
Flask RESTfuls, lists and url fields
don't seem to play nicely together.
3:20
I could not get them to do what I wanted,
but this one worked and was fairly easy.
3:24
So this is the way that I'm
recommending you do it.
3:29
All right, so now I'm gonna update this
get method down here on course list.
3:33
I'm gonna have it get all the courses.
3:38
So courses = models.Course.select,
so that'll pull out all the courses.
3:41
And I'm gonna return, 'courses' : courses.
3:47
Now this is a good start, but let's
go see what happens when we get this.
3:55
Actually know what?
4:02
Let's use Postman, because that's
what we're supposed to be using.
4:02
All right.
4:08
So let's get that.
4:10
And look we've got TypeError,
it's a little hard to read here but
4:11
you can see that we have a TypeError.
4:14
See if I do preview, there we go.
4:17
So TypeError Course SELECT, blah, blah,
blah, blah, blah is not JSON serializable.
4:18
So we can't turn this into JSON,
4:24
fair enough, so how do we handle that?
4:29
Well.
4:34
Flask RESTful has two methods,
I'm gonna put
4:35
all these into, just getting awfully long.
4:40
All right, so we have two things here,
we have marshal and we have marshal_with.
4:45
And we're gonna need both of those, so
marshal and marshal_with is a decorator.
4:52
And it works just like marshal does, but
4:59
it allows you to not have to do
a certain little bit of work.
5:02
So we had to bring in those two.
5:06
So now when you're using marshal,
you provide it the record or
5:08
records and the fields that
you defined for that resource.
5:12
So I have to do that for
each of the records.
5:17
So what I'm gonna do here is
let's make a new thing and
5:20
we can say courses = marshall course and
5:25
course fields for a course in that.
5:30
That line's way too long, so
I'm gonna break it there.
5:35
All right, so marshal all of these things
for every course that's inside of this.
5:40
And then we're gonna return that.
5:45
So now, let me test this again real quick.
5:47
And check it out, we got our information.
5:51
So cool,
we got back pretty much everything.
5:54
The reviews field is null which
is probably because there's
5:57
not actually a reviews
attribute on the model.
6:01
And we don't have any reviews yet either.
6:03
There are couple of different ways that
I could solve not having any reviews on
6:06
the model.
6:10
I could have property to the model,
have a property defined named reviews.
6:12
And then that goes and
fetches all the reviews but
6:16
that makes the model and
the API tied together pretty tightly.
6:19
And I don't necessarily want them
to be super tightly coupled.
6:24
I could also turn model
instances into dictionaries and
6:27
then add a key which works.
6:31
Or I could do what I'm gonna do and I'm
gonna add an attribute to each instance.
6:35
Now, why do it this way instead of
the dictionary or model approach?
6:39
Like I said,
6:43
the model approach requires the model
to know about the API as a limitation.
6:44
I don't like that,
it's way too tightly coupled.
6:47
The dictionary one and
6:50
the attribute one that I'm gonna do,
those are pretty much interchangeable.
6:51
So you could pick whichever
one of those you like better.
6:54
I just happen to think the attribute
is a little bit cleaner, so
6:57
that's the way I wanna do it.
7:01
So I'm gonna add a new method up here or
functions,
7:03
sorry, function while not method.
7:07
That's gonna be called add_reviews and
it's gonna take a course.
7:11
And then I'm gonna say course.reviews,
so I'm gonna make a new attribute.
7:14
And then I'm gonna use
the url_for method and
7:18
I'm gonna say resources.reviews.review.
7:21
So that's going to that end point.
7:25
And the id is gonna be equal to review.id
for review in course.review_set.
7:27
And then I'll return the course.
7:35
And again this is long,
so let's break it there.
7:36
That still feels kind of long, but it
says I'm only at 72, so that's all right.
7:42
I need to import url_for and
this actually comes from RESTful.
7:47
But I think you can use the one
that Flask provides as well,
7:55
I don't believe it matters
which one that you use.
7:57
And then I need to use this method,
so I'm gonna marshal course but
8:00
first I'm gonna do add_reviews to course.
8:04
Okay, cool, so we're gonna pass
the course in the add_reviews,
8:07
which adds the reviews and
returns the course.
8:11
And then we're gonna pass the course into
marshal which finds the reviews thing.
8:13
That makes sense?
8:18
It all just functions all the way down.
8:19
All right, so
now let's try requesting this again and
8:22
reviews is now an empty
list as it should be.
8:26
So awesome.
8:31
So that's the place where
reviews are gonna go.
8:32
All right, so now I want to do,
I'm gonna ignore post for now.
8:34
I'm gonna come down here and
I'm gonna do the get for a single course.
8:38
So I'm gonna use marshal_with for
this one, so
8:43
I can show you how the decorator works.
8:47
But before I do that,
I need to have a way to get a course or
8:49
to throw a 404 if that
course doesn't exist.
8:53
So let's come up here and
add another method.
8:56
And we'll call this course_or_404 and
course_id.
9:00
Sorry, I need to import more thing,
I need to import abort.
9:06
Which abort just
immediately ends a request.
9:10
All right, so we're gonna try
course = models.Course.get,
9:14
models.Course.id is equal to
course_id that was passed in.
9:19
Except models.Course.DoesNotExist.
9:26
So if the course doesn't exist,
then I'm gonna run the abort function with
9:30
a status code of 404 and a message that
is Course something does not exist.
9:36
And I'll format that with
the course_id that they provided.
9:45
Otherwise, return the course, okay?
9:49
Really straightforward function there.
9:54
So down here, let's do return add_reviews,
9:58
course_or_404 and
then the id that gets passed in.
10:03
And then we decorate this method
with @marshal_with(course_fields).
10:10
So what this will do is this ends
up returning a single record.
10:17
And so the marshal_with takes that record
and marshals it using those fields.
10:22
So the exact same work we did before,
10:27
we could totally just do marshal and
course_fields like that.
10:31
But doesn't really matter,
[LAUGH] one way or the other.
10:37
They're equivalent,
they're the exact same idea.
10:45
Marshal_with is really meant to be used
when you're returning a single thing.
10:47
And marshal becomes more useful
when you have to sort of
10:50
work on the model instance
before it comes out.
10:55
Or you have to work on a lot of
model instances all at once,
10:58
it seems like marshal's easier to use.
11:01
As you build these APIs, you'll start to
be able to predict which one you should be
11:04
able to use whenever you're
building a method or whatever.
11:08
So I added a course in the last video,
which means I should be able
11:12
to go over here to /courses/1 and
get that course back out.
11:17
And check it out, there's
Python Collections and there's the URL, so
11:25
I got it.
11:29
Let me make sure that my 404 thing works,
I'm gonna go to /2 which should not exist.
11:30
And yeah, it doesn't exist.
11:35
And it got an unexpected keyword message.
11:40
Does abort not expect message?
11:43
Well, you know what let's just take
that off and we'll just say 404.
11:46
So send that and cool, we got a 404 and
11:51
the request url is not
found on the server.
11:54
So great, that's what we want.
11:57
Now, I want you to see if
you can do something similar
12:00
to what I've done here for
courses to both ReviewList and review.
12:04
Just for the get and
maybe a post method if you want.
12:08
In the next video,
I'll show you my version of those and
12:12
we'll talk about put,
delete and adding some headers.
12:14
You need to sign up for Treehouse in order to download course files.
Sign up