API Exposes Sensitive Fields0:00
In a traditional web app, having sensitive data in your models isn't usually a problem, because the content of the models isn't sent to the browser. But when we start talking about APIs and SPAs, single-page apps, the line gets blurred, because you're passing the full bottle into the browser. Okay, so we're here in our code, and this is our api.php routes file, and here we have a really simple API route called Books, and all Books is doing is returning all of the published Books. So it's a really simple route, and this is the sort of thing that you would see in a really simple app, where we're just sending all of the data over the API. Let's have a look at what that looks like in the browser.
really simple app, where we're just sending all of the data over the API. Let's have a look at what that looks like in the browser. Okay, so here in the browser, we have the output of that API call, and we can see here we have the three different Books that have come through, and we've got a bunch of information about them. We've got the ID, the User ID, the Key, Slug, Title, Description, Image, PublishedAt, CreatedAt, and UpdatedAt. But the problem here is we have the Key attribute, and the Key attribute could be considered sensitive. It probably is, given its name and what it contains, it's probably used as some form
Hiding Model Attributes1:17
But because it's being included, sorry, because it's on the model, and there's no protections in place, it's being sent to the browser, along with everything else. We want to stop that. We don't want to send that Key value to the browser. We don't want the user to be able to access it. So what can we do here? Well, we'll jump over into our model, and we'll add in the hidden attribute. Okay, so we're here in our Book model, and as we have explored in a previous episode, we have the fillable field there, which defines which fields can be filled. We can also add in what's called a hidden attribute as well, hidden property, I should
we have the fillable field there, which defines which fields can be filled. We can also add in what's called a hidden attribute as well, hidden property, I should say. So do protected, hidden, then I'm going to do key. So that's all we need to do, is we can add in a simple array attribute onto the model called hidden, and we list all the different attributes that are hidden, that shouldn't be included on the model when it's sending it to the browser. So we'll jump back to the browser. Okay, so we're in the browser, and I'm going to refresh the page. And as we can see, the key has now disappeared, because we've now marked it as hidden.
How Hidden Works2:05
Okay, so we're in the browser, and I'm going to refresh the page. And as we can see, the key has now disappeared, because we've now marked it as hidden. And so it's now safe. And so by setting all of the sensitive attributes on the model in the hidden array on the model, any time the data is sent to the browser like this, it won't be included, which keeps it nice and safe. So how is that working under the hood though? Because it's always good to understand how these features work, to get a better idea of what's going on. So we'll jump over into the route, and I'm going to throw a dd, and then we'll look.
of what's going on. So we'll jump over into the route, and I'm going to throw a dd, and then we'll look at what's actually arriving in the route, and see what's there. Okay, so I'm in the route here, and I'm just going to add a little dd in here on the end of this collection, and then we'll jump back to the browser. I'm going to refresh the page, and as we can see, we've got an array which has the three books. And if we open up the first book, we can see here under Attributes, it has the key attribute. So when it's loading the model from the database, it's loading all of the information, so the attribute is there.
So when it's loading the model from the database, it's loading all of the information, so the attribute is there. And we can use it, we can manipulate it, we can work with it in our code. And so when Laravel translates this model into an array, or into JSON, in order to send it into the browser as part of the standard route handling, it reviews, it looks at what's in hidden, and it excludes that from the attributes that it sends out. Which is why it wasn't there when we had the API call. But it's here now, it's on the model itself. So that's one way to do it, but what if we don't want it loaded at all? What if we don't want this attribute in the code?
Selecting Specific Columns3:25
So that's one way to do it, but what if we don't want it loaded at all? What if we don't want this attribute in the code? What if we just want to extract and return the fields we want to display on the screen? Well, we can do that too, so we'll jump back to our routes file. Okay, so in our routes file, what we wanted to do is to only return the specific information we want on the API response, rather than loading everything and then filtering. Because we also don't want all those other fields, there's a bunch of noise in there we don't really need. So instead what we can do is we can actually do it on the query level itself. So we can add select in here, which is basically adding a select clause into the database query.
So instead what we can do is we can actually do it on the query level itself. So we can add select in here, which is basically adding a select clause into the database query. Then I want slug, I want title, description and image. So we only want those four fields to come out in the API response. Then when I go back to the browser, and we go to refresh the page, we now get only those four. Because we've only loaded these from the database. And if we did a dd now, we would see that it would only contain those in the model. Because that's all we told the database, all we included in the database query. So there are two simple ways of filtering the output and protecting sensitive information.
Creating API Resources4:26
Because that's all we told the database, all we included in the database query. So there are two simple ways of filtering the output and protecting sensitive information. But there's another way that's really useful, especially if you do a lot of API work, or if you're running an SBA. Which essentially you've got an API behind your SBA. And that is called an API resource response, which Laravel includes as part of its standard framework. So in the console we can create a new resource response class, and then use that to return only the information we want to return via the API. So php artisan make:resource BookResource.
Using Resource in Route4:54
only the information we want to return via the API. So php artisan make:resource BookResource. That's going to make my resource class, and then we'll jump back into the code and open up the class. Okay, so this is our newly created BookResource class. And as you can see here, it comes with a single toArray method, which is the method that it uses to translate the resource, the model in this case, to an array to return via an API. So we'll get rid of the parent::toArray here, and instead what I want to do is do our slug. And we want this slug, and I also want title, description, and image.
So we'll get rid of the parentToArray here, and instead what I want to do is do our slug. And we want this slug, and I also want title, description, and image. So I'll just do a quick replacement of these. And then image. Okay, so what we're doing here is we're telling the BookResource to only return slug, title, description, and image for this model. So now we'll jump to the API route and we'll update that. Okay, so in the API route we can get rid of this. What we can do here is BookResourceCollection, and then I'm going to wrap this in here like so.
What we can do here is BookResourceCollection, and then I'm going to wrap this in here like so. I'll just simplify that. Okay, cool. So what we've got here now is we're grabbing all the published books and we're passing them into the BookResourceCollection static class, static method. And then that's going to use the BookResource to render our response in the API. So we'll jump back to the browser. Okay, in the browser I'm going to refresh it, and now we should see a very similar output. We'll notice it's actually added data in here, and that's just part of the API syntax that
Okay, in the browser I'm going to refresh it, and now we should see a very similar output. We'll notice it's actually added data in here, and that's just part of the API syntax that it's using when it's outputting information. But ultimately the information it's still giving us here is the same. We've defined those four fields in our BookResource class, and these are the fields that it's displaying on the page when it's rendering the page. And the benefit of using a resource response like this is it means you don't need to worry about hidden attributes or selecting specific values in your routes or using other tricks in your routes. You define in your resource class what is safe to go in the API, what attributes for
in your routes. You define in your resource class what is safe to go in the API, what attributes for that model are safe. And then any time you load that model, you use the resource, and then that worries about the responsibility. So your routes, your logic doesn't have to care about the permissions, about the visibility of the attributes. It just does its work and then it passes it off to the resource, and that's the bit that cares about the attributes. So if you're using an API, then definitely check out the resource responses.
