-
Notifications
You must be signed in to change notification settings - Fork 11k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[5.5] API Responses #19449
[5.5] API Responses #19449
Conversation
Hi @themsaid, can you change the Keep up the good work 👍 |
Hi again, can you check the paginator response in your description: {
"data": [
{
"name": "Prof. Alfonzo Schulist DDS",
"email": "[email protected]"
},
{
"name": "Prof. Oma Armstrong PhD",
"email": "[email protected]"
}
],
"meta": {
"current_page": 1,
"from": 1,
"last_page": 50,
"next_page_url": "http://laravelnext.dev/controller?page=2",
"path": "http://laravelnext.dev/controller",
"per_page": 2,
"prev_page_url": null,
"to": 2,
"total": 100
}
} The I know this is just an example but i'm confused to process it 😜
|
{ | ||
if ($object instanceof Collection) { | ||
return [ | ||
'data' => $this->user->map([$this, 'transformResource']), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be $object
and not $this->user
? Same applies below.
Would love to see a static factory especially with the return UserApiResponse::create(User::find(1))->withStatus(201); I would also get some usage about adding misc meta. So maybe a Any thoughts on making the pagination meta its own key? {
"data": [
{
"name": "Prof. Alfonzo Schulist DDS",
"email": "[email protected]"
},
{
"name": "Prof. Oma Armstrong PhD",
"email": "[email protected]"
}
],
"meta": {
"pagination": {
"current_page": 1,
"from": 1,
"last_page": 50,
"next_page_url": "http://laravelnext.dev/controller?page=2",
"path": "http://laravelnext.dev/controller",
"per_page": 2,
"prev_page_url": null,
"to": 2,
"total": 100
}
}
} |
Added a
|
This looks like an awesome addition! Would help a ton to be able to standardize the format that we use to return api data to the front end. With that in mind, are there any thoughts regarding a standard format when returning errors for api requests? For instance if I use a Not sure if this is the correct venue for discussing it but figured I would give it a mention. |
@JacobBennett I typically do this in the global exception handler since most of those types of exceptions you will want to handle in the same way. Also, you will want to look at the way 5.5 is going to render exceptions now, you might be able to bake it into that. |
@JacobBennett in 5.5 if your API call has a
|
Totally forgot to mention that. Would be nice if it would respond with JSON automatically if the route is an API route |
@sixlive, in your API routes (or Controllers) should respond with: return response()->json(...); Or something similar. This PR is just a helper to transform objects without using external packages like fractal or even using |
Thanks! Well aware of what this PR is. Just making a side comment on global exception handling responses. |
@DanielDarrenJones Oh sweet! Thanks mate! Totally missed that one! |
Isn't it better to use class inheritance without using a trait. Something like,
Anyway it seems this is equivalent to league/fractal |
Thanks for the heads up on the JSON response stuff for exceptions @themsaid, looks like 5.5 has it covered! |
@lkmadushan you always could make your own class which will use trait under the hood. |
use Illuminate\Database\Eloquent\Collection; | ||
use Illuminate\Pagination\AbstractPaginator; | ||
|
||
trait ApiResponseTrait |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we call this something else? Like ApiResponse
or RespondsToApiCall
or something without the Trait
suffix..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with @tillkruss. Suggesting one more option: HasApiResponse
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This trait actually describes what the class is, so IsApiResponse
sounds good to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JosephSilber option is the best one.
* | ||
* @var array | ||
*/ | ||
public $metaData = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Metadata is a single word, and should therefor not be camelcased.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't agree with it because result will be displayed in meta
array key.
use Illuminate\Database\Eloquent\Collection; | ||
use Illuminate\Pagination\AbstractPaginator; | ||
|
||
trait ApiResponseTrait |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This trait actually describes what the class is, so IsApiResponse
sounds good to me.
|
||
use InvalidArgumentException; | ||
use Illuminate\Database\Eloquent\Collection; | ||
use Illuminate\Pagination\AbstractPaginator; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then we should also require "illuminate/database": "5.5.*"
and "illuminate/pagination": "5.5.*"
in Illuminate/Http/composer.json
/** | ||
* Create an HTTP response that represents the object. | ||
* | ||
* @return \Illuminate\Http\Response |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@return \Illuminate\Http\JsonResponse
instead
* Create an HTTP response that represents the object. | ||
* | ||
* @return \Illuminate\Http\Response | ||
* @throws InvalidArgumentException |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing backslash => @throws \InvalidArgumentException
Great @themsaid ! I think having |
Thanks @lucasmichot and @JosephSilber, applied the following changes:
|
@@ -17,6 +17,7 @@ | |||
"php": ">=7.0", | |||
"illuminate/session": "5.5.*", | |||
"illuminate/support": "5.5.*", | |||
"illuminate/pagination": "5.5.*", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably be sorted ;-)
Shouldn't we use the |
I share @adiachenko opinions on that, @taylorotwell |
@taylorotwell said he'll think about it more, if he decided to not go for it then yes I think releasing it as a package would be nice :) Just hope this gets into the core since it's really simple but helps alot with creating responses. |
I fully agree, JSON-API feels way to over spec for what 99% of people need. Having something simple now would make such a huge improvement across the board for Laravel, is there a way the formatters could be pulled out to be configurable so if in the future it changes to JSON-API or another mapping it can be replaced by the user? |
This looks like what http://fractal.thephpleague.com does. |
@joselfonseca I would go out on a limb here and say that 100% of people trying to PR API responses into Laravel have used and disliked Fractal. |
@deleugpn Actually I really like fractal, especially when wrapped in https://github.com/spatie/laravel-fractal, that said it would be nice to have a unified global api response system in Laravel. |
@deleugpn Interesting, I find it quite good myself. Then again having something in Core would be nicer. |
@DanielDarrenJones Well, Fractal (kinda) does the job, but it's very awkward. Among other things:
In short, there's no smoke without fire. Otherwise, we'll all be using Fractal by now instead of trying to push a similar solution into the core. |
Praise the 🌞 \[T]/ |
Something that would help me in this thread are answers to this question: what are we trying to solve? At the end of the day, implementations seems to boil down to something like this:
Everytime I start hacking on it a bit I come back to the core fact that we are just giving you a fancy way to declare a plain PHP function that returns an array. Is that all we're trying to do? Does everyone agree with that? |
@taylorotwell basically yes, a way to convert an object to a PHP array to finally be converted to JSON. We're also trying to bring the ability to automatically convert a Collection of objects or a pagination to a JSON format, where objects inside those collections are transformed using the toArray function we're adding in this feature. |
And the main problem with using |
The main reason for transformers in my opinion is to decouple the underlying attribute names or database table names from the API response, doing so means we can change the underlying data structure while still keeping consistencies for users. It also gives us a chance to cast the type explicitly before it is transformed to JSON, this has its uses from time to time. Having a base transformation structure of the model allows us to pull that in a different response templates and transform to standard API response formats much like JSONAPI or similar. I think ultimately I am looking for something very similar to https://github.com/spatie/laravel-fractal, I want an easy way to model my API responses. I think over the last year and a half especially since Laravel has become so close to Vue we have seen a strong shift towards API driven development and for Laravel to fully embrace this we need the tools to do it correctly. |
I think the main reason of this feature is to have something similar to Creating a plain PHP function doesn't seems as an Eloquent way to work with. When creating a Transformer class, you can apply it to a Instead of using an external library, i think laravel already has more than Adding this feature is like adding the cherry on the cake. UPDATE: |
@taylorotwell |
OK thanks for your responses. |
Is there any benefit using this instead of league/fractal? |
@lkmadushan someone tried to answer that like 6 comments up. |
@taylorotwell yeah. see those comments. but didn't see any special difference compared to league/fractal. it seems like we are doing same thing in different ways. but It would be great if you can provide a JSON-API response format and a supported client for the frontend to consume JSON-API API service easily. |
For me, the main purpose of features like this is being able to respond to a request in a very specific way with very specific data with common resources. With attributes like We are trying to use common resources (Models) for specific responses. That's why generic behaviours doesn't match very well when we are trying to do such specific/independent things. Fractal does a very good work in this area, but it is extremely verbose for a framework like Laravel and I and many like me think it could be done better. (No pretending to offense to PHPLeague, of course) That's why I opened a PR (time ago) trying to figure out what is the Laravelish way to accomplish such work #18502. Is a bit old, and I didn't know about recent |
@lkmadushan it's the same thing, but done right. |
@deleugpn I'm curious to hear your problems with Fractal. |
@lkmadushan JSON:API Server responses is a good thing to have out of the box, but JSON:API Client is task out of the Laravel scope. It's not a trivial job and there is no reason for the Laravel team to develop and maintain it. |
@taylorotwell at first, it's not beginners-friendly. You have to opt for As you mentioned yourself in the thread, we're basically seeking model-to-array transformation layer. The amount of overhead just for that is too high through Factral. Factral At the end of the day, I think we're trying to have simple (and laravel-friendly) transformers for simple things. |
Done. |
PR: #20710 |
This PR Introduces a trait you can use on a
Responsable
:The trait needs a
$resource
property to exist on your Responsable object, using this convention it's going to create a response for you based on the type of object you pass (Resource, Collection, Paginator), you have to implement atransformResource
method to tell Laravel how to transform a single resource instance for the API.Now in your controller you can return any of the following:
The responses will look like the following:
For a single resource:
For when you pass a paginator:
For when you pass a collection: