I'm returning some json data as response in a Controller, i want to add some information to
In my DriversController extend's Apicontroller in DriversController i'm returning some data on api call, i want to appent the status code information to below response
if ($request->wantsJson()) {
return Response::json([
'data' => [
'user_details' => $agent_percentage,
'dropdown_data' => [
'employment_types' => $employment_types->all(),
'roles' => $roles->all(),
'vehicle_brands' => $vehicle_brands->all(),
'vehicle_types' => $vehicle_types->all()
]
]
]);
}
//to the above response
return Response::json([
$this->respondSuccess(), // i am append this information
'data' => [
'user_details' => $agent_percentage,
'dropdown_data' => [
'employment_types' => $employment_types->all(),
'roles' => $roles->all(),
'vehicle_brands' => $vehicle_brands->all(),
'vehicle_types' => $vehicle_types->all()
]
]
]);
In ApiControllre I'm setting all the status code and messages
class ApiController extends Controller
{
protected $statusCode = 200;
//getter status code
public function getStatusCode()
{
return $this->statusCode;
}
//setter status code
public function setStatusCode($statusCode)
{
$this->statusCode = $statusCode;
return $this;
}
//failure messages
public function respondFailure($message='Account is not active contact admin', $status='failure')
{
return $this->setStatusCode(400)->respondWithMessage($message, $status);
}
//success messages
public function respondSuccess($message='Agent is active', $status='success')
{
return $this->setStatusCode(200)->respondWithMessage($message, $status);
}
//a layer of abstraction to avoide repetation
public function respond($data, $headers = [])
{
return Response::json($data, $this->getStatusCode(), $headers);
}
//get ststus code and message parse it for errors
public function respondWithMessage($message, $status)
{
return $this->respond([
'status_code' => $this->getStatusCode(),
'status' => $status,
'message' => $message
]);
}
}
But the response i'm getting is different as expected
//expected result
{
"status_code": "200",
"status": "success",
"message": "User details with dropdown data",
"data": {
"user_details": {
"id": 2017001,
"name": "User Name",
"email": "user#email.com",
},
"dropdown_data": {
}
}
}
//getting response
{
"0": {
"headers": {},
"original": {
"status_code": 200,
"status": "success",
"message": "Agent is active"
},
"exception": null
},
"data": {
"user_details": {
"id": 2017001,
"name": "User Name",
"email": "user#email.com",
},
"dropdown_data": {
}
}
}
the middleware
<?php
namespace App\Http\Middleware;
use Closure;
use Response;
use App\Http\Controllers\ApiController;
class UserStatus extends ApiController
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if($request->user() === null)
{
return $this->respondFailure();
}
if($request->user()->isActive($request->user()))
{
return $next($request);
}
return $this->respondFailure();
}
}
You are only appending the response from the respondSuccess() and not merging the response.
$this->setStatusCode(200)->respondWithMessage($message, $status);
on this response:
return Response::json([
$this->respondSuccess(), // i am append this information
'data' => [
'user_details' => $agent_percentage,
'dropdown_data' => [
'employment_types' => $employment_types->all(),
'roles' => $roles->all(),
'vehicle_brands' => $vehicle_brands->all(),
'vehicle_types' => $vehicle_types->all()
]
]
]);
It gives the response as you got not the response you expected.
To get the expected response you need to do something like this:
public function respondWithMessage($message, $status)
{
return [
'status_code' => $this->getStatusCode(),
'status' => $status,
'message' => $message
];
}
I have used only array and not $this->respond() because you only have this message:
"status_code": "200",
"status": "success",
"message": "User details with dropdown data",
For the type of response, you might need to merge the two arrays into one.
Look on array_merge() to get more understanding.
$responseMessage= $this->respondSuccess();
$data = ['data' => [
'user_details' => $agent_percentage,
'dropdown_data' => [
'employment_types' => $employment_types->all(),
'roles' => $roles->all(),
'vehicle_brands' => $vehicle_brands->all(),
'vehicle_types' => $vehicle_types->all()
]
]
];
$responseArray = array_merge(responseMessage, data);
return Response::json($responseArray);
I have not yet tested the code but this might give you some understanding of how to get the expected array response you want.
If I am wrong anyone could suggest the edit.
Related
I'm sending have an array of JSON objects that I'm POSTing to the DB with other data:
{
"emotions":[
{
"id":1,
"intensity":67,
"new_intensity":67
},
{
"id":2,
"intensity":67,
"new_intensity":67
},
{
"id":3,
"intensity":64,
"new_intensity":64
},
{
"id":4,
"intensity":64,
"new_intensity":64
},
{
"id":5,
"intensity":64,
"new_intensity":64
}
],
"situation":"An event",
}
What I want to do is validate both the situation and emotions[{},{}] json array:
Controller
public function store(Request $request)
{
$this->validate($request, [
'situation' => 'required',
]);
$data = ['data' => $request->input('emotions')];
$this->validate($data, [
'data.*.id' => 'digits:2|between:1,70',
'data.*.intensity' => 'digits:3|between:1,100',
'data.*.new_intensity' => 'digits:3|between:1,100'
]);
}
Error
Argument 1 passed to App\Http\Controllers\Controller::validate() must be an instance of Illuminate\Http\Request, array given
I'd like to be able to combine the two validating methods, but I have no idea how to do that as well?
Here is the answer I got my first try from
You can use array validators. Something like below code may help you achieve this
$validator = Validator::make($data, [
'data.*.id' => 'digits:2|between:1,70',
'data.*.intensity' => 'digits:3|between:1,100',
'data.*.new_intensity' => 'digits:3|between:1,100'
])
You can check whether it fails and do your desired action
if($validator->fails()){
// Do something
}
If consuming message fails message is re-queued with a delay by default.
Is there a way to add a counter to a message so I could know if message is on its last attempt?
This is desired behavior:
First attempt:
App\Message\Message {
body: array:2 [
"id" => 2
"alias" => "some_alias",
"attempt" => 0,
]
}
First retry:
App\Message\Message {
body: array:2 [
"id" => 2
"alias" => "some_alias",
"attempt" => 1,
]
}
Second retry:
App\Message\Message {
body: array:2 [
"id" => 2
"alias" => "some_alias",
"attempt" => 2,
]
}
Third retry:
App\Message\Message {
body: array:2 [
"id" => 2
"alias" => "some_alias",
"attempt" => 3,
]
}
Solution
messenger.yaml:
...
buses:
messenger.bus.default:
middleware:
# service ids that implement Symfony\Component\Messenger\Middleware
- 'App\Middleware\RetryMiddleware'
...
App\Middleware\RetryMiddleware:
namespace App\MessageMiddleware;
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Middleware\StackInterface;
use Psr\Log\LoggerInterface;
class RetryMiddleware implements MiddlewareInterface
{
public function handle(Envelope $envelope, StackInterface $stack): Envelope
{
try {
return $stack->next()->handle($envelope, $stack);
} catch (\Throwable $error) {
$msg = $envelope->getMessage();
$body = $msg->getBody();
$body['attempt']++;
$msg->setBody($body);
//rethrow same error
throw $error;
}
}
}
App\Message:
namespace App\Message;
class Message
{
public $body;
public function getBody()
{
return $this->body;
}
public function setBody(array $body): void
{
$this->body = $body;
}
}
I'm trying to write to a slide element.
I keep getting the error responses of "Invalid JSON payload received. Unknown name" and " Cannot bind query parameter. Field"
My request is
{
"requests": [
{
"deleteText": {
"objectId": "g33c4ea3b90_0_9",
"textRange": {
"type": "FROM_START_INDEX",
"startIndex": 0
}
}
},
{
"insertText": {
"objectId": "g33c4ea3b90_0_9",
"text": "$8.23",
"insertionIndex": 0
}
}
]
}
I am posting to: https://slides.googleapis.com/v1/presentations/PRESENTATION_ID:batchUpdate?access_token=ACCESS_TOKEN
I am manually cURLing the request in PHP:
$params = '
{
"requests": [
{
"deleteText": {
"objectId": "'.$page_object_id.'",
"textRange": {
"type": "FROM_START_INDEX",
"startIndex": 0
}
}
},
{
"insertText": {
"objectId": "'.$page_object_id.'",
"text": "$8.23",
"insertionIndex": 0
}
}
]
}
';
$options = array(
CURLOPT_RETURNTRANSFER => true, // return web page
CURLOPT_HEADER => false, // don't return headers
CURLOPT_FOLLOWLOCATION => true, // follow redirects
CURLOPT_MAXREDIRS => 10, // stop after 10 redirects
CURLOPT_ENCODING => "", // handle compressed
CURLOPT_AUTOREFERER => true, // set referrer on redirect
CURLOPT_CONNECTTIMEOUT => 120, // time-out on connect
CURLOPT_TIMEOUT => 120, // time-out on response
CURLOPT_CUSTOMREQUEST => 'POST' ,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false ,
CURLINFO_HEADER_OUT => true ,
CURLOPT_VERBOSE => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $params
);
$ch = curl_init($url);
curl_setopt_array($ch, $options);
$content = curl_exec($ch);
curl_close($ch);
$obj = json_decode($content, true);
print_r( $obj );
When I call it from the API Explorer it works perfectly, but not from my server.
So the problem was the use of double quotes instead of single quotes in the request parameter json string.
So the following works:
{
'requests': [
{
'deleteText': {
'objectId': 'g33c4ea3b90_0_9',
'textRange': {
'type': 'FROM_START_INDEX',
'startIndex': 0
}
}
},
{
'insertText': {
'objectId': 'g33c4ea3b90_0_9',
'text': '$44.23',
'insertionIndex': 0
}
}
]
}
I had been working on this for two days.
I'm adding a REST API onto an existing cakephp codebase.
It is working as I expect. I hit /api/v1/contacts/12312 and get json data back for contact 12312. If put an id of a contact that doesn't exist then I get the html 404 page error rather than json.
This happens internally on the contacts->get($id) line.
In the api app controller I have
public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
$this->loadComponent('Crud.Crud', [
'actions' => [
'Crud.Index',
'Crud.View',
'Crud.Add',
'Crud.Edit',
'Crud.Delete'
],
'listeners' => [
'CrudJsonApi.JsonApi',
'CrudJsonApi.Pagination', // Pagination != ApiPagination
'Crud.ApiQueryLog',
],
'Error' => [
'errorLevel' => E_ALL,
'exceptionRenderer' => 'CrudJsonApi\Error\JsonApiExceptionRenderer',
'skipLog' => [],
'log' => true,
'trace' => true,
],
]);
$this->Crud->config(['listeners.jsonApi.exceptionRenderer' => 'CrudJsonApi\Error\JsonApiExceptionRenderer']);
$this->setJsonResponse();
}
public function beforeRender(Event $event)
{
$this->RequestHandler->renderAs($this, 'json');
$this->response->type('application/json');
$this->set('_serialize', true);
}
I thought using the JsonApiExceptionRenderer 404 errors would be handled with json output.
Also the Pagination works but the Pagination data isnt returned with the response...
{
"viewVar": "crmContacts",
"crmContacts": [
{
"id": 1,
"lastname": "testname1"
},
{
"id": 2,
"lastname": "smith"
}
],
"success": true
}
Any ideas?
Thanks
I'm trying to use a custom FormRequest with validation rules for JSON formatted data. If I use same code in controller instead of the FormRequest class then it works fine, see below:
array data (from ajax request):
[
{
"name": "id",
"value": "1"
},
{
"name": "title",
"value": "My fun project"
}
]
Controller:
public function update(Request $request, $id) {
//convert it to readable json
$jsonReq = $request->json()->all();
$jsonData = array();
foreach ($jsonReq as $json) {
$jsonData[$json["name"]] = $json["value"];
}
$rules = [
'id' => 'required|numeric:1',
'title' => 'required|max:255',
];
$validation = Validator::make($jsonData, $rules);
if ($validation->fails()) {
return $validation->errors();
}
}
Above works fine when used in the controller. However, I want to separate my validation in a separate class, extending the FormRequest. This generates some errors, most likely due to the array format.
class UpdateProjectValidationRequest extends FormRequest {
public function rules() {
$jsonReq = $this->json()->all();
$jsonData = array();
foreach ($jsonReq as $json) {
$jsonData[$json["name"]] = $json["value"];
}
return [
'id' => 'required|max:1', //does not work
$jsonData['title'] => 'required|max:255', //does not work
];
}
Controller:
public function update(UpdateProjectValidationRequest $request, $id) {
// validate against rules
$request->rules();
The error message:
{
"message": "The given data was invalid.",
"errors": {
"My fun project": [
"My fun project field is required."
],
"id": [
"The id field is required."
],
Clearly this has to do with the format. Any ideas how to solve this? Note that after the foreach loop the data is formatted to below:
{
"id": "1",
"title": "My Fun project",
}
Ok so i could not solve it using the laravel FormRequest, instead I modified the ajax call itself by serializing it to json instead of an array.
$.fn.serializeObject = function()
{
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name] !== undefined) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return o;
};
//old: var formdata = JSON.stringify(jQuery('#myForm').serializeArray());
var formdata = JSON.stringify(jQuery('#myForm').serializeObject());