Send multiple variable to laravel Api resources - laravel

I want to different type of collection..One containing users acros the city and another one containing near by users. I want these from single api hit. is it possible ? If yes then please suggest how to do that.
Waht I did
return ServiceProviderCollection::collection($near_by);
Output:
"data": [
{
"username": "??",
"email": "??",
"rating": 0,
"role_id": 2,
"wallet": "0"
}
],
I want
return ServiceProviderCollection::collection($near_by,$across_city);
expected output:
{
"across_city": {
"data": [
{
"username": "??",
"email": "??",
}
],
},
"near_by": {
"data": [
{
"username": "??",
"email": "??",
}
],
}
}

No, you can't pass 2 objects in Resource. You can do it like this
return [
'across_city' => ServiceProviderCollection::collection($across_city),
'near_by' => ServiceProviderCollection::collection($near_by)
];
Edit: After comment
If you want to show pagination information then you have to create separate controller action and then return ServiceProviderCollection::collection then you will get result with pagination meta information.
create these action in your controller ex. (UserController)
public function acrossCity(){
$acrossCity = User::where('city','test')->paginate(10); //example
return ServiceProviderCollection::collection($acrossCity);
}
public function nearBy(){
$nearBy = User::where('near','1')->paginate(10); //example
return ServiceProviderCollection::collection($nearBy);
}
create routes for these
Route::get('user/acrossCity','UserController#acrossCity');
Route::get('user/nearBy','UserController#nearBy');
Check document https://laravel.com/docs/5.6/eloquent-resources#pagination
Note: when using resource class then name it without Collection. For your case you should name resource as ServiceProviderResource and then when you call its collection then ServiceProviderResource::collection($object) but when returning single object then new ServiceProviderResource($object).

I am currently using Laravel 7 and in my controller I am passing an array of collection objects to resource class
$data = ['quotation' => Quotation::first()];
return new QuotationResource($data);
and in my resource class I can access the data using
public function toArray($request)
{
return [
'quotation' => $this->resource['quotation']
];
}

Related

Laravel Fractal add success message to response

Is it possible to add a success message to a JSON response using Fractal? I would like the structure to look like the following
{
"success": true,
"message": "Clients found",
"_metadata": {
"total_count": 2
},
"data": {
"clients": [
]
}
}
I have written the following code to return the data
$response_data = fractal()
->collection($person_array)
->transformWith(new ResponseTransformer())
->toArray();
Do I need to create a new serialiser to get this format? I have been following this documentation https://packagist.org/packages/spatie/fractalistic but there is no option to add extra key values such as success: true.
I also want to use this format for all my API responses, is it possible to create a generic Transformer which returns what ever array data I pass into it instead of creating a Transformer per Model?
Laravel fractal allows to add meta data to collections :
fractal()
->addMeta([
'status' => [
'success' => true,
'code' => 1,
'message' => 'Test'
]
])
Resulting JSON output
"meta": {
"status": {
"success": true,
"code": 1,
"message": "Test"
}
}

How to return HTTP status code when returning a ResourceCollection in Laravel

I'm building an API and I'm trying to return a ResourceCollection for a Classroom in Laravel.
Previously I used an array of classrooms and returned a response with the array and the status code, like this:
$classrooms=Classroom::all();
return response()->json($classrooms,200);
Now this is my code:
$classrooms = new ClassroomCollection(Classroom::paginate(10));
return $classrooms;
to get this response:
"data": [classrooms array],
"links": {
"first": "http://127.0.0.1:8000/api/classrooms ?page=1",
"last": "http://127.0.0.1:8000/api/classrooms ?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": null,
"last_page": 12,
"path": "http://127.0.0.1:8000/api/classrooms ",
"per_page": 10,
"to": null,
"total": 0
}
and I can't find a way to send a status code along with the ClassroomCollection, because if I do
return response()->json($classrooms,200);
I'm only returned the "data" object, without the links and meta of the paginator.
Any help?
you can override the withResponse function in your collection like this:
public function withResponse($request, $response)
{
if($response->getData()) {
$response->setStatusCode(200);
} else{
$response->setStatusCode(404);
}
parent::withResponse($request, $response);
}
If you really want to you can do the following:
return response()->json($classrooms->jsonSerialize(), 200);
->jsonSerialize() does not actually serialize as a JSON string but returns an array that can be serialized to JSON string. Laravel serializes to a JSON response if you return an array or JsonSerializableable object from a controller/route and that is what the paginator implements.
However, if 200 is the status code you want, that is implied and the default status code and there is no need to supply it.
So the above is equal to:
return $classrooms;

Array with single attribute of many-to-many Eloquent relationship

