Omitting Fields by Route0:00
Different routes typically need to return a different response, even if we are working with similar resources. Like, for example, the show and the index routes for our TicketController, well, they work with Tickets, but they, of course, show different information. And I would make the argument that for the index routes, we don't need the description, primarily because if a client is making a request for a collection of Tickets, well, the more pertinent information is title, status, things like that. The description isn't something that the user or the client would want to display when requesting a list of Tickets. So I want to remove the description attribute for everything but the show route.
Conditional Fields with when()0:45
a list of tickets. So I want to remove the description attribute for everything but the show route. Now, we can approach this in a couple of different ways. The first is to just create multiple resources, and yes, that would work. No, it's not what we want to do, primarily because then we have multiple files that we have to keep track of, and no. So thankfully, the JSON resource class gives us several tools that we can use to conditionally omit or include information. For example, there's a method called when, the idea being that when the condition that we pass to the first argument, like when the route is tickets.show, then we want to include
For example, there's a method called when, the idea being that when the condition that we pass to the first argument, like when the route is tickets.show, then we want to include the value that we pass to the second argument, which would be the description from our model. And it would only be included when that condition is true. So therefore, the description is now going to be omitted for the collection of tickets. If we make that request, we can see that it is no longer listed there. But whenever we make a request for an individual ticket, we can see that it is still included. So it's nice and easy, it's straightforward, it's easy to read, and that's the most important thing to me because we don't have a bunch of if statements or anything like that. It just kind of flows in with the rest of our structure.
Scaffolding Users API2:12
thing to me because we don't have a bunch of if statements or anything like that. It just kind of flows in with the rest of our structure. Now I also want to include the User information here, but then we have to start thinking about what do we need to include for different kinds of requests. Like for example, if we are requesting for a ticket, but we also want to include User information, we don't need all of the User information. We just need what is the most important User information that's related to the ticket. Now of course, as it is right now, we don't have really anything set up for our users. So let's start by creating a controller for our users. So we will make the controller Api\V1\UsersController.
So let's start by creating a controller for our users. So we will make the controller ApiV1UsersController. We want it to be a resource controller, we want the model to User, and we want the requests as well. So let's do that. And while we're here, let's go ahead and let's make a new resource for our User resource so that we can have that in place as well. And with those files, now we do need to make some modifications because we created these StoreUserRequest and UpdateUserRequest, we need to move those into ApiV1. So let's do that.
store and update User requests, we need to move those into API v1. So let's do that. And unfortunately, Visual Studio Code does not automatically update those namespaces. So we need to do that as well. So we will tack on API v1. Let's just copy that because we need to paste that in several other places. Let's open up the UpdateUserRequest, we will paste in that new namespace. Let's go to UsersController. And we need to modify the use statements for those request objects. But with that in place, we are good to go as far as our controller.
And we need to modify the use statements for those request objects. But with that in place, we are good to go as far as our controller. Although let's do this. Let's go ahead and let's return our User resource. And we'll call the collection method, we will pass in all of our users and we'll paginate these as well. So we will have that in place. Let's get rid of the create method because we don't need that. Let's get rid of the edit method because we don't need that either. And then for the show method, we will return a new User resource.
Let's get rid of the edit method because we don't need that either. And then for the show method, we will return a new UserResource. We will pass in the User there. So our controller is all set to go. We do need to set up the routes here. So let's go to our api/v1 file. Let's copy the route that we have set up for our tickets. And we'll just make the necessary changes for our users. So the controller is UsersController. And let's add that use statement.
Defining UserResource Fields4:57
So the controller is UsersController. And let's add that use statement. Okay, we have our Ticket resource. Let's open up our User resource. Let's go ahead and let's start defining this. Now we want to follow the same kind of structure that we have for our Tickets. So we will have the type, which is going to be a User. Let's have the ID, which is of course going to be the ID attribute from our model. Then we will list our attributes. Now some of these attributes we always want to display.
Then we will list our attributes. Now some of these attributes we always want to display. Like for example, the name. That should be included with just about everything. Because I would imagine anytime we provide user information, we would want that name there as well. So we will include the name as well as the email. But all of the other information we don't necessarily need except if we are making a request from our UserController. Like for example, there is the email_verified_at.
if we are making a request from our UserController. Like for example, there is the emailVerifiedAt. And we could do what we did with the description, to where we would call the win method. Our condition would be for when the request route is. And then we would want it for any request or any route from our users route. And then we would simply provide the emailVerifiedAt value. And that would work. I mean, there's something to say about code that works. However, we would have to do this three separate times.
Grouping Fields with mergeWhen()6:26
I mean, there's something to say about code that works. However, we would have to do this three separate times. One for email_verified_at, one for updated_at, and then we would need the created_at as well. And there's gotta be a better way, and thankfully there is. We have a method called mergeWin. The idea being that, once again, we provide a condition to test. So in this case, it is going to be if the route is from our User's routes, then we will include all of these other keys and values. So here we will have email_verified_at,
then we will include all of these other keys and values. So here we will have email_verified_at, which would of course be from our model value. Then we just need to include the created_at and the updated_at fields. So it's going to give us the same result as if we used individual win methods. But it's nice and compact. It's a lot easier to read and follow along. So therefore, well, it is what we need to do. So with that in place, we should be able to use that to include the User information in our TicketResource.
Adding User Includes to Tickets7:31
So with that in place, we should be able to use that to include the User information in our Ticket resource. But we do need to set up the relationship, don't we? So let's go to our Ticket model. public function, we'll call this simply user. And this is a belongsTo relationship to where we will return. This belongsTo and it belongs to a User. So with that in place, we should be able to go back to our Ticket resource. And now, let's say that after relationships, we will have the includes. Let's take a look at the JSON API specification.
And now, let's say that after relationships, we will have the includes. Let's take a look at the JSON API specification. And this is where we can start to deviate from it, because I don't necessarily like how they use included information. Like for example, here is the data for an individual article. And the relationships, all that stuff. And then as a sibling property, we have the included information. And I don't necessarily like that. And if this were a collection, then it would be even weirder. Because the data would be, of course, the collection of, well in this case,
And if this were a collection, then it would be even weirder. Because the data would be, of course, the collection of, well in this case, it would be articles. And then the included would be a collection of all of the things that were included. I just don't like that approach. So instead, we're going to make the includes as part of the individual ticket info. So here, we can have includes. And then we will include a new UserResource.
So here, we can have includes. And then we will include a new User resource. And we will pass in this user. So if we take a look at this, let's go to Postman. Let's go ahead and make a request for an individual ticket. We should still see pretty much everything that we did before. But now we have the includes, and we have the user information. We have the type, the ID, and just the attributes that we would need in this particular request, the name and the email. All of the others are not there.
that we would need in this particular request, the name and the email. All of the others are not there. So let's do this. Let's create a new blank Collection. And let's call this users. And let's do this. Let's make it a little bit easier on ourselves. Let's set the authorization to bearer token. We're doing this on the entire collection so that every request that we make under this users collection
We're doing this on the entire collection so that every request that we make under this users collection is going to inherit this bearer token. So we will use our bearer variable there. We will be sure to save that. It would be nice if we could set headers here as well, but oh well. At least we can set the authorization. So now we can add a new request. Let's call this getUsers. The URL is going to be very similar to our tickets,
Let's call this getUsers. The URL is going to be very similar to our tickets, except that we will need to make a request to users. We don't have to worry about the authorization, but we do need to set the accept header to application/json. And let's send that. We should get our user information. So we can see that we have the data structure that we expected. And now we have the extra information, the verified_at, the created_at, and updated_at values.
And now we have the extra information, the verified_at, the created_at, and updated_at values. Now with going through that whole process, in the next episode, I want us to revisit this idea of including things. Because by default, we really shouldn't be including the user information. That should be something that the client should opt into. Now of course, yes, we need to supply the user_id, which we do inside of this relationships. But what I'm referring to is the actual user information, such as the name and the email address.
But what I'm referring to is the actual User information, such as the name and the email address. Since that's not necessarily absolutely needed for a request for our tickets, it needs to be an opt-in feature. And we will look at how to implement that next.
