Optional Include Parameter0:00
In the last episode, we implemented this includes property on our Ticket resource and I think that this is great. I think we need to do that. However, I think that the client needs to opt into that because it does add size to the payload and the client might not necessarily want that information with every request for a ticket. So I think we need to make this optional. So we can do that very easily by just adding an include query parameter. We could just say for the ticket, we could include the author because that's what we would want to do and then we would include that author information.
We could just say for the Ticket, we could include the author because that's what we would want to do and then we would include that author information. So then the question becomes, how do we implement that? I think the most straightforward thing to do is to just have something like this inside of our controller so that we could have a method called include and we could check to see if the author was included or part of the request, I should say. So the client is requesting that we include the author and if so, then we could provide our ticket information with the user relationship and that would work. There are many different ways that we can implement this, but I think the two most viable ways would be to use a trait or to just use a base class.
Create Base ApiController1:23
There are many different ways that we can implement this, but I think the two most viable ways would be to use a trait or to just use a base class. We've used a trait, let's use a base class just for kicks. So let's create a new controller. We'll use php artisan make:controller to make the controller. We will version this API V1 and let's just call this ApiController. We don't need to use any of the other flags. We just need basically an empty controller so that we can add this include method and then we could use that in all of our other API controllers. So let's create this include and there's probably a better word that we could use for the name.
then we could use that in all of our other API controllers. So let's create this include and there's probably a better word that we could use for the name of the method, but one of the hardest things to do is name things and I'm horrible at it. So we're just going to call it include and we will accept a string, which let's call this relationship just because we're going to have the word include used a lot. So let's just call this relationship. We will say that it will return a Boolean value. So let's first of all get the include parameter. So we will do that by getting the include query parameter from the request. And let's check if we don't have that parameter, then there's really nothing to do because
So we will do that by getting the include query parameter from the request. And let's check if we don't have that parameter, then there's really nothing to do because there's nothing to include. So we will return false and we're done if that's all that we need. However, we do need to check to see if the parameter that was provided is the same as the relationship that was passed to this method. Now I kind of want to think ahead, but I don't want to think too far ahead because I'm thinking that at some point in time, we might want to have the ability to include multiple relationships. So the client would provide a comma separated value for the relationships. I think it's good to plan for that, but we're not going to completely implement that.
Parse Include Relationships3:22
So the client would provide a comma separated value for the relationships. I think it's good to plan for that, but we're not going to completely implement that. So let's do this. Let's say that we'll have the include values and we are going to take the value from the parameter and we're going to explode it. But we also need to normalize all of our strings. So let's convert this to lowercase so that then we can check to see if the provided relationship, which we will need to normalize as a lowercase string, is inside of the include values. So yeah, I think that that's going to work. Let's go back over this.
So yeah, I think that that's going to work. Let's go back over this. So we will pass in the relationship. We will get the include query parameter from the URL. If that is not set, we return false. Otherwise, we explode that query parameter value, just kind of planning ahead a little bit, and we normalize that to a lowercase string so that then we can check to see if the provided relationship that we also convert to lowercase is inside of that array. Yeah, that looks great. So now we can go to our TicketController, we can inherit the APIController, and that
Conditionally Load Ticket Includes4:40
Yeah, that looks great. So now we can go to our TicketController, we can inherit the APIController, and that should work. So let's copy this code. Let's put this inside of our show method because we essentially want to do the same thing except that we just want to return a single Ticket resource, which in this case, we will call the load and then specify the name of the resource or the relationship there. So as far as that is concerned, we're good. We need to go to the TicketResource, and we need to conditionally show the includes only when we have a User to display.
We need to go to the Ticket resource, and we need to conditionally show the includes only when we have a User to display. And thankfully, this is very easy to do because we have a method kind of like the wins method that we used and the mergeWins method. We have a method that will check to see if we have a loaded relationship. So here, we still have the includes. We are still newing up our UserResource, but we aren't passing the user relationship. We are checking to see when that relationship is loaded. And when it is, then that resource will be loaded for the includes key inside of our JSON structure.
And when it is, then that resource will be loaded for the includes key inside of our JSON structure. Otherwise, it will be completely omitted. So let's test this out. Let's send the request for our tickets, and we see all of our tickets. If we scroll on down, we see the includes. Now let's remove the include, and let's see if that is still going to work. And yes, it does. We see the include is no longer listed there. And of course, if we go to the tickets URL, if we send the request without the includes,
We see the include is no longer listed there. And of course, if we go to the tickets URL, if we send the request without the includes, same thing. All we get are the tickets. However, let's include the author, and now we should see the included information for each individual ticket. And we do. So that's great. Now we just need to implement this for our users. So let's start with our UserController, because we need to inherit the APIController.
Add User Tickets Includes6:47
Now we just need to implement this for our users. So let's start with our UserController, because we need to inherit the ApiController. Then inside of our index method, we want to call our new include method. And in this case, we need to check the tickets resource. So if tickets are being requested, then we will return the user collection. We will call with tickets, which we need to set up that relationship, I believe. I don't think we've set that up. So we'll do that here in a minute. Let's copy this. Let's go down to the show method, and let's put that there.
Let's copy this. Let's go down to the show method, and let's put that there. We will need to return a new UserResource, and we will want to load the tickets. So let's go to our User model, and let's add that tickets relationship. So this is going to be a hasMany relationship, and we will simply return this hasMany tickets. So now the only other thing that we need to do is go to the UserResource, and essentially do the same thing. We need that include. So we will have includes. Now this is a collection of tickets.
So we will have includes. Now this is a collection of tickets. So we will use our TicketResource collection method, and then we will call the whenLoaded method, passing in the tickets relationship, and that should get us what we need. So with that in place, let's go back to Postman. Let's go to our users request. Let's send a request without the include query parameter. And sure enough, we don't see that. We just have the user information, but let's include the tickets. And now we should see the ticket information included as well.
We just have the User information, but let's include the tickets. And now we should see the ticket information included as well. Now notice here, though, that we are getting the ticket resource. So we see the attributes, and I think that that's fine except the relationships. We are getting the author information, which we already have the author information. So that might need to be something that we think about. I think for right now, we can leave that as is, but we might have to revisit that at some point. Let's do this. We need another request for an individual User.
Let's do this. We need another request for an individual User. So let's create a new request for that. I will call this simply getUser. The URL will be essentially the same except that we will get the User with an ID of one. We don't need to set the authorization header, but we do need to add the accepts header that is application/json. So whenever we send this, we should get the individual User and includes and all of the tickets, and we do. So that is working great.
Standardize Resource Links9:39
tickets, and we do. So that is working great. Now one other thing that I want to implement, we have the links, but that's for the ticket. We need to add links for our User. And something else that I want to do, let's take a look at the paginated structure. And we'll see that, you know, there's this links, but it is slightly different than what we implemented from the JSON API. If we take a look at what we did, we have links, which is an array. And then there would be an object for each individual link. And what Laravel is giving us with the paginated results, links is just an object where the
And then there would be an object for each individual link. And what Laravel is giving us with the paginated results, links is just an object where the individual links are properties and values. So I want to follow along. I want everything to be consistent. So let's make a few changes. Let's go to our TicketResource and let's change the links here. We don't need an array of arrays. We just need an array. We'll do the same thing for the user link, which we need to implement, which we can do.
We just need an array. We'll do the same thing for the user link, which we need to implement, which we can do now. Let's take the code for our ticket link and let's just make a few changes here. So we want to use the users.show route, the user key, and then the value will be simply userId. And I think that's the only links inside of our ticket resource. So let's go to our user resource. Let's add in that links there. We will simply need to change this to use the users.show, and then the key is user.
Let's add in that links there. We will simply need to change this to use the users.show, and then the key is user. All right, so that should get us. We are now successfully including information based upon the client's request. All they have to do is provide an include query parameter, specify what they want to include, and it will be included. Our links are all consistent now. And so in the next episode, we can look at how we can start querying and filtering data.
