In the first two posts of this series, we discussed how to route REST requests to controllers and return HTTP response code. In this article I will talk about managing API keys.
Having the clients send API key within the HTTP header is convenient to handle. We can quickly check the HTTP request header and decide whether to allow or deny the request.
As a prerequisite you should be familiar writing front controller plugins. Let's write a front controller plugin that does the following:
We will not perform any changes to our previous article controller.
Let's start writing code.
Step 1: Write the front controller plugin.
Create the directory library/My/Controller/Plugin.
Inform the autoloader about the namespace 'My'. Also, register the plugin "My_Controller_Plugin_RestAuth". Let's add these lines to our configuration file application/configs/application.ini generated by Zend_Tool(or the quick start guide).
autoloadernamespaces.1 = "My_" resources.frontController.plugins = "My_Controller_Plugin_RestAuth"
Let's write the front controller plugin. Create and edit the file library/My/Controller/Plugin/RestAuth.php
<?php
class My_Controller_Plugin_RestAuth extends Zend_Controller_Plugin_Abstract
{
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$apiKey = $request->getHeader('apikey');
if ($apiKey != 'secret') {
$this->getResponse()
->setHttpResponseCode(403)
->appendBody("Invalid API Key\n")
;
$request->setModuleName('default')
->setControllerName('error')
->setActionName('access')
->setDispatched(true);
}
}
}
?>In our front controller plugin, we hook into the preDispatch() method. Before a controller action is executed, our Predispatch() method is called.
In our preDispatch() method, we check whether the HTTP request header contains the key 'apikey' with value 'secret'. If the request does not have the correct API key we set the 403 HTTP response code and set the controller and action to 'error' and 'access' respectively. We also set the dispatched status to true.
Step 2: Add the 'access' action to the error controller in application/controllers/ErrorController.php.
<?php
public function accessAction()
{
$this->_helper->ViewRenderer->setNoRender(true);
}
?>In the sample code, we simply disable the view. In your application, you could perform logging in the access action of the error controller.
Step 3: Let's test our application using cUrl.
Make a request without sending the 'apikey' HTTP header.
curl http://zfrest.example.com/article -v
The sample output of the above command looks like:
* About to connect() to zfrest.example.com port 80 (#0) * Trying 127.0.0.1... connected * Connected to zfrest.example.com (127.0.0.1) port 80 (#0) > GET /article HTTP/1.1 > User-Agent: curl/7.19.7 (i386-redhat-linux-gnu) libcurl/7.19.7 NSS/3.12.4.5 zlib/1.2.3 libidn/1.9 libssh2/1.2 > Host: zfrest.example.com > Accept: */* > < HTTP/1.1 403 Forbidden < Date: Mon, 01 Mar 2010 08:46:03 GMT < Server: Apache/2.2.14 (Fedora) < X-Powered-By: PHP/5.3.1 < Content-Length: 16 < Connection: close < Content-Type: text/html; charset=UTF-8 < Invalid API Key * Closing connection #0
We recieved the HTTP response code 403 with the body content 'Invalid API Key'.
Let's make another test. This time, let's add the correct API key in the request HTTP header.
curl -H "apikey: secret" http://zfrest.example.com/article -v
Using the -H switch, we can send headers.
The output :
* About to connect() to zfrest.example.com port 80 (#0) * Trying 127.0.0.1... connected * Connected to zfrest.example.com (127.0.0.1) port 80 (#0) > GET /article HTTP/1.1 > User-Agent: curl/7.19.7 (i386-redhat-linux-gnu) libcurl/7.19.7 NSS/3.12.4.5 zlib/1.2.3 libidn/1.9 libssh2/1.2 > Host: zfrest.example.com > Accept: */* > apikey: secret > < HTTP/1.1 200 OK < Date: Mon, 01 Mar 2010 08:57:15 GMT < Server: Apache/2.2.14 (Fedora) < X-Powered-By: PHP/5.3.1 < Content-Length: 20 < Connection: close < Content-Type: text/html; charset=UTF-8 < * Closing connection #0 all articles content
This time we received the HTTP response code 200 with body content 'all articles content'.
Reference:
Writing front controller plugins
Shouldn't an X-.... http
Shouldn't an X-.... http custom header being used?
Re: Shouldn't an X-.... http
Giorgio,
Thanks for the comment.
Custom HTTP header x-apikey makes more sense.
Thanks !! Great Stuff
Hi Sudheer,
This is a great stuff and thanks for the POST. I tried implementing, and it worked great!!!
Thanks !!
I have a query for you, can we expand this functionality to work together with Zend_OAuth also? If so, pls give a small example. Your suggestion will be a great help for me.
Re: Thanks !! Great Stuff
Hi Vineela,
You're welcome.
I wouldn't recommend extending this example to use OAuth. I will try to cover Zend_Oauth in a future article.
Thanks for the comment.
Re:Zend_OAuth
Hi Sudheer,
Will be eagerly waiting for a sample Application using Zend_OAuth.
Thanks,
reply
your post is too nice and it helped me a lot
mcse
Can you please explain me the
Can you please explain me the curl commands for PHP ?
The tutorial is great, but would have been better using actual php curl calls, rather than the shell.
Thanks.
I will cover writing REST
I will cover writing REST clients using PHP in the upcoming posts.
First, thanks for the
First, thanks for the articles.
I'm very interested in this as well. For example, let's say I want to write a PHP client to interact with my REST API via POST. What should the postAction do if the supplied data is invalid? I understand sending out a response code (400?), but what should the response body contain? Ideally it would contain the supplied values for each param and any associated error codes, but I'm not sure how to do this. I'm also not sure how to then use that data. For example, let's say my client was a ZF controller with a Zend_Form in it. My controller posts to my REST controller via curl, and receives a response with errors ... how do I use the response to populate my form/view? The same could be asked if I posted via ajax, but updating view would have to be done via JS, so that may be too much to cover.
Overall, I think it would be great if the next article focused on actually building a client to interact with the api. Good stuff.
Thanks for the comment. It is
Thanks for the comment.
It is hard to answer all the questions in a comment reply. Like you say, the next few posts in this series should cover returning responses in detail.
@rob: This may be helpful, check it out
Hi Rob, This REST Client code may be useful to you.
<?php
/**
*
* THIS IS AN EXAMPLE AS HOW TO CALL A REST CALL - POST METHOD
*/
$url = 'http://www.helloworld.com/article';
$fields_string = '';
$ch = curl_init();
$headers[] = array('apikey' => 'secret');
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("apikey: secret")); // this is for the API key
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch,CURLOPT_POST,'');
curl_setopt($ch,CURLOPT_POSTFIELDS,$fields_string);
$result = curl_exec($ch);
curl_close($ch);
echo($result).'';
?>
<?php
/**
* this is to make GET call
**/
$url = 'http://www.helloworld.com/article/1';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("apikey: secret")); // this is for the API key
$result = curl_exec($ch);
curl_close($ch);
echo($result).'';
?>
<?php
/**
* THIS IS TO HAVE A PUT CALL
**/
/**
$xml = 'Hello World! Watch me PUT this here.';
$fh = fopen('php://memory');
fwrite($fh, $xml);
rewind($fh);
**/
$ch = curl_init('http://www.helloworld.com/article');
curl_setopt($ch, CURLOPT_HTTPHEADER, array("apikey: secret")); // this is for the API key
curl_setopt($ch, CURLOPT_PUT, true);
//curl_setopt($ch, CURLOPT_INFILE, $fh);
//curl_setopt($ch, CURLOPT_INFILESIZE, strlen($xml));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
echo curl_exec($ch);
curl_close($ch);
//fclose($fh);
?>
<?php
/**
* THIS IS FOR HTTP - DELETE
**/
$request = 'http://www.helloworld.com/article/1';
$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL, $request);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("apikey: secret")); // this is for the API key
curl_setopt ($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)");
//curl_setopt ($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
//curl_setopt ($ch, CURLOPT_USERPWD, $this->requestLogin);
curl_setopt ($ch, CURLOPT_HEADER, 0);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_HTTPHEADER, Array("Content-Type:application/atom+xml"));
curl_setopt ($ch, CURLOPT_FAILONERROR, 1);
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
echo curl_exec ($ch);
?>
Thankee.
Thanks for the helpful series of REST articles! Sudheer.
401 Unauthorized
Similar to 403 Forbidden, but specifically for use when authentication is possible but has failed or not yet been provided. The response must include a WWW-Authenticate header field containing a challenge applicable to the requested resource.
http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_Error
Get xml format
Your series of posts are very useful... first iam appreciating your efforts.
I have used the GET type of curl request, and i want the response as xml foramt... iam using Zend Rest Controller... how can i achieve this.
You could create the XML
You could create the XML document and pass it on to the view. Optionally, you can directly send the response from the controller. If I were to send a lot of XML documents, I would make an action helper.
How to do curl Authentication?
Thanks for your reply sudheer.
I want to know how to retrieve the username and password for validating a user.
See, we are sending the credentials as part of a curl request (CURLOPT_USERPWD) and how can we retrieve these values in our next page, and where we need to check these values, in database or any other source, for verification?
Please help :)
stateless
One of the REST constraints is statelessness. No client context is stored on the server between requests. You have to send the credentials in every request.
Cool...
Thanks for ur answer sudheer, i actually want to know how do i fetch the username and password that i pass as request to a page, through curl. And i got my solution here:
http://stackoverflow.com/questions/4942417/curl-http-authentication-with...
Post new comment