Laravel Fractal add success message to response - laravel

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"
}
}

Related

Get all Data in a Body using Guzzle in Laravel from External API

I want to retrieve only the email in a JSON response using guzzle in Laravel from an external API. Here is what I have tried
//Get all customer
$allcus = 'https://api.paystack.co/customer';
$client = new Client();
$response = $client->request('GET', $allcus, [
'headers' => [
'Authorization' => 'Bearer '.'sk_live_#########################',
],
]);
$cus_data = json_decode($response->getBody()->getContents());
//returns a json response of all customers
//dd($cus_data);
$cus_data_email = $cus_data->data->email;
dd($cus_data_email);
Using this returns error
$cus_data_email = $cus_data->data->email;
"message": "Trying to get property 'email' of non-object"
But when I tried this, it returns the customer in the first array
$cus_data_email = $cus_data->data[0]->email;
I don't want to return just one customer email. I want to retrieve all of the customers' emails.
This is the way the JSON response is
{
"status": true,
"message": "Customers retrieved",
"data": [
{
"integration": ######,
"first_name": null,
"last_name": null,
"email": "a###$gmail.com",
"phone": null,
"metadata": null,
"domain": "live",
"customer_code": "CUS_##########",
"risk_action": "default",
"id": #######,
"createdAt": "2020-05-26T00:50:12.000Z",
"updatedAt": "2020-05-26T00:50:12.000Z"
},
...
What you're looking for is a loop!
$cus_data->data is an array, which is a variable that can store multiple values at once. These can be accessed with an index, and are commonly seen with loops.
I highly suggest reading the two links I supplied, the loop I'll be using is a foreach loop, as it's the most readable in this context. All the loops have their place, so it would pay to get familiar with them.
$emailsArray = []; // initialise an array
$emailsString = ""; // initialise a string
// Here's our loop, which will go over all the values of $cus_data->data
foreach($cus_data->data as $datum) {
// $datum is the single value in $cus_data->data which we're currently looking at
// Each of these values have an email property, which we access with arrow notation
array_push($emailsArray, $datum->email); // add the email to our array
$emailsString = $emailsString . $datum->email . ", "; // add the email to our string
}
Following this, $emailsArray will be an array (like we learned about above!) with all the emails from $cus_data->data.
$emailsString will contain the same information, just in a comma-separated string.
One thing to watch out for is if some of your data doesn't have emails! Then the code above could fail.
Admittedly, this isn't the shortest solution. For a problem like this, I would probably use array_map. The code here does the same thing in a more verbose format so we can understand it better.

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;

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 how to validation with unique JSON fields type?

I have a POST endpoint on my Laravel 5.7 API and Mariadb 10.3, I used postman to test my route and here is the problem. I want to send an array of the same kind of object, like this :
{
"Shops":[
{
"name": {
"en":"ShopEng",
"es":"ShopESP"
},
"code": "0891"
}
]
}
In my database.I have Shops table and Name field as JSON type.
{"en":"TestEng","es":"TestESP"}
In my Request. I also tried with the simple but not work.
public function rules()
{
return array(
'Shops' => 'required|array',
'Shops.*.name.en' => 'required|unique:shops,name->en',
'Shops.*.name.es' => 'required|unique:shops,name->es',
'Shops.*.code' => 'required|integer'
);
}
With Message.
"message": "Method Illuminate\\Validation\\Validator::validateUnique,shops,name>en does not exist.",
"exception": "BadMethodCallException",
"file": "/var/www/html/vendor/laravel/framework/src/Illuminate/Validation/Validator.php",
The second parameter written in the unique validation rule refers to a column on the database table where the unique rule will be tested, I'm afraid the syntax you wrote there is not valid.
My guess here is that you will have yo create a custom validation rule for handling this particular case.

Send multiple variable to laravel Api resources

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']
];
}

Resources