YII 2.0 REST API error handler - php

How to set a REST API error handler, when API used as a module.
I'm getting an invalid 404 found exception in HTML response rather than a json/xml response.
this is the sample api URL with an invalid entry point
http://localhost.backend.com/api/v1/invalidentrypoint
here api is in a module and v1 in nested with api module.
the reponse is
Not Found (#404)
Unable to resolve the request "api/v1/invalidentrypoint".
The above error occurred while the Web server was processing your request.
Please contact us if you think this is a server error. Thank you.
I'm expecting a response like
**HTTP/1.1 404 Not Found
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8
{
"type": "yii\web\NotFoundHttpException",
"name": "Not Found Exception",
"message": "The requested resource was not found.",
"code": 0,
"status": 404
}**
please help.

Have you tried setting the response format to json?
just add to the config:
'response' => [
'format' => \yii\web\Response::FORMAT_JSON
]
here's some info from the yii documentation:
https://github.com/yiisoft/yii2/blob/master/docs/guide/rest-error-handling.md
Edit: using the yii define from ethan's comment
the define is "json" but it's a good pratice to use the defined const from Yii

I add the following to the constructor of my API Controller(s):
public function __construct(string $id, Module $module, array $config = [])
{
parent::__construct($id, $module, $config);
\Yii::$app->response->format = Response::FORMAT_JSON;
}
This allows me to specify JSON error responses for individual controllers.

Related

FCM HTTP v1 Batch request won't work in PHP

I'm using currently the Firebase messaging with PHP. I was able to make it work with a single notification with PHP and cURL. I've read the documentation about making batch request and I've constructed the request string as follow:
--subrequest_boundary
Content-Type: application/http
Content-Transfer-Encoding: binary
Authorization: Bearer ya29.xxxxxnY
POST /v1/projects/xxxxxxxx/messages:send
Content-Type: application/json
accept: application/json
{
"message":{
"token":"cxxxxx3",
"data":{
"typeNoti":"paiement",
"idcompte":"admin",
"typecompte":"paiement"
},
"notification":{
"title":"Test1",
"body":"Notification de test 1"
}
}
}
--subrequest_boundary
Content-Type: application/http
Content-Transfer-Encoding: binary
Authorization: Bearer yaxxxxxxY
POST /v1/projects/xxxxxx/messages:send
Content-Type: application/json
accept: application/json
{
"message":{
"token":"eoxxxxxU1",
"data":{
"typeNoti":"paiement",
"idcompte":"compte2",
"typecompte":"paiement"
},
"notification":{
"title":"Test1",
"body":"Notification de test 1"
}
}
}
--subrequest_boundary--
This string is generated in a file called batch_request.txt as the documentation said. When trying to send the request with cURL I receive this error:
{
"error": {
"code": 400,
"message": "Failed to parse batch request, error: 0 items. Received batch body: (0) bytes redacted",
"status": "INVALID_ARGUMENT"
}
}
I've experienced a strange behavior also, which is when I construct that string manually (in PHP I use HEREDOC), the batch request does occurs with 200ok response. I've tried to find some hidden character but couldn't.
I know there is a library called firebase-php. The problem with it is that I cannot find a straight foreward example like this:
//authenticate with json file
//create new token if it doesn't exist or skip
//create notification array
//create data array
//send multi notifications to multiple devices
I actually use a for loop and mono notification (one device token, one message at a time). The problem with this is that not all notifications are sent.
I appreciate your help thanks!
I gathered the code from firebase-php docs. After installing the library with composer I get a lot of errors and a lot of missing files in Firebase directory inside vendor like Factory.php etc
My solution was to NOT USE firebase-php library due to the numerous bugs I've faced (or maybe misuses) neither to construct the REST request text file for batch request. I used instead the NodeJS SDK which worked like a charm. I'm running a javascript file from my php code using exec.

Client error: bad request. Error 400. NoCaptcha Laravel Anhskohbo

I connect the re-captcha to the site, which is built on Laravel. And when you click on "I am not a robot", and then on "registration", this error appears.
In the past, I connected the re-captcha on the framework yii2. I had no such problems with exceptions. Now I Installed captcha - Anhskohbo NoCaptcha.
The error itself looks like a notification:
Client error: POST https://www.google.com/recaptcha/api/siteverify resulted in a 400 Bad Request response:
{
"success": false,
"error-codes": [
"bad-request"
]
}
According to the Google reCAPTCHA documentation, this error is given when the request is malformed. Can you check what values are being passed to the /siteverify endpoint? The first thing that comes to mind is that the Content-Type: header for the request to Google's endpoint should be application/x-www-form-urlencoded as per this response - this is also true in my experience.

Docusign INVALID_REQUEST_BODY after adding eventNotification

While trying to add webhook status to a nicely working Docusign integration API, it started to give me a the error INVALID_REQUEST_BODY.
As I'm using the PHP API, I'm not writing the JSON payload myself, Docusign PHP package is responsible for serializing the thing, but, it says INVALID_REQUEST_BODY, pointing to here:
"eventNotification":[{"url":"https:\/\/xxx.yyyy.zzz.com\/docusign\/webhook",
^
I also tried to remove everything else, sending only the url parameter. Tried to change the URL, sending only a domain. Nothing worked. If I send the event notification I get the error, if I don't send it, everything works fine.
And the Docusign PHP package raises exceptions if you send wrongly named items to it, so, I'm also sure the EventNotification model is pretty much correct.
Here's the full error message, without sensitive data:
[DEBUG] HTTP Request body ~BEGIN~
{"documents":[{"documentId":1,"name":"XXXXXXXXXX.pdf","documentBase64":"XXXXXXXX="}],"recipients":{"signers":[{"tabs":{"signHereTabs":[{"documentId":1,"recipientId":1,"pageNumber":1,"anchorString":"recipient_signature"}]},"name":"xxxxxxxxx","email":"xx#xxxxxxxx.com","recipientId":1,"clientUserId":XXXX}]},"eventNotification":[{"url":"https:\/\/xxx.yyyy.zzz.com\/docusign\/webhook","loggingEnabled":"true"}],"status":"sent","emailSubject":"XXXXXX - XXXXXX Certification","brandId":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}
~END~
* Hostname demo.docusign.net was found in DNS cache
* Trying 162.248.186.25...
* TCP_NODELAY set
* Connected to demo.docusign.net (162.248.186.25) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate: demo.docusign.net
* Server certificate: Symantec Class 3 EV SSL CA - G3
* Server certificate: VeriSign Class 3 Public Primary Certification Authority - G5
> POST /restApi/v2/accounts/XXXXXX/envelopes HTTP/1.1
Host: demo.docusign.net
User-Agent: PHP-Swagger/2.0.0
X-DocuSign-Authentication: {"Username":"dev#xxxx.com","Password":"xxxxxxx","IntegratorKey":"XXX-XXXXXXXX-XXX-XXXX-xxxxx-xxxxxxxxxxxx"}
X-DocuSign-SDK: PHP
Accept: application/json
Content-Type: application/json
Content-Length: 3981
Expect: 100-continue
< HTTP/1.1 100 Continue
* We are completely uploaded and fine
< HTTP/1.1 400 Bad Request
< Cache-Control: no-cache
< Content-Length: 725
< Content-Type: application/json; charset=utf-8
< X-DocuSign-TraceToken: c227xxxx
< Date: Wed, 05 Apr 2017 00:13:16 GMT
< Strict-Transport-Security: max-age=31536000; includeSubDomains
<
* Curl_http_done: called premature == 0
* Connection #0 to host demo.docusign.net left intact
[DEBUG] HTTP Response body ~BEGIN~
{
"errorCode": "INVALID_REQUEST_BODY",
"message": "The request body is missing or improperly formatted. Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'API_REST.Models.v2.eventNotification' because the type requires a JSON object (e.g. {\"name\":\"value\"}) to deserialize correctly.\r\nTo fix this error either change the JSON to a JSON object (e.g. {\"name\":\"value\"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.\r\nPath 'eventNotification', line 1, position 3790."
}
So what's happening?
You are incorrectly using the eventNotification parameter as an array.
The following should work. I have removed the square braces []
"eventNotification": {
"url": "https:\/\/xxx.yyyy.zzz.com\/docusign\/webhook",
"loggingEnabled": "true"
}
Here is your complete request
{
"documents": [ { "documentId": 1, "name": "XXXXXXXXXX.pdf", "documentBase64": "XXXXXXXX=" } ],
"recipients": {
"signers": [
{
"tabs": {
"signHereTabs": [
{
"documentId": 1,
"recipientId": 1,
"pageNumber": 1,
"anchorString": "recipient_signature"
}
]
},
"name": "xxxxxxxxx",
"email": "xx#xxxxxxxx.com",
"recipientId": 1,
"clientUserId": XXXX
}
]
},
"eventNotification": {
"url": "https:\/\/xxx.yyyy.zzz.com\/docusign\/webhook",
"loggingEnabled": "true"
},
"status": "sent",
"emailSubject": "XXXXXX - XXXXXX Certification",
"brandId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

Response::json() sending html instead of json

Using Laravel 4, return Response::json(array('foo' => 'bar')) used in one controller will return actual application/json, whereas in another controller, for another action, it will return text/html. Both actions are called via Ajax.
In the faulty controller, I tried to force the content-type with this snippet:
[...]
$response = Response::json($data);
$response->header('Content-Type', 'application/json');
$response->header('Content-Foo', 'Bar'); // test if additional headers are really set
Log::info($response);
return $response;
... while working controller returns correct Json response with:
return Response::json($data);
In both, $data is an array (tested).
Logged response from the faulty controller is:
HTTP/1.0 200 OK
Cache-Control: no-cache
Content-Foo: Bar
Content-Type: application/json
Date: Wed, 17 Sep 2014 10:55:03 GMT
But received response (in Firebug / DevTools) is:
Connection Keep-Alive
Content-Type text/html
Date Wed, 17 Sep 2014 10:55:03 GMT
Keep-Alive timeout=5, max=93
Server Apache/2.2.25 (Unix) mod_ssl/2.2.25 OpenSSL/0.9.8y DAV/2 PHP/5.5.3
Transfer-Encoding chunked
X-Powered-By PHP/5.5.3
I tried to directly return Response::json(array('foo' => 'bar')) at the beginning of the faulty controller action but it still sends the response as text/html.
I would like to know why would the content-type switch from application/json to text/html for no reason? And why the mock header isn't in the received response?
-- EDIT --
The problem seems to be located around the validator.
public function faultyAction()
{
if(!Request::ajax()) App::abort(405);
$validator = Validator::make(
array('trackfile' => Input::file('trackfile')),
array('trackfile' => 'required|audio')); // audio is a custom validator
if($validator->fails())
{
Log::info('validation failed!');
return Response::json(array('code' => 1, 'message' => 'File validation has failed.'));
}
else
{
Log::info('validation passed!');
return Response::json(array('code' => 0, 'filename' => 'test'));
}
}
... returns text/html response while validation passed.
public function faultyAction()
{
if(!Request::ajax()) App::abort(405);
$validator = Validator::make(
array('trackfile' => Input::file('trackfile')),
array('trackfile' => 'required|audio')); // audio is a custom validator
return Response::json(array('code' => 0, 'filename' => 'test'));
}
... returns application/json.
How comes the same response is returned with different content-type depending on where it is called in the code?
May it come from $validator->fails() (even if nothing seems to alter the headers or to print something in the Laravel's Validator.php code)?
Hi basically using Response::json() with an array of data as parameter is enough.
Defining again the Content-type header is useless, Response::json is supposed to set it right by default.
I'm creating json responses on my project right now and so far it went fine.
Just to be clear the faulty controller returns the good value with a wrong content-type header, right ?
Can you try again using just Response::json and can you tell which exact laravel version are you using ?
Hi again i'm editing my first answer based on your replies :
you should test something like this :
$json = json_encode($yourArray);
// first check the $json variable with var_dump() oro Log::info() to see if you have the space problem. Then you can create the response.
$response = Response::make($json, 200);
$response->header('Content-Type', 'application/json');
return $response;
Hope it helps...
It may not be the case for OP, but this is a best search result for json response sent as text/html. I just spent considerable amount of time debugging this issue in Laravel 9 with php 8.2
One possible reason for wrong content type is hidden somewhere in php magic goo. In another words, how it handles sending response headers.
If you have whitespace anywhere before or after php opening or closing tag, respectively, the headers will be sent and you cant modify them anymore. This is why it is recommended to not use php closing tag in multi file applications, but this does not help for whitespace before opening tag:
<?php
Now if your framework, like Laravel, checks with headers_sent(), before modifying headers for you, the result is, drumm roll: text/html, with no errors anywhere.
To identify the problem, try setting headers yourself, with header(), somewhere at the end of call stack. It should then fail and tell you in which file the headers are already sent. For me the culprit was hidden in one of the lang files.

Connecting to an ASP.Net web service from PHP and retrieving data as JSON

I'm having issues connecting to an ASP.Net web service using PHP.
The web service is known to be operational, since it's returning data when we connect using Javascript from the same domain, but when I attempt to connect using PHP I receive the following error:
HTTP/1.1 500 Internal Server Error Content-Type: application/json; charset=utf-8 Server: Microsoft-IIS/7.5 jsonerror: true X-Powered-By: ASP.NET Date: Tue, 17 May 2011 03:40:17 GMT Connection: close Content-Length: 819
{"Message":"Invalid JSON primitive: birthday.","StackTrace":" at System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializePrimitiveObject()\
[etc]
The Content-Type is set to "application/json; charset=utf-8" in PHP, and we are trying to send a parameter called "birthday" using the following POST data in PHP:
$post_data = array(
'birthday' => 'none'
);
I think the ASP web service is not able to parse the 'birthday' parameter for some reason, but I'm not sure why.
Do I need to explicitly encode the POST data as JSON from PHP before calling the web service?
Thanks.
May be this web service takes the post data in Json format. If it is then you should use
$post_data = array( 'birthday' => 'none' );
$jsonData = json_encode ($post_data );
for details json_encode

Categories