I created a model NearMiss that has a many-to-many relationship with a Type model. When there is a GET request for a specific NearMiss, I want an array to be attached to the JSON output that has the name attribute of all Type instances that belong to the NearMiss instance.
I can attach an array of Types to the output, but I want to get rid of all the additional information (such as pivot information).
The GET request /nearmisses/{nearmiss} executes the following method:
public function show($id)
{
try {
$nearmiss = NearMiss::findOrFail($id)->first();
$nearmiss->types->makeHidden(['id', 'created_at', 'updated_at']);
return response()->json($nearmiss);
} catch(ModelNotFoundException $e) {
abort(400, 'Model not found');
}
}
The NearMiss model has the following types relation:
public function types()
{
return $this->belongsToMany('App\Type', 'near_miss_type', 'near_miss_id', 'type_id');
}
Current output:
{
"id": 1,
"location_long": "0.0000000",
"location_lat": "0.0000000",
"employee_id": 1,
"created_at": "2019-02-11 16:38:24",
"updated_at": "2019-02-11 16:38:24",
"types": [
{
"id": 1,
"name": "Brandgevaar"
"created_at": "2019-02-11 16:33:25",
"updated_at": "2019-02-11 16:33:25",
},
{
"id": 2,
"name": "Slipgevaar",
"created_at": "2019-02-11 16:34:12",
"updated_at": "2019-02-11 16:34:12",
}
]
}
I know that I can remove additional attributes (such as id, created_at, updated_at), but that still leaves me with an array of Type instances (with just a single name attribute). When I try flatten() I receive an error that flatten() can't be used on BelongsToMany relationships.
Desired output:
{
"id": 1,
"location_long": "0.0000000",
"location_lat": "0.0000000",
"employee_id": 1,
"created_at": "2019-02-11 16:38:24",
"updated_at": "2019-02-11 16:38:24",
"types": [
"Brandgevaar", "Slipgevaar"
]
}
Can someone help me to get the desired output please.
You could load the types manually and use the pluck() function to only get the name of each type.
$nearmiss->types = $nearmiss->types()->pluck('name');
However I'm not sure if this will interfere with the magic properties from Eloquent.

Query unknown data structure in GraphQL

I just started to work with GraphQL and I am setting up a server with webonyx/graphql-php at the moment. Since a GraphQL query already has to contain the resulting data structure, I am not quite sure how to get dynamic data. Assumed that I query the content which consists different element types and my final structure should look like this:
{
"data": {
"dataset": {
"uuid": "abc...",
"insertDate": "2018-05-04T12:12:12Z",
// other metadata
"content": [
{
"type": "headline",
"text": "I am a headline"
},
{
"type": "image",
"src": "http://...",
"alt": "I am an image"
},
{
"type": "review",
"rating": 3,
"comment": "I am a review"
},
{
"type": "headline",
"text": "I am another headline"
}
// other content elements
]
}
}
}
How could I write a query for this example?
{
dataset {
uuid
insertDate
content {
????
}
}
}
And how would a type definition for the content section look like? There is a defined set of element types (headline, image, review, many more) but their order and number of elements is unknown and they have only one field, type, in common. While writing the query in my frontend, I don't know anything about the content structure. And what would the graphql-php type definition for the content section look like? I couldn't find any similar example online, so I am not sure if it is even possible to use GraphQL for this use case. As an extra information, I always want to query the whole content section, not a single element or field, always everything.
When you're returning an array of Object types, but each individual item could be one of any number of different Object types, you can use either an Interface or a Union. We can use an Interface here since all the implementing types share a field (type).
use GraphQL\Type\Definition\InterfaceType;
use GraphQL\Type\Definition\Type;
$content = new InterfaceType([
'name' => 'Content',
'description' => 'Available content',
'fields' => [
'type' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The type of content',
]
],
'resolveType' => function ($value) {
if ($value->type === 'headline') {
return MyTypes::headline();
} elseif ($value->type === 'image') {
return MyTypes::image();
} # and so on
}
]);
Types that implement the Interface need to do so explicitly in their definition:
$headline = new ObjectType([
# other properties
'interfaces' => [
$content
]
]);
Now if you change the type of the content field to a List of content, you can query only fields specific to each implementing type by using inline fragments:
query GetDataset {
dataset {
uuid
insertDate
content {
type # this field is shared, so it doesn't need an inline fragment
... on Headline {
text
}
... on Image {
src
alt
}
# and so on
}
}
}
Please see the docs for more details.

laravel/codeception : test if json response contains only certain keys

I have a json array coming from my api as response:
{
"data": [
{
"id": 1,
"name": "abc"
}
}
I am using laravel for api and laravel-codeception for testing.
public function getAll(ApiTester $I)
{
$I->sendGET($this->endpoint);
}
I have to test if the response contains only id and name key (not any other key) example this response should fail the test.
{
"data": [
{
"id": 1,
"name": "abc",
"email":"abc#xyz"
}
}
I have found $I->seeResponseContainsJson(), but it checks if JSON is present or not. It does not check if JSON response contains only specified keys.
Thanks.

Resources