May 2021 - Powering JSON Responses with Eloquent API Resource

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
okay you all can see my screen yeah it's visible yeah yeah yeah you can see the code there right yeah yeah yeah okay so here uh it's a very simple uh application uh which i have uh took liberty to put the basics in place so we have a users we have an admin user so i'll you database table structure quickly so so we have let's say four users one of them is an admin and rest of the normal users each user can have one or more courses attached to that user and a course has many lessons then through this join table so just very simple we'll mostly focus on users only so for the current logged in user if you want to get the information of the current routing user then there's an api route called slash me which is under this uh authentication sanctum middleware i'm not explaining each and everything i'll just focus on the api uh the response thing okay so the authentication is done through sanctum in this api application so this me returns whatever whoever the current login user is this route returns that loading users information so let's see what is there so this is that me method in the controller it is doing just uh returning request error user this returns the current authenticated users object element object so let's see how it looks in a rest client so this is the current login user if i send the request it shows the current login users record from the eloquent model you can see it shows all the fields id name email is then minimally verified it's created and updated reason being we are just returning the complete user object we are not returning any specific fields okay so now let's try to understand first what api resources are as you know laravel is an mvc framework m for model v for view and c for controller but when you are building an api what goes missing from there model is there controller is there but one thing that goes missing is view view right so now you must be wondering then how we can still create a view layer there's no view layer as of now but how we will create a view layer in case we are building an api based laravel application so this is not an official statement but this is my understanding only so what i term api resources is api resources are like view layer for api based laravel applications so when you create api resource you are actually creating a view to present the json to the consumer okay and api resources uh let's try to understand it with uh with an example so here we saw that a user for user we are getting all the fields from database as is what if we don't want to uh return created and updated or email verified these four fields are not really important for the consumer generally name email and id is important so what do you in a normal case what we'll do we'll just write here only id name and email so what this will do this will only select id name and email from the user object so let's see this is fine however in the index section where we are listing all the users in the system let's see what happens here here we are still getting all the other fields so now you see there's a discrepancy in one of the api calls we have a user object represented by just id email and name and in other api response the same user object is represented by these fields okay so what you will do to fix this display you will try to you can only go in here as well again same thing now both for the user listing as well as the single user we are getting the same object now when building apis you must you you all must have also consumed other apis like facebook api or twitter api or any xyz api if you have noticed then there json response is really consistent so if if if uh they are returning a user returning a user object in any any of the endpoints then they return the same set of fields in everywhere it's not like that if you see a single user they return a different set of fields if they're returning a list of users they will return different fields for that user that doesn't happen so when building apis it is really important to have some consistency in the response so if you are uh responding with uh within with a user object for example then that user object should be consistent across all endpoints be it single user or list of users or maybe if you're returning a list of posts and want to include a user object who is the owner of that post there as well so everywhere should be consistent so this is where api resource comes in handy it makes sure that your responses are consistent across all the endpoints let's see how okay so this was one of the thing that to keep all the responses consistent we we use api resource then this this is not just the only feature of api resource the other feature is transformation so let's say uh right now we only have a single field uh name but if let's say we have in database we have two fields first name and last name and while responding you want to concatenate these two fields and respond with just a name okay so normally what you will do you have two or three options here you can either uh concatenate both the fields in the sql query itself into a single field or you can create a model attribute uh accessor attribute name wherein you'll concatenate both of them and respond with a name or in this case api resource can come in handy it it can transform uh the user object and concatenate both you first name and last name fields into a single field called as name okay we'll see how so let's now convert this into a resource response rather than a normal json response so for that first we will create an api resource for the user model so the command for that is php artisan make resource user resource this creates a user resource class in the resources directory so if you go in here if you look in app http resources you will see the newly created class now this resource class when when you generate a resource class by default it has this method to array this method is invoked automatically whenever you instantiate the resource class this method will be invoked and it this method is the responsibility of this method is to return an array that will represent the model object so in case of user this should return all those fields that we want in the json response for that for user model so by default it just calls the parent class request parent class to array so let's see what happens now let's use this resource as is without making any changes so i'll remove this and instead of returning the model object we will now create an instance of user resource and provide the user object as the argument to the user resource constructor okay now let's see what happens here this is that api call we got the complete user object as is why as is because in the resource in the resource we are not doing anything special we are just returning the complete model object as is so now let's remove this and return only the fields that we want so what what all things we want we want id then we want name and email these three things we want for user object now what's the value of id when laravel when you invoke when you create the resource here and pass the user object to this resource what happens is this user resource class proxies the model itself so all the model attributes that are uh present in this object in this user object those are all those are also present in this resource class so to get the user's id you can do download this arrow id why download the server id because this is representing this user resource which is proxying the user object which you passed it here so the name will be dollar user error name and email will be this email okay now let's see what happens here now it is done returning only these three fields you will also notice that it wraps the entire user object in data this is the default behavior we will see later on how to turn this behavior off but uh ideally if you look at standard apis you'll always see that the object the primary object is always wrapped in a data property this is the standard normal behavior of most of the apis so this is how you will create a user resource you will instantiate a user resource to return a single object so this is how you were returning a single object now let's see when we have a collection of objects in this case this will return a collection of user objects not just single user object okay so you cannot do new user resource and pass a single uh pass the collection to that resource because a resource represents only one user object a resource at a time represents only one user object so let's see how to pass the collection how to transform the collection using api resource so instead of this what we'll do is we'll grab all the users first and returning instead of returning the use directly we will now call a special method called as collection this is a static method present in the user resource class and then pass the collection of users to that method so when you have a single user a single model object to respond with you will directly instantiate the resource pass the object as an argument to the constructor whenever collection of objects then you will call the collection method of the class resource class and pass the collection now let's see this so now you see uh we got the data and the area of all the users and we have only these three fields present in the response so now what happened here the repetitive code that we added earlier to select only id name and email fields we remove that now wherever we use resource user resource it will always respond with those three fields only no there's no need to write a duplicate code in all the controller methods to only select id name and email okay any questions so far are all good okay i guess it's all good so next let's see uh here we are getting only the user object now what if user is rated with some other model for example in this case our user's user is related with courses model user has them belongs to many course so each user will have many associated courses let's try to send the user courses in the response so what we will do for that in the resource we will add a new key courses and then this zero courses as i said earlier the resource is proxying the user model so whatever the user model attributes our methods are those are available in dollar this here so since user has many courses i've already defined in user model i've already defined the relationship that user belongs to many courses that is why i can write this set of courses here so this will return all the courses of the of this user so now if i come in here this user didn't have any codes that is what is showing uh empty array if i this is a different user this user had some courses so we got these three courses for this user now you saw that we added courses only in the api resource so that means wherever this resource is being used whether it is single uh currently it is being used in two different endpoints one is single user and the list so it will affect both the end points so now if i see a list of users earlier there were no there was no course now you will see courses in the list of users as well so this is how the consistency comes in you just modify uh you just modify the user object at a single place that is user uh that is api resource user api resource and it will reflect everywhere whether api resource is being used so now we have a consistency wherever user resource is return we will see courses along with the user but it may happen that you don't need a this is a heavy query this means it will always try to find all the courses there can be a number of courses attached to each user so it will always run queries in the backend and the background to find courses for all the users while this is fine for a single user you may not need users when you're listing the when you're showing the list of users in the front end right so in that case it may happen that you know don't need to use our courses for that user in this case so let's see how to fix that or how to make changes to achieve that so if you want this courses to be available in the response only when the process has been loaded in the user object okay and how to load courses you can do that using load method so what this does is first the user is found and from that user object it loads all the courses it runs the query to find all the courses for that user so this is this loads all the course object process object in the user object so we will return courses only when uh it is loaded so for that first we will need to create okay before that what i will we will see uh one moment so in here again for courses you are seeing that it is uh showing id names created at all everything we only need id and name so let's quickly create a collection for courses first php course resource and in course resource we only want id and name of the course so what you can do in user resources you can transform the courses which is a currently raw element object into the api resource by using the course resource here so you can write course resource column column collection by collection because this is a collection of courses okay so now let's see the response now in response you get courses and this is coming through the courses api resource just id and main now we want to load this only when it has been loaded uh using the object user object so for that what you can do is use a special method of the resource which is called as when loaded now what will happen this courses will come will be loaded and return in the response only when it has been pre-loaded like this here we are not loading courses at all okay so let's see the difference now if i see a single user earlier we were getting or let me know earlier we were getting the courses array this is for a single user [Music] what happened okay so when we are looking at the single user we we are getting all the courses because we have loaded it in the controller itself however when we see a list of users when we see a list of users we haven't loaded the courses here so here we shouldn't get courses now no courses so this is called as conditional loading of related resources if you want the related resources uh related objects to always be loaded then you can remove this when loaded thing so it will always be loaded and if you want it uh to be included in the response only when it is loaded in the controller then that when noted method can be can come in handy any questions so far you guys are getting what i am saying transforming the user object so let's uh just for fun let's see if we want to transform something let's say we uh in users we want the created to be returned but we don't want to return we don't want it returned in the api response as is if i return it as this let's see what happens you get this iso format data string but in the front and normally we don't display date and time with this format right so what we can do is in here we can transform this we can format it and this is a readable format human readable format so we have a better formatted date now and we only had to make change at one place and it will affect all the end points where users are returned so here also you will see that human readable created date so this is what a transformation i was talking about earlier so we are transforming the default user module object into a more human uh readable format okay so next let's see um earlier said that api resource wraps the response in data key normally this comes in handy but in case you don't want this in case you don't want the response to be wrapped in data key you can turn this off how you can turn it off let's see if you want to turn it off globally so that anywhere for all the api resources be it user resource or post resource or any resource you create if if you want to turn it off globally then you have to open app service provider and in the boot method you can write json resource for long colon without wrapping so when you do this this will affect all the api resources not just the user resource but it will affect all the api resources let's see so now know that no data is coming it is not wrapped inside data similarly if you look at the list of users data is gone so this is how you turn off wrapping data wrapping however if you don't want to turn it off globally this will affect all the resources if you want to turn it off only in certain cases then what you can do is you can you don't need to write that in app service provider but just write it in the individual controller method so if i write it here i have removed it from the app service provider so it is not global if i write it in the control method itself so this will affect only this me endpoint however it will not affect this list of users endpoint let's see so this is uh me endpoint so you see no data in here if i go to get all users i get the data so this is how you turn off data locally if you write it in app service product is global if you write it in individual controller method then it is local okay uh next let's take a look at uh pagination how the pagination response works in api resource so currently we were just finding all the users and returning it in the response however this is generally this if we don't do this we there is a large set of data we paginate the data so instead of get if we use page in it api resources handle paginate by default you don't need to do anything extra so let's see how the response is now this was the response earlier data and the list of users now you will see the pagination information also included in the response links metadata so this is how pagination works along with api resources you just need to instead of a collection user default user collection you need to provide the collection with the uh resource collection with the originate originated eloquent response okay now moving on let's see let's say we want to in the response we want to add some fields but only in certain conditions for example [Music] admin is calling this request show current user of wherever admin whenever admin is logged in this is these are the admin endpoints this is the user so whenever admin is looking at the user we also want to respond okay so when administ is accessing this me and point we want to respond with count of courses as well along with the courses so let's see how we can achieve that we want that count to be included only when the current user is admin okay so for that what we can do is there is a method called as when in the api resource class when the first argument this needs is the condition in which condition we want this field to be written in the response so we want this field force content course count to be returned only when current logged in user is admin so current router news i will get in the request we have the request object here request error user this is the current login user and if it is admin then only return this field and what should be the value of this field the value should be count of courses for this user so this is coming through relationship now let's see uh so here i had the list of all the users now i can see the course count 0 3 0 3 this is admin calling the user endpoint now if a normal user calls the user endpoint the same user endpoint let's see what happens you don't get course content here you're only getting courses remember courses were present for this me and point but if a normal user is viewing now this force count is not being written in the response but for admin it is returned so this is how you can add conditional attributes okay now if there's a there is an issue here [Music] what is the issue this code will be executed no matter whether the current user is admin or normal user and as you know this will fire additional queries to find the count of the courses and it will run every time even if this field is not included in the response but this this will be executed right so what we can do is we can pass a callback to this function to the when instead of directly given giving the value we can pass a callback now what will happen this callback function will be called only when this is true so that means this will not be executed all the time this will be executed only when this is true let's see if this works or not so this is the admin uh yeah we need to return so we are getting the count and for normal users you're not getting the count so it is working let me shorten this using the okay so this working working okay so this is how you load conditional attributes now if there are more than one attribute that you want to return for this particular condition so let's say if you have another field just for example let's see if you have a list example or whatever you want this field to be included in the response only when user is admin so normally what you will do you will just duplicate this now this is code duplication you are doing you are checking for this condition multiple times so instead of doing this what you can do is use another method called as mergement this works similarly however instead of uh just returning one field you can return multiple fields in here will be this and example will be this like this so what merge one will do you combine two different uh statements into one now these two fields will be written in the response only when this is true but this is true both this will be will be included in the response let's see whether it works or not so this is admin so we should now see both the fields force count and example however for normal user you shouldn't see any of those fields it's not coming in for normal use so this is working properly so this was uh excuse me [Music] uh that is because i think in this video okay yeah okay uh so this was conditional attributes and merging two different uh two attributes in the condition let's move on to next piece now up until this point everything is clear any questions anyone okay so next we will see uh how to add additional metadata to the responses so this is user response all good no problems but let's say when you are uh in this me and point if you want to add some additional data to the response which you don't want in here okay and you don't want to write code in the resource itself then what you can do is we have another resource let's say okay then we have this method called as additional this takes let's see if you want to add a something with let's say current let's say date time current date time in the response so this is how you can add additional metadata if you don't want to edit it in the resource itself with conditions you can add it in the controller like this so you'll create the new object of the resource and then you you will call the additional method of the resource and end the additional metadata let's see how this material appears now this is metadata this is not this will not appear inside the user object this will up this will come in a response as a separate object let's see [Music] like this so this will not come this is the additional metadata we are touching so this will not come inside the user object it will come separately okay so this is how you can add additional metadata to the response we added it here we didn't edit in the list of users so it shouldn't appear in the list of users it's not there let's see how it looks if we add it in the list of users as well so if i add this in the list of users as well i haven't tried this not sure if it will work or not it does so again in here this is the data in the designation data and then in the last and then you can see this additional metadata add it to the response so this metadata is added to the entire response not to individual user object when it when you when you're responding with collection okay while if you add something in here it will be present for all the users in the collection not just one user so this is how you add additional metadata to the response now let me quickly revert this we don't want this okay now next is by default laravel what uh what laravel does is it converts this resource into the response object we are not converting we are not doing anything like this response and something like this we are not doing anything like that laravel uh internally converts all the resources when you turn the resource from a controller method it will convert that resource into a response now what we if you want to uh modify the response for example in normal cases if you are responding you do something like this response arrow json then whatever you want to respond with okay and if you want to add the headers to it then you add headers in here itself right to the response if you want to set a status code you set a status score in here itself correct now how to do this when you're using resources let's see if you want to modify the response in any manner what you can do is again we will connect this in an object first so now the resource has a method called as response this will give us the this will convert the resource into a response object and then this is the normal level response object then you can add anything in here let's say if you want to add an header i want to add an header let's say the name of the app okay so this is how i will add additional headers to the response when you when i'm using resources let's see if this header appears in here or not i'm getting the response and if i look at the headers i can see my custom header alternatively uh you may define uh this thing whatever you have done here if this looks clearly if you don't if you want this header to be present in all the responses then you will have to do the same thing in all the controller methods which is again code duplication so what you can do is not write it here instead we will write that thing inside the resource class itself let's see how so if you want to add the same header to all the responses for the user resource we'll just create a new method in here called as with response this method is followed automatically when laravel is converting this resource into response okay in here you will get the request and the response and then you can modify this response as you see fit so what we want to do is we want to add header to this response which header meter so now this will present in all the responses and not just a single response let's see here you go and if i look at all the users here also um what happened okay in case of collection it will we need to create a collection class and then it will end the response it won't get to the collection directly we'll have to create a collection class okay uh now what if we want to along with this we want to change the status code right now for example if you did we have an end point where we delete certain object if you're deleting let's say a lesson then generally what should be the status quo when you are not when your response doesn't have any data the response should be 204 right so in that case let me in fact create an endpoint quickly just to show you what i mean so in lesson controller i'll create a function called as destroy in this case we generally don't respond with anything right so for such cases what you can do is you can set a status code let's say two zero four i'm doing it further uh for the user for now just to show you so now if i call this i'll get 204 no content why because i read the status quo to the response so this is how you can modify the response okay with this i think we have covered pretty much there are there are certain more things if you go to um official documentation of api resources a few things that we haven't covered was uh how to recover data mapping metadata conditional relationships with those collections we haven't covered the collection class itself so what we did was we only work with a single resource and to convert it into a collection we use the resources collection method but there's another way of doing it that is using the collection resource itself if you are using this then what you have to do is uh you have to return something like this in the correction class so you can head on to the official documentation and read on this okay i think we covered it pretty much anyone any questions hello no question you guys understood what i was trying to say or it all went i wasn't able to explain it properly please give me some honest feedback no the explanation was pretty good hey thank you i i understood almost all the things but since this api uh thing is kind of new for me so i think i'll have to refer to the documentation more because i haven't worked with the api yet though this is something that i always wanted to know uh so thank you very much i understood a lot of things today anyone else has any questions or any comments feedback anything i just wanted to ask one thing like will this video be available on uh youtube or somewhere that i can see later on or referred to yes yes i'll be uploading this to the youtube the same channel laravel channel okay then thank you everyone thank you for joining us and hopefully i'll see you all next month and as always we are always on the lookout for new speakers uh so if anyone is interested in speaking at our meetups please come forward it is absolutely not necessary that you are in uh your lovable expert or anything like that everyone here is a learner even i am a learner so anyone can come forward and present their dog it need not be uh it can be a simple topic or a complex topic or whatever okay uh do you do you have a list of topic which is already taken in the laravel mark4 uh rihanna you can get it from the channel our youtube channel so pretty much every month we upload the videos there okay okay otherwise i'll also share the list with you no problems i'll have to find the list actually or alternately what you can do is uh if you go to our uh all events page all events laravel okay then you will find all the topics in here so yeah you'll find all the topics whether they are on youtube or not everything is there sure even those topics that we covered uh when we were doing in-person meetups those were the golden days yeah okay okay thank you everyone thanks a lot keep safe and have a good night thanks bye bye weekend happy weekend
Info
Channel: Laravel Nagpur
Views: 645
Rating: undefined out of 5
Keywords:
Id: n85k9eiN_AY
Channel Id: undefined
Length: 49min 22sec (2962 seconds)
Published: Sat May 29 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.