Zend Framework REST service HTTP status code problem - php

I'm trying to create a REST service in zend framework. I'm using zend server.
Here's my code:
class ArticleController extends Zend_Rest_Controller
{
public function postAction()
{
//Create the acticle and return it
$data = array("foo" => 0, "boo" => 11);
$this->getResponse()->setHttpResponseCode(201);
$this->_helper->json($data);
}
The HTTP response returns the appropriate headers and JSON data but under the JSON data there's an apache error document.
The only way I can think of to remove the appended error document is to add the following in my httpd.conf file:
ErrorDocument 201 " "
But what's the "corrent" way of doing this?

Your original way is correct. 201 is an appropriate response after POSTing a new resource.
I think that the Error document which you see generated after your own content should not be there. Are you running Zend Server Community Edition v5.0 by any chance? If yes, then see this thread, I think that you encountered the same problem as the other guy there:
How to turn off default HTTP status code errors in Zend Server?

Why are you using code 201? 201 means you have created a resource for the request and are providing a link to it. If you have the article and are returning it you should just use 200.
Otherwise, what you're doing seems like the correct way, you remove the ErrorDocument associated with status-code 201.

Related

Laravel forcing json response for api

I'm building an api at my company using laravel.
The problem I'm encountering is that if you send an api request without defining the correct header with the request you will get html back if there is a failure e.g. authorization failure or findOrFail() failure.
My thinking is that you never want to return html (even if the user has the wrong header).
I have a couple of solutions. In BeforeMiddleware.php I can manually insert a header into the request such as:
// Check if we are on an api route
$apiRoute = strncmp($uri, '/api/', 5) == 0;
// Insert the request header to force json response
if ($apiRoute){
$language = $request->header->add('Accept', 'application/json');
}
The 2nd solutions would be to throw an error if they don't have the correct header.
What would be the best way to enforce a json response, what is a good practice for handling api responses in laravel?
Once you detected that you are on your api path you are out of the woods and can indeed tackle your problem in the app\Exceptions\Handler.php file like suggested on How do you force a JSON response on every response in Laravel?.
For an open source project I created JSON exception objects by Microsoft format as output, but you can choose the jsonapi format (http://jsonapi.org/examples/#error-objects-basics) as you like:
https://github.com/StadGent/laravel_site_opening-hours/blob/develop/app/Exceptions/Handler.php
(note that on this implementation it is indeed depending from the headers, but you can use your path detection I think)

Invoking WCF service with PHP (with federated security)

I’m trying to invoke a WCF service (.NET) from PHP. It’s a little more complicated than just using a SoapClient since the service uses a WS2007FederationHttpBinding to authenticate.
Here’s the code I’m using at the moment. I haven’t even added credentials as I’m not sure how, but regardless, I’m not even at the point where I’m getting access denied errors.
$wsdl = "https://slc.centershift.com/sandbox40/StoreService.svc?wsdl";
$client = new SoapClient($wsdl,array(
//'soap_version'=>SOAP_1_2 // default 1.1, but this gives 'Uncaught SoapFault exception: [HTTP] Error Fetching http headers'
));
$params = array();
$params['SiteID'] = 123;
$params['GetPromoData'] = false;
$ret = $client->GetSiteUnitData(array('GetSiteUnitData_Request'=>$params));
print_r($ret);
Which WSDL should I be pointing to?
https://slc.centershift.com/Sandbox40/StoreService.svc?wsdl
Seems to be very short, but includes a reference to (note the wsdl0) https://slc.centershift.com/Sandbox40/StoreService.svc?wsdl=wsdl0
https://slc.centershift.com/Sandbox40/StoreService.svc?singleWsdl
Seems to have everything in it.
Do I need to specify SOAP 1.2? When I do, I get a connection timeout ([HTTP] Error Fetching http headers). When I don’t, the default of SOAP 1.1 is used and I get a [HTTP] Cannot process the message because the content type 'text/xml; charset=utf-8' was not the expected type 'application/soap+xml; charset=utf-8'. Is this because I’m not authenticated yet, or because I’m using the wrong SOAP version?
How to authenticate in PHP? Here’s the corresponding .NET/C# code. Do I need to somehow put these as SOAP headers? Or am I thinking about it all wrong, and I need to do some kind of authentication before I even call the method (from what I read, I’m supposed to get a token back and then use it for all future method calls – I think I see an example of this in an answer here on Stack Overflow.
If I call $client->__getFunctions(), using either WSDL and either SOAP version, I’m getting a valid list of all functions, so I assume either of these is fine and my real issue is the authentication.
Other programmers I’ve talked to had spent time trying to get this to work, but gave up and instead implemented a proxy in .NET. They pass their parameters from PHP to their own unsecured .NET service, which in turn calls this secure service. It works, but seems crazily inefficient to me, and counter-productive, as the purpose of WCF is to support all types of clients (even non-HTTP ones!).
I’ve read How to: Create a WSFederationHttpBinding on MSDN, but it didn’t help.
You can use this URL for WSDL https://slc.centershift.com/Sandbox40/StoreService.svc?singleWsdl. This WSDL has all definitions.
You have to use 1.2 because this webservice works with SOAP 1.2 version. I tried it with 1.1 and 1.2 and both of them gived error. 1.1 is version error, 1.2 is timeout error. I think there is an error at this test server. I used it with svcutil to generate code but it gived error too. Normaly it should get information and generate the code example to call service.
Normally you can add authenticate parameters with SoapHeader or directly add to options in SoapClient consruct (if service authentication is basic authentication). I write below code according to your screenshot. But it gives timeout after long wait.
$wsdl = "https://slc.centershift.com/sandbox40/StoreService.svc?wsdl";
$client = new SoapClient($wsdl,array('trace' => 1,'soap_version' => SOAP_1_2));
$security = array(
'UserName' => array(
'UserName'=>'TestUser',
'Password'=>'TestPassword',
'SupportInteractive'=>false
)
);
$header = new SoapHeader('ChannelFactory','Credentials',$security, false);
$client->__setSoapHeaders($header);
$params = array();
$params['SiteID'] = 100000000;
$params['Channel'] = 999;
try {
$ret = $client->GetSiteUnitData($params);
print_r($ret);
}catch(Exception $e){
echo $e->getMessage();
}
__getFunctions works, because it prints functions defined in WSDL. There is no problem with getting WSDL information at first call. But real problem is communication. PHP gets WSDL, generates required SOAP request then sends to server, but server is not responding correctly. SOAP server always gives a response even if parameters or request body are not correct.
You should communicate with service provider, I think they can give clear answer to your questions.
Having worked with consuming .NET WS from PHP before I believe you would need to create objects from classes in PHP that matches the names that .NET is expecting. The WSDL should tell you the types it is expecting. I hope this assist with your path forward!
If the SOAP call works from a C# application, you could use Wireshark (with the filter ip.dst == 204.246.130.80) to view the actual request being made and then construct a similar request from php.
Check this answer to see how you can do a custom SOAP call.
There's also the option of doing raw curl requests, since it might be easier to build your xml body, but then you would have to parse the response yourself with simplexml.

CodeIgniter Web Services Client

I'm a newbie at CI, and I want to retrieve XML data from web services WebLogic, the server that is located at: http://services.insw.go.id/web-services/nsw?operation.invoke=getListGA . I want to to get the XML response from the server. How should I do this?
I made this function on controllers (resttest.php)
public function getRest()
{
$this->rest->initialize(array('server' => 'http://services.insw.go.id'));
$lartas = $this->rest->get('web-services/nsw',array('operation.invoke' => 'getListGA'),'xml');
die(var_dump($lartas));
}
Sometimes I get an error like "array(0) { }" and if I refresh, I get all HTML view, the same as when I browse to: http://services.insw.go.id/web-services/nsw?operation.invoke=getListGA
Am I wrong, or missing some step, or do you have any suggestion about how to change this code?
It looks as if your webservice is using SOAP (simple object access protocol). This is not REST. You'll want to use PHP's built in Soap extension with the SoapClient class. This way it's easy to post a XML "request" to that page which will return xml results rather than a html view (I assume).
Check Soap the soap extension is loaded on your server
Read about the SoapClient http://php.net/manual/en/class.soapclient.php
See if that webservice offers a WSDL (web service description language) file.
Create an instance of a soap client, using the wsdl and call the function you require.
Simple example from PHP.net
$client = new SoapClient("http://localhost/code/soap.wsdl");
$something = $client->HelloWorld(array());
echo $something->HelloWorldResult;
To get a xml response, you do not need Codeigniter. Specifically it provide WSDL. At http://services.insw.go.id/web-services/nsw you can find the example as
String wsdlUrl = "http://services.insw.go.id:80/web-services/nsw?WSDL";
So the WSDL API would be http://services.insw.go.id:80/web-services/nsw?WSDL
Then you can check this page to see how to install soap for your php.
Then you can get a xml response by the following code:
$client = new SoapClient('http://services.insw.go.id:80/web-services/nsw?WSDL');
//var_dump($client->__getFunctions());
$response = $client->getListGA();
echo $response;
these code do not need Codeigniter.
Note: $client->__getFunctions() will show you all functions that the WSDL support and the parameters the functions need.
Good luck

Can CakePHP 2.x Exceptions respond in the same request format?

I'm writing an API in Cake2.1.3 using the REST instructions in the docs. Having previously written one in Cake1.3, I would use the now-deprecated cakeError class to issue a response with an HTTP code in the format it was requested in. For example, if I requested http://example.com/widgets/view/invalid-code.json, cakeError would dispatch a 400 error code (and message) in the JSON format. Cake 2.x uses exceptions to handle this. According to the docs:
throw new BadRequestException()
issues a 400 HTTP code with a "Bad Request" message, but it only seems to do so in the HTML format. Can it automatically respond in the format it was requested in?
While you can do it with the selected answer, an easier way would be to let Cake render it automatically. Cake uses the same view finding rules when rendering exceptions. This means simply add a 'json' folder to the Error folder in your view, and create the appropriate view file.
/View
/Errors
/json
error404.ctp
error404.ctp
The error view could be something simple, like this:
<?php
echo json_encode(array(
'error' => array(
'name' => $name,
'url' => $url
)
));
Visiting /users/missing-page.json will then render the following json:
{"code":404,"url":"\/users\/missing-page.json","name":"Action UsersController::missing-page() could not be found."}
From my knowledge there's no way to do this automatically, but you could write your own exception handler that checks the request and outputs the appropriate content type.

PHP HTTP header REST

I am developing an UI for a REST repository using PHP and the PEAR HTTP REQUEST package (http://pear.php.net/package/HTTP_Request/).
I created a HTTP GET request and it delivers the requested rdf/xml file as expected. But I want to extend this request and I can't get this working.
The repository allows sending zip files which are attached to an id. So I have to call the same URL which delivers the rdf/xml data, but I have to change the HTTP GET header from xml to accept: application/zip, before executing my request. This should deliver the zip instead of the rdf/xml file.
$req =& new HTTP_Request();
$req->setMethod(HTTP_REQUEST_METHOD_GET);
$req->setURL($url);
$req->clearPostData();
if (!PEAR::isError($req->sendRequest())) {
$response2 = $req->getResponseBody();
} else {
$response2 = "";
}
echo $response2;
Does anyone know how to modify the GET call to get this done? I really need help!
Furthermore I want to create a HTTP PUT request which uses multipart/form-data. Does anyone know how to make this?
Please help me! Thanks!
For your first question, you can set the Accept field of your GET request header by:
$req->addHeader('Accept', 'application/zip');
# assuming that this will trigger the server to respond with the zip and not xml
Question number 2:
# Set method to PUT
$req->setMethod(HTTP_REQUEST_METHOD_PUT);
# Attach file to request
$req->addFile('file_upload_field', '/path/to/file.ext', 'application/zip');
Read up more on file uploads using HTTP_Request.
To modify the request headers, take a look at the addHeader() method of the HTTP_Request object: http://pear.php.net/manual/en/package.http.http-request.headers.php
To change the method, use the setMethod(): http://pear.php.net/package/HTTP_Request/docs/latest/HTTP_Request/HTTP_Request.html#methodsetMethod

Categories