Why Use API Resources0:00
Alright, what next? Why don't we talk a bit more about resources? So to illustrate this, I've created a new, very quick page for Threads. You know, something like a form. And real quick, if you want to take a look at that, it's pretty simple. We accept threads as a prop, and then we iterate over the threads, and for each one we render an article tag. Very very basic stuff. But if we take a look at the controller, you'll see right now I'm not using any API resource or anything like that.
But if we take a look at the controller, you'll see right now I'm not using any API resource or anything like that. I'm running a basic Eloquent query that returns a collection that is then converted to JSON. Which means if we open up Vue DevTools, like so, have a look, yeah, here's what we get. So all the information for the thread, and we also eager load the author. Okay, so instantly, probably like you, I see some issues here. Some security issues, and also just a very heavy payload that's not necessary. So first up, yeah, I'm pretty religious about using API resources for almost everything that I pass to Inertia. You don't have to.
Creating ThreadResource1:07
that I pass to Inertia. You don't have to. You could run an Eloquent query, and then map over it, and return an array subset, that would be fine. But generally, as a rule, I will often have a companion API resource for every Eloquent model. Okay, so let's do that now. php artisan make:resource, and we'll call it ThreadResource. Okay, so now that'll be added to my HTTP/Resources directory, and yeah, what do we want here? Well, immediately we know, at minimum, I need the title of the thread, and actually, let's
Okay, so now that'll be added to my HTTP resources directory, and yeah, what do we want here? Well, immediately we know, at minimum, I need the title of the thread, and actually, let's take a look at this real quick. If I open up TablePlus, and I look at the threads table I created, yeah, you can see a thread consists of a title, body, user_id, you know, your standard demo example that's not quite practical for real life, but good enough for a quick little exercise. So let's do a body. And then I also want the author of the thread. And what you'll see here is on my Thread model, I have a relationship here to grab the associated User.
And what you'll see here is on my Thread model, I have a relationship here to grab the associated User. Okay, let's switch back. And I can say, this author. Alright, so clearly, there's more to do here. But to get us going, let's now swap that over to ThreadResource. And I have an array, so we need a collection of items here. And that's getting a little messy for my taste, we might extract a variable or keep it to something like that. Okay, so now if I come back, and we give this a refresh, I of course still see the same
Wrapping Author in UserResource2:37
something like that. Okay, so now if I come back, and we give this a refresh, I of course still see the same thing because we're passing the same data that the view component needs. But now, and again, that should all be a recap at this point. But now, if we take a look at each of the Thread objects here, it contains exclusively the information that we care about, excluding this author section here. If I expand that, bam, we still have that same User model array dump. So we need to remember to do that as well. Let's come back. And we're going to wrap this within a UserResource.
Let's come back. And we're going to wrap this within a UserResource. So now notice that when it comes to what we pass to our view components, the resource class almost ends up being sort of like the single source of truth. So now if we come back and give it one more refresh, let's see what we have here. Okay, so now we have information about the thread, and then the UserResource. And this is fairly good. But yeah, we still have a little bit of that situation where for each thread, we're passing through quite a bit of data that we will never reference. So I think for your own projects, you have to decide how much a concern this is.
Reducing Relationship Payload4:16
a relationship, every single time you need a new property, you would have to return to the API resource and ensure that you pass it through. So I don't worry about it too much. And yet it's still something to consider. It all depends on the particular use case. So if that is a problem for you, remember, you don't always have to pass through the full relationship. So if it turns out, like we just discussed, all I really need is the author's name, then you have a couple choices, right? You could do something like this, where you declare the subset.
you have a couple choices, right? You could do something like this, where you declare the subset. So $name would be this $authorName. And now if I come back and give this a refresh, once again, we get the exact same thing. But now we have further limited what we are passing to the client. Now another option is, remember, what you pass to the client doesn't have to be a one-to-one mapping of what your database structure is. In fact, they will often not be that way. So for example, if you just want to make this, I don't know, $author or something like that, and then you delegate like this, that would be fine as well.
So for example, if you just want to make this, I don't know, Author or something like that, and then you delegate like this, that would be fine as well. But yeah, let's bring it back to what we had before. And we'll just assume in real life for displaying these threads, you'll need a lot of information about the User. So we'll just pass that through. And this looks pretty good. Okay, but now imagine that in other areas, you need access to information about a Thread, but not quite so much. For example, maybe up here on every page, we'll display what the latest Thread is.
Sharing Latest Thread Globally6:07
And of course, you could use things like Redis for that. But to demonstrate how we can tweak these API resources, we'll do it this way. So let's do this. Let's go into our handle under ShowRequestsMiddleware. And if I scroll down, this is where we can declare, as you surely know, data that should be shared across all views. If every page needs information about the latest Thread. Yeah, let's just, let's play around with this. So if I said thread latest first, and we run an Eloquent query here, if we come back and we take a look at what's being passed right here, give it a refresh.
So if I said thread latest first, and we run an eloquent query here, if we come back and we take a look at what's being passed right here, give it a refresh. There we go. If we take a look at what's being passed, sure enough, I do have information about the latest thread, at which point I could then go into my layout here. Let's have a look here. So this is the header section. And yeah, maybe right here instead of welcome back. So I will say latest thread. And then let's use an Inertia link that would send you to the URI for that thread.
So I will say latest thread. And then let's use an Inertia link that would send you to the URI for that thread. And then let's set the text to what would it be page.props.latestThread.title like so. So if I come back and refresh, sure enough, I can see it's kind of a silly example. But sure enough, I can see the most recently created thread. Something bland it is, consecrator, and it does match up here. Okay. But yeah, all of this illustrates that it's a shame to send through so much data, as you see here, when we only needed maybe one or two fields here. And you can imagine a lot of examples for this.
see here, when we only needed maybe one or two fields here. And you can imagine a lot of examples for this. So if we address this, again, the first step we could do is if I make a habit of always having a resource for an Eloquent model, then I would wrap this. And now if I come back and refresh, it's still going to work. But now I've slightly altered, excuse me, the data that we're passing there. But again, it's still maybe a little bit too much. And again, to keep reminding you, in real life, there would be so many more fields here over time. I run a forum.
But at the time of this recording, which is March 2022, that's not something you can do. Instead, I think Taylor would recommend, well, in that situation, create another resource. There's no rule that there is a one-to-one mapping between an Eloquent model and an API resource. If you need four API resources for various states of a Thread, then that would be fine. So maybe he might say, let's go here, go to the file. What if we were to copy that and maybe have something like Thread. And for situations where you only need pieces of a Thread, like a ThreadSnapshotResource or something like that, then you create another one like this. Now I'm going to tell you right now, I think this is overkill when we just want to display
Okay, so in that case, maybe you only need the title and the body for a thread snapshot. Or the title, maybe not even the body, maybe the title and the author. We could do something like that. Name this author name. All right, so this is absolutely one way to go. The only downside I would say is, I like this approach, but you somewhat lose your single source of truth, if you like to think of it that way. Because now it's being declared here, and then you also have another area where you declare what those attributes are. Maybe not a problem.
declare what those attributes are. Maybe not a problem. Maybe using single source of truth isn't quite appropriate there. But it's something to think about. So anyways, if we come back to our middleware now, I could swap this out with our VariationThreadSnapshotResource. And now you'll see, if we come back and refresh, at this point, what we're passing here for latestThread will now be exclusively the title and the author's name. So that's one way that we could essentially filter down what we pass to the view component. Another way would be to extend your resources in some way.
Adding an Only Method10:46
So that's one way that we could essentially filter down what we pass to the view component. Another way would be to extend your resources in some way. So for example, let's just get rid of this and say we're not going to take that approach. Bring this back. Okay, so what if we could do something like give me only the title and the author? And yeah, of course, you can always implement things like this on your own. So for example, if I go to ThreadResource, we could just create our only method here, where it accepts an array of attributes, or we'll make it an array. And then I can show you a couple ways to write this. But quickest would be, what I want to do here is basically have Laravel resolve this array
And then I can show you a couple ways to write this. But quickest would be, what I want to do here is basically have Laravel resolve this array down to the actual key value pairs. So it needs to evaluate everything, figure out what gets included, what gets excluded. So this is a little behind the scenes stuff, but Laravel has this resolve method that it triggers when we convert it to JSON. And you can see what that's doing here. It converts it to an array, filters down any null values, stuff like that. So if we want, we could just manually call that, resolve it down, and then say, once you've done that, give me only the ones where the keys exist in this array.
So if we want, we could just manually call that, resolve it down, and then say, once you've done that, give me only the ones where the keys exist in this array. And then convert that back to an array. Yeah, and I think that actually would do it. Let's have a look. Take a look at this, and to latest threads. And sure enough, we have only the title and the author, as you see here. And yeah, now actually, as an example, if you wanted to, this is where you could extend it quite a bit to maybe support dot notation. Give me the title, and then the author and name.
But if you ever take a look at it, all it's really doing is calling, well, it's preparing. It's figuring out what keys you need. And then it's just passing that to array_only. So if you want, we could do that ourselves. array, Illuminate\Support\Arr::only. And then we'll say $this, resolve, and then $attributes. And yeah, I mean, that's basically the same thing, and we don't have to wrap it in a collection. Come back, refresh, and we still get the same thing. All right, so I'm just giving you a bunch of different ideas for how, if you ever run into this situation where you want to tweak an API resource, maybe your default API resource.
All right, so I'm just giving you a bunch of different ideas for how, if you ever run into this situation where you want to tweak an API resource, maybe your default API resource is returning 50 different fields, but on certain pages, you only need to return five or 10. Well, now you have a couple different ideas. You could either create a brand new Resource class entirely that matches that particular use case, or you could kind of hack something like this. You probably need to tweak this a little bit, but you could do that as well. You could even create a base Resource class like that, where you have your only method. And then any of these could extend your base Resource like so, get rid of that.
You could even create a base resource class like that, where you have your only method. And then any of these could extend your base resource like so, get rid of that. And yeah, actually, if I come back, we would need to make sure that your base resource then extends Laravel's JsonResource. Okay, so now we've introduced a new base resource class, where if you ever do, again, need to add unique functionality, maybe in your toArray method, there are certain cases where if a certain condition is met, that's a little tricky. Well, now you have a place that you could put that, and you're still going to get the same thing.
