You are viewing revision #15 of this wiki article.
This version may not be up to date with the latest version.
You may want to view the differences to the latest version or see the changes made in this revision.
- Information about REST
- Usefull Tools
- Requirements
- Setting up the URL Manager
- Create an API controller
- Implementing the Actions
- Additional Methods Needed
- Apache Issues
- Discussion
- Code Download
- Links
This article will explain how to create a REST API with the Yii framework.
Information about REST ¶
A good introduction about implementing REST service with PHP can be found on http://www.gen-x-design.com.
Usefull Tools ¶
To fire up a REST request to a Yii application, you can use the Firefox REST Client Addon.
If you want to send REST requests via a console, perhaps you might check cUrl.
Requirements ¶
We will create an API that allows us to
- Get all items of a certain model
- Get one single model item via its primary key (id)
- Create a new item
- Update an existing item
- Delete an existing item.
In this tutorial, we will use the Yii Blog demo application. Speaking of a model here means the Post model, i.e. creating and reading post items
The API shall be flexible enough that it can be extended easily to work on more different models, e.g. comments or user data.
All requests to the API shall use an authorization.
All right, let's get things going!
Setting up the URL Manager ¶
When using the API, we would like to have the following URL scheme:
- View all posts: index.php/api/posts (HTTP method GET)
- View a single posts: index.php/api/posts/123 (also GET )
- Create a new post: index.php/api/posts (POST)
- Update a post: index.php/api/posts/123 (PUT)
- Delete a post: index.php/api/posts/123 (DELETE)
In order to parse these URL's, set up the URL manager in config/main.php like this:
...
'urlManager'=>array(
'urlFormat'=>'path',
'rules'=>array(
'post/<id:\d+>/<title:.*?>'=>'post/view',
'posts/<tag:.*?>'=>'post/index',
// REST patterns
array('api/list', 'pattern'=>'api/<model:\w+>', 'verb'=>'GET'),
array('api/view', 'pattern'=>'api/<model:\w+>/<id:\d+>', 'verb'=>'GET'),
array('api/update', 'pattern'=>'api/<model:\w+>/<id:\d+>', 'verb'=>'PUT'),
array('api/delete', 'pattern'=>'api/<model:\w+>/<id:\d+>', 'verb'=>'DELETE'),
array('api/create', 'pattern'=>'api/<model:\w+>', 'verb'=>'POST'),
// Other controllers
'<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
),
),
...
Note that for all requests, we will get the requested model (e.g. posts) via the GET model parameter.
For the Get Single Item and Update Item method, we will receive the model's primary key via the GET id parameter.
Create an API controller ¶
In this tutorial, we will implement all REST methods in a new controller. Put this file in the controllers directory:
class ApiController extends Controller
{
// Members
/**
* Key which has to be in HTTP USERNAME and PASSWORD headers
*/
Const APPLICATION_ID = 'ASCCPE';
/**
* Default response format
* either 'json' or 'xml'
*/
private $format = 'json';
/**
* @return array action filters
*/
public function filters()
{
return array();
}
// Actions
public function actionList()
{
}
public function actionView()
{
}
public function actionCreate()
{
}
public function actionUpdate()
{
}
public function actionDelete()
{
}
}
Implementing the Actions ¶
Get all Models List Action ¶
public function actionList()
{
// Get the respective model instance
switch($_GET['model'])
{
case 'posts':
$models = Post::model()->findAll();
break;
default:
// Model not implemented error
$this->_sendResponse(501, sprintf(
'Error: Mode <b>list</b> is not implemented for model <b>%s</b>',
$_GET['model']) );
exit;
}
// Did we get some results?
if(is_null($models)) {
// No
$this->_sendResponse(200,
sprintf('No items where found for model <b>%s</b>', $_GET['model']) );
} else {
// Prepare response
$rows = array();
foreach($models as $model)
$rows[] = $model->attributes;
// Send the response
$this->_sendResponse(200, CJSON::encode($rows));
}
}
Get a Single Model Action ¶
public function actionView()
{
// Check if id was submitted via GET
if(!isset($_GET['id']))
$this->_sendResponse(500, 'Error: Parameter <b>id</b> is missing' );
switch($_GET['model'])
{
// Find respective model
case 'posts':
$model = Post::model()->findByPk($_GET['id']);
break;
default:
$this->_sendResponse(501, sprintf(
'Mode <b>view</b> is not implemented for model <b>%s</b>',
$_GET['model']) );
exit;
}
// Did we find the requested model? If not, raise an error
if(is_null($model))
$this->_sendResponse(404, 'No Item found with id '.$_GET['id']);
else
$this->_sendResponse(200, CJSON::encode($_GET['model']));
}
Create a new Model Action ¶
public function actionCreate()
{
switch($_GET['model'])
{
// Get an instance of the respective model
case 'posts':
$model = new Post;
break;
default:
$this->_sendResponse(501,
sprintf('Mode <b>create</b> is not implemented for model <b>%s</b>',
$_GET['model']) );
exit;
}
// Try to assign POST values to attributes
foreach($_POST as $var=>$value) {
// Does the model have this attribute? If not raise an error
if($model->hasAttribute($var))
$model->$var = $value;
else
$this->_sendResponse(500,
sprintf('Parameter <b>%s</b> is not allowed for model <b>%s</b>', $var,
$_GET['model']) );
}
// Try to save the model
if($model->save())
$this->_sendResponse(200,
$this->_getObjectEncoded($_GET['model'], $model->attributes) );
else {
// Errors occurred
$msg = "<h1>Error</h1>";
$msg .= sprintf("Couldn't create model <b>%s</b>", $_GET['model']);
$msg .= "<ul>";
foreach($model->errors as $attribute=>$attr_errors) {
$msg .= "<li>Attribute: $attribute</li>";
$msg .= "<ul>";
foreach($attr_errors as $attr_error)
$msg .= "<li>$attr_error</li>";
$msg .= "</ul>";
}
$msg .= "</ul>";
$this->_sendResponse(500, $msg );
}
}
Update a Model Action ¶
public function actionUpdate()
{
// Parse the PUT parameters
parse_str(file_get_contents('php://input'), $put_vars);
switch($_GET['model'])
{
// Find respective model
case 'posts':
$model = Post::model()->findByPk($_GET['id']);
break;
default:
$this->_sendResponse(501,
sprintf( 'Error: Mode <b>update</b> is not implemented for model <b>%s</b>',
$_GET['model']) );
exit;
}
// Did we find the requested model? If not, raise an error
if(is_null($model))
$this->_sendResponse(400,
sprintf("Error: Didn't find any model <b>%s</b> with ID <b>%s</b>.",
$_GET['model'], $_GET['id']) );
// Try to assign PUT parameters to attributes
foreach($put_vars as $var=>$value) {
// Does model have this attribute? If not, raise an error
if($model->hasAttribute($var))
$model->$var = $value;
else {
$this->_sendResponse(500,
sprintf('Parameter <b>%s</b> is not allowed for model <b>%s</b>',
$var, $_GET['model']) );
}
}
// Try to save the model
if($model->save())
$this->_sendResponse(200,
sprintf('The model <b>%s</b> with id <b>%s</b> has been updated.',
$_GET['model'], $_GET['id']) );
else
// prepare the error $msg
// see actionCreate
// ...
$this->_sendResponse(500, $msg );
}
Please keep in mind to check your model beforeSave
and afterSave
methods if any code eventually uses a logged-in user's id like the blog Post
model:
protected function beforeSave()
{
...
// author_id may have been posted via API POST
if(is_null($this->author_id) or $this->author_id=='')
$this->author_id=Yii::app()->user->id;
...
}
Delete a Model Action ¶
public function actionDelete()
{
switch($_GET['model'])
{
// Load the respective model
case 'posts':
$model = Post::model()->findByPk($_GET['id']);
break;
default:
$this->_sendResponse(501,
sprintf('Error: Mode <b>delete</b> is not implemented for model <b>%s</b>',
$_GET['model']) );
exit;
}
// Was a model found? If not, raise an error
if(is_null($model))
$this->_sendResponse(400,
sprintf("Error: Didn't find any model <b>%s</b> with ID <b>%s</b>.",
$_GET['model'], $_GET['id']) );
// Delete the model
$num = $model->delete();
if($num>0)
$this->_sendResponse(200,
sprintf("Model <b>%s</b> with ID <b>%s</b> has been deleted.",
$_GET['model'], $_GET['id']) );
else
$this->_sendResponse(500,
sprintf("Error: Couldn't delete model <b>%s</b> with ID <b>%s</b>.",
$_GET['model'], $_GET['id']) );
}
Additional Methods Needed ¶
Sending the Response ¶
How are the API responses actually sent? Right, we need to implement the _sendResponse method.
This code is borrowed from http://www.gen-x-design.com/archives/create-a-rest-api-with-php.
private function _sendResponse($status = 200, $body = '', $content_type = 'text/html')
{
// set the status
$status_header = 'HTTP/1.1 ' . $status . ' ' . $this->_getStatusCodeMessage($status);
header($status_header);
// and the content type
header('Content-type: ' . $content_type);
// pages with body are easy
if($body != '')
{
// send the body
echo $body;
exit;
}
// we need to create the body if none is passed
else
{
// create some body messages
$message = '';
// this is purely optional, but makes the pages a little nicer to read
// for your users. Since you won't likely send a lot of different status codes,
// this also shouldn't be too ponderous to maintain
switch($status)
{
case 401:
$message = 'You must be authorized to view this page.';
break;
case 404:
$message = 'The requested URL ' . $_SERVER['REQUEST_URI'] . ' was not found.';
break;
case 500:
$message = 'The server encountered an error processing your request.';
break;
case 501:
$message = 'The requested method is not implemented.';
break;
}
// servers don't always have a signature turned on
// (this is an apache directive "ServerSignature On")
$signature = ($_SERVER['SERVER_SIGNATURE'] == '') ? $_SERVER['SERVER_SOFTWARE'] . ' Server at ' . $_SERVER['SERVER_NAME'] . ' Port ' . $_SERVER['SERVER_PORT'] : $_SERVER['SERVER_SIGNATURE'];
// this should be templated in a real-world solution
$body = '
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>' . $status . ' ' . $this->_getStatusCodeMessage($status) . '</title>
</head>
<body>
<h1>' . $this->_getStatusCodeMessage($status) . '</h1>
<p>' . $message . '</p>
<hr />
<address>' . $signature . '</address>
</body>
</html>';
echo $body;
exit;
}
}
Getting the Status Codes ¶
Also, we need to implement the _getStatusCodeMessage method. This is pretty straight forward:
private function _getStatusCodeMessage($status)
{
// these could be stored in a .ini file and loaded
// via parse_ini_file()... however, this will suffice
// for an example
$codes = Array(
200 => 'OK',
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
500 => 'Internal Server Error',
501 => 'Not Implemented',
);
return (isset($codes[$status])) ? $codes[$status] : '';
}
Authentication ¶
If we want to have the API user authorize himself, we could write something like this:
private function _checkAuth()
{
// Check if we have the USERNAME and PASSWORD HTTP headers set?
if(!(isset($_SERVER['HTTP_X_USERNAME']) and isset($_SERVER['HTTP_X_PASSWORD']))) {
// Error: Unauthorized
$this->_sendResponse(401);
}
$username = $_SERVER['HTTP_X_USERNAME'];
$password = $_SERVER['HTTP_X_PASSWORD'];
// Find the user
$user=User::model()->find('LOWER(username)=?',array(strtolower($username)));
if($user===null) {
// Error: Unauthorized
$this->_sendResponse(401, 'Error: User Name is invalid');
} else if(!$user->validatePassword($password)) {
// Error: Unauthorized
$this->_sendResponse(401, 'Error: User Password is invalid');
}
}
Also, in all REST methods where an authentication is required, we need to put
$this->_checkAuth();
at the beginning of each method.
The API user then needs to set the _XUSERNAME and _XPASSWORD headers in his request.
Apache Issues ¶
If PUT or DELETE requests don't work in your Apache setup (perhaps you get an 403 - Forbidden error), you can put the following .htaccess file in the application's web root:
<Limit GET POST PUT DELETE>
order deny,allow
allow from all
</Limit>
See also this link. Other thoughts about mimic PUT and DELETE can be found here.
Discussion ¶
Please add your comments here or send comments to the respective forum post.
Code Download ¶
Of course you can download the code developed here.
Why the down vote?
Could you, who gave the downvote, please explain in a comment the reason?
Just amazing
Finally a great great tutorial for REST API implementation!! thanks you jwerner, vote up from me!
Very well explained
Thanks for this wonderful tutorial. It will come in handy when developing my application. Real nice work. Thank you for sharing it!
Perfect timing
I was about to attempt to solve this exact problem. Thank you for the time & effort you've put into this.
Where is it?
I can not see where you use the ApiController controller as a Service. You only created the ApiController. Or am i not right?
RE: Where is it?
elbek,
The ApiController is available when the Yii application is requested via HTTP.
E.g. the controller is used when you request www.example.com/yourapp/index.php/api/posts or /api/posts/1 via GET etc.
Notes
As first, written hardcode like CJson::encode is a bad practice - it's so difficult rewrite to xml, xml over dtd like soap protocol. Also as using GET and POST data (or php://input steam in restfull json).
Simple front controller helps to remove transport level from your code in one component. See in Symfony 2 beta - components Request and Response is a good practice in SOA applications.
As second - use if-based error handlers - is a dirty code. Use exceptions! It is a simple way to create simple and readable code. Also, exceptions is a good documentation.
$_SERVER headers
many thanks for the code.
My host does not print $_SERVER['HTTP_X_USERNAME'] so I had to use
if(isset($_SERVER['HTTP_AUTHENTICATION'])) { $auth_params = explode(":" , substr($_SERVER['HTTP_AUTHENTICATION'], 6)); $username = $auth_params[0]; unset($auth_params[0]); $password = implode('',$auth_params); } else { $username = $_SERVER['HTTP_X_'.self::APPLICATION_ID.'_USERNAME']; $password = $_SERVER['HTTP_X_'.self::APPLICATION_ID.'_PASSWORD']; }
Any suggestions to this would be appreciated.
Re: $_SERVER Headers
@kanejoe: The _$_SERVER['HTTP_X_USERNAME'] and $_SERVER['HTTP_X_PASSWORD']_ headers need to be set by the client using the API.
During testing and if you use the Firefox REST Extension, you can set these parameters (set _XUSERNAME and _XPASSOWRD only, I assume HTTP is added by the webserver).
api request headers
@jwerner - thanks and you are correct. I can set them using $.ajax( headers() ); with jquery. Have the api working live now. thanks again.
How to enhance the security of rest method
as the title said, can we use some other ways like app secret, app key to enhance the security? is there any tutorial for this? thanks!
Create a New Post Not Working for me
I've implemented your code in the blog demo, and everything seems to work EXCEPT the create Post. I use the request you included using the Firefox request add-on and I get a database error, "CDbCommand failed to execute the SQL statement: SQLSTATE[23000]: Integrity constraint violation: 19 tbl_post.author_id may not be NULL". The error appears in the beforeSave because if I change it to "$this->author_id=1;//Yii::app()->user->id;" while debugging it works OK. It seems that even though the user is logged on via demo/demo headers there is no user->id???
Any help would be appreciated. Thanks.
protected function beforeSave() { if(parent::beforeSave()) { if($this->isNewRecord) { $this->create_time=$this->update_time=time(); $this->author_id=Yii::app()->user->id; } else $this->update_time=time(); return true; } else return false; }
Never Mind
I saw that you dealt with this by adding this code to the Post.php beforeSave() method (not mentioned in the article):
if(is_null($this->author_id) or $this->author_id=='') { $this->author_id=Yii::app()->user->id; }
RE: Never Mind
@drmiller: Thanks for your comment, I have added a note regarding logged-in user not available during API access.
Great!
Thanks - very nice write up! I will be using Yii and backbone.js in my next app and I think this will work nicely with Yii's cache. Will write a tutorial or screen cast on how it goes.
Authentication with Token
What if I wanna use token?
I certainly don't want my username and password sent via networks right?
Fix for IIS servers
I had to change the code a bit, since it chached on IIS in the _sendResponse funcion, here:
$signature = ($_SERVER['SERVER_SIGNATURE'] == '') ? $_SERVER['SERVER_SOFTWARE'] . ' Server at ' . $_SERVER['SERVER_NAME'] . ' Port ' . $_SERVER['SERVER_PORT'] : $_SERVER['SERVER_SIGNATURE'];
a more robust implementation would be:
$signature = (isset($_SERVER['SERVER_SIGNATURE']) && $_SERVER['SERVER_SIGNATURE'] != '') ? $_SERVER['SERVER_SIGNATURE'] : $_SERVER['SERVER_SOFTWARE'] . ' Server at ' . $_SERVER['SERVER_NAME'] . ' Port ' . $_SERVER['SERVER_PORT'];
Thanks for the article. Amazingly helpful!
Going cross-domain with CORS
To make this REST API cross-domain with CORS, there are other things we need to do. In this example I am adding support for cross-domain requests with Basic Authentication headers and json content.
Cross-domain requests may need a preflight request if your request uses other verbs, headers or json support (learn more about it here).
A preflight request is basically an OPTIONS request to ask for permission to use cross-domain features.
So we have add the proper verb in the url manager rules (config/main.php):
// REST CORS pattern array('api/preflight', 'pattern'=>'api/*', 'verb'=>'OPTIONS'),
Then, in our ApiController, we added the corresponding action:
public function actionPreflight() { $content_type = 'application/json'; $status = 200; // set the status $status_header = 'HTTP/1.1 ' . $status . ' ' . $this->_getStatusCodeMessage($status); header($status_header); header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE"); header("Access-Control-Allow-Headers: Authorization"); header('Content-type: ' . $content_type); }
Finally, in the function _sendResponse, I added the lines:
header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Headers: Authorization");
I am accessing the REST API from a JS mobile app like this:
~~~
[javascript]
$.ajax({
url: 'http://myserver.com/index.php/api/user/1', type: 'GET', dataType: 'json', success: function(data, textStatus, jqXHR) { /* do stuff with data*/ }, beforeSend: function (xhr) { xhr.setRequestHeader ("Authorization", "Basic cGVkcm9za???????????????206MTIz"); }, complete: function(jqXHR, textStatus){ /* do other stuff*/ }, });
I hope this saves someone the time I couldn't. Cheers!
Using CHttpException
Thanks for this great tutorial!
Just an idea but wouldn't it be nicer to throw CHttpExceptions in situations like when a model wasn't found instead of calling sendResponse()? It should be possible to overwrite the errorHandler component and the actionError() in the ApiController to take the error codes and messages like this
public function actionError() { if($error=Yii::app()->errorHandler->error) $this->sendResponse($error->code,$error->message); }
cheers,
Hannes
show certain column values
Thanks for this tutorial but how can one show certain column only example title description etc because when I run actionlist I get all column with their respective but want to show only values from certain column as I have mentioned. Thanks again.
Typo
actionDelete
$this->sendResponse(200, $num); //should be $this->_sendResponse(200, $num);
actionUpdate
$this->sendResponse(200, CJSON::encode($model)); // should be $this->_sendResponse(200, CJSON::encode($model));
Good tutorial
Thanks for this, i am using it for a web app at the moment.
Module
Great post. Thanks. I am implementing this for our site Your text to link here... . BTW, I think that this can be encapsulated in a separated module.
RESTful principles
Just a reference of REST specifications at the following link:
RESTful Web services
in case there are future editors of this wiki :)
How is it used???
I am not understanding how it is working? can u please describe how the client side working? the demo contains the API controller but is it used anywhere in the demo?
How to set this authentication variable with cURL
This are mentioned above in comments.
$username = $_SERVER['HTTP_X_'.self::APPLICATION_ID.'_USERNAME'];
$password = $_SERVER['HTTP_X_'.self::APPLICATION_ID.'_PASSWORD'];
How to set this variable through cURL ?
Use this way to set X_ASCCPE_USERNAME & X_ASCCPE_PASSWORD
<?php
curl_setopt($ch, CURLOPT_HTTPHEADER, array('X_ASCCPE_USERNAME:demo','X_ASCCPE_PASSWORD:demo') );
?>
How to call restful sevice from yii
I want to get list of posts ,what I have to write,to get it from rest service.
RE: Authentication with Token
@Johny Joe: I was wondering exactly the same thing!
That's why I used a 2 step process:
To authenticate the user I used the amazon method so no password is transiting. basically it calculate the hmac of a known string with the user password as the secret key:
http://docs.amazonwebservices.com/AmazonS3/latest/dev/RESTAuthentication.html#RESTAuthenticationQueryStringAuth
The known string is the concat of multiple arguments: expiration time of the request, url requested, ...
XSS problems..
if($model === null) $this->_sendResponse(400, sprintf("Error: Didn't find any model <b>%s</b> with ID <b>%s</b>.", $_GET['model'], $_GET['id']) );
There are multiple XSS problems in your script. A htmlspecialchars() on all user-input would fix it.
Javascript Authorization
Would anyone please guide me on how to do Ajax/Javascript authorization to use this API?
I spent a lot of time getting it to work. Am new to Yii.
Here is what am trying:
$.ajax({ url: 'http://localhost/demos/yii-blog-rest/index.php/api/post/1', type: 'GET', dataType: 'json', success: function(data, textStatus, jqXHR) { /* do stuff with data*/ $('#result').text(data); }, beforeSend: function (xhr) { xhr.setRequestHeader("X_ASCCPE_USERNAME","demo"); xhr.setRequestHeader("X_ASCCPE_PASSWORD","demo"); }, complete: function(jqXHR, textStatus){ /* do other stuff*/ $('#result').text(jqXHR); $('#result').text(textStatus); }, });
Thanks in advance.
PUT Request
How I can test put request with the demo application ? (In folder "rest client request" put request is missing).
Re: PUT Request
@co-k-ine:
The REST Client Requests txt files were just done with the Firefox REST Client Addon and then saved as text files.
It appears as these files just contain a JSON object containing the REST parameters.
Regards,
Joachim
Re: Javascript Authorization
@beesho:
Please check this how-to.
Regards,
Joachim
Re: Javascript Authorization
@jwerner
Thank you very much!
Last saved id
How can I get the last saved items autoincrement primary key value?
CORS REST API
Hi, I tried to follow TiagoA instructions for the CORS REST API, but I have had no luck. WHen the browser makes the OPTIONS request, it will get a 401 Unauthorized response. Any ideas?
Authorization
If you user Apache+PHP (I tested on XAMPP), maybe you use this :
// Check if we have the USERNAME and PASSWORD HTTP headers set? if(!(isset($_SERVER['PHP_AUTH_USER']) and isset($_SERVER['PHP_AUTH_PW']))) { // Error: Unauthorized $this->_sendResponse(401); } $username = $_SERVER['PHP_AUTH_USER']; $password = $_SERVER['PHP_AUTH_PW'];
instead of
// Check if we have the USERNAME and PASSWORD HTTP headers set? if(!(isset($_SERVER['HTTP_X_USERNAME']) and isset($_SERVER['HTTP_X_PASSWORD']))) { // Error: Unauthorized $this->_sendResponse(401); } $username = $_SERVER['HTTP_X_USERNAME']; $password = $_SERVER['HTTP_X_PASSWORD'];
when use basic authentication (not to add custom header)
Authentication with Token
Thanks for this tutorial. How to implement "API Authentication with Token" to avoid sending username and password each time? can any one please help on this?
Thanks
how to get header details?
i'm using rest api for my application to support mobile, i want to know,how i catch the details comes from header?
How to solve "Undefined index error in $_SERVER['HTTP_X_USERNAME']"
When
$_SERVER['HTTP_X_USERNAME']
is used, the variable name in header should be
since HTTP_ is automatically attached to the variable name in the REST Client extension of Chrome or Firefox browser.
For example,
If HTTP_X_USERNAME is used as variable name in header, the index becomes $_SERVER['HTTP_HTTP_X_USERNAME'] therefore "undefined index error in $_SERVER['HTTP_X_USERNAME']" occurs. Beware.
this doesnt work for me.
i am getting this error when i sent the request this way,
http://localhost/RestApi/index.php/api/post/1
Error 404
Unable to resolve the request "api/view".
i have done this inside a module called "api" and in DefaultController.
Api is controller and View is action
Hi @Azy
According to this REST api document, Api is a controller not a module.
And view is an action.
You said you placed Api in module directory as a module, it is a wrong place.
Place the ApiController under the protected/controllers/ directory.
And actionView as one of the actions in ApiController class.
Cheers.
HTTP_X_USERNAME & HTTP_X_PASSWORD doesnt set
I am unable to set HTTP_X_USERNAME & HTTP_X_PASSWORD through REST client. Did anyone else get the same problem and/or have a workaround for this ?
Appreciate a quick reply.
Read the others' comments about same issue.
Hi @Azy
I cannot know what may be the problem based on your short description.
But see the others' comments, there may be an answer for your case.
Especially read my comment titled 'How to solve "Undefined index error in $_SERVER['HTTP_X_USERNAME']"'
I hope this may help.
I resolved it
The issue was a small typo.
i should set the headers this way,
X-Username:azraar
X-Password:azraar
instead of underscore(_) have to use a the dash(-)
URL pattern issue
I have a url pattern defined as below for a REST API build using yii.
'urlManager'=>array(
'urlFormat'=>'path', 'rules'=>array( array('api/default/list', 'pattern'=>'api/<model:\w+>', 'verb'=>'GET'), array('api/default/view', 'pattern'=>'api/<model:\w+>/<id:\d+>', 'verb'=>'GET'), array('api/default/update', 'pattern'=>'api/<model:\w+>/<id:\d+>', 'verb'=>'PUT'), array('api/default/delete', 'pattern'=>'api/<model:\w+>/<id:\d+>', 'verb'=>'DELETE'), array('api/default/create', 'pattern'=>'api/<model:\w+>', 'verb'=>'POST'), '<controller:\w+>/<action:\w+>'=>'<controller>/<action>', ), ),
What i am trying now is,
http://example.com/RestApi/index.php/api/post?offset=5&limit=10
The above works, but the following doesnt work.
http://example.com/RestApi/index.php/api/post/offset/5/limit/10
How can i make it work like second way? what changes needs to be done to the Url Manager ?
Thanks
Update
The error i get for second way is,
Unable to resolve the request "api/post/offset/5/limit/10".
how do i enable multiple parameters in all put,get,delete/update ? now it only works for one like this,
get - example.com/posts , get - example.com/posts/1
what if i want to add more params like ? example.com/posts/offset/1/limit/10 ?
Use the right pattern in urlManager
Hi @Azy
I would suggest that you should pay attention to the pattern of urlManager.
The url( http://example.com/RestApi/index.php/api/post/offset/5/limit/10 ) is not matched by any pattern of the urlManager. Hence Yii can not resolve the above url.
To match the above url, the pattern should be , for example, array('api/default/list', 'pattern'=>'api/<model:\w+>/<value1:\w+>/<value2:\d+>/<value3:\w+>/<value4:\d+>', 'verb'=>'GET').
value1 will be set as 'offset', value2 '5', value3 'limit' and value4 '10' by urlManager.
There is an another extension which provides full REST service, which supports sub resources like 'offset/5/limit/10'. This extension is a little complex. But have a look at it if you want to.
http://www.yiiframework.com/extension/restfullyii
Cheers
Performance related,
Hi There,
I am writing my first REST api and would like to get your feedback on this performance matter.
http://www.yiiframework.com/forum/index.php/topic/49119-model-exist-or-not-in-yii-using-a-custom-function-performance/
Appreciate a prompt reply.
Thanks
another way to build REST api.
public function actions() { return array( 'user'=>array( 'class' => 'JRestAction', 'model' => 'User', 'routes' => array( 'GET' => array('findAll', 'id' => 'findByPk'), 'PUT' => array('id' => 'save'), 'POST' => array('save'), 'DELETE' => array('id' => 'delete'), ) ), ); }
list: GET http://domain.com/controller/user
view: GET http://domain.com/controller/user/1
update: PUT http://domain.com/controller/user/1
create: POST http://domain.com/controller/user
delete: DELETE http://domain.com/controller/user/1
Authentication from request data
_checkAuth() function is authenticating based on the header username and password. If i get authentication data request itself then how can i authenticate a client?
I have request in following format
{ "request": { "signin": { "id": "12345", "username": "test", "password": "xyz" }, "memberid": "03000000015", "remarks": { "remark": "check user request remark" } } }
Id,username and password will be validated against db values.
Can you please suggest how to authenticate client in such case?
how display comment
hi all
thank you for this artical
but
what about comment
if i want to view post with its comment
how it should by
thank you very match
Archive links
Archive link -
https://web.archive.org/web/20130910164802/http://www.gen-x-design.com/archives/create-a-rest-api-with-php/
https://web.archive.org/web/20130323001500/http://www.gen-x-design.com/archives/making-restful-requests-in-php/
Chrome Extension
Chrome Extension for Advanced REST client Application -
https://chrome.google.com/webstore/detail/hgmloofddffdnphfgcellkdfbfbjeloo
URLmanager suddenly won't work
I have
array('api/delete', 'pattern'=>'api/<model:\w+>/<id:\d+>', 'verb'=>'DELETE'),
set up and it was working correctly. Sending DELETE to /api/comments came back with the message I didn't have the $_GET['id'] parameter set up and when I sent DELETE to /api/comments/12, I got the proper response.
Out of nowhere though, from today, if I don't specify the ID in the URL, the above URLManager rule does not apply. It simply skips on and goes to the next rule. As if the parameters were to be strictly applied. But they shouldn't. I tried everything, no idea what happens or how to fix this. Any ideas?
Why is the <id:> parameter required all the sudden?
Doesn't work with nginx
Hello,
you're Url manager pattern doesn't work with nginx configuration.
See this topic (http://www.yiiframework.com/forum/index.php/topic/62727-issue-with-yii-rest-api-and-nginx-url/ ) for more informations
get rest params
From Yii 1.1.7 version, Can use this commands for get REST params instead use $_GET, $_POST, or php://input :
GET => Yii::app()->request->getQuery('foo') POST => Yii::app()->request->getPost('foo') PUT => Yii::app()->request->getPut('foo') DELETE => Yii::app()->request->getDelete('foo') REST PARAMS => Yii::app()->request->getRestParams()
REST Api guide Yii2 is available here.
https://www.yiiframework.com/doc/guide/2.0/en/rest-quick-start.
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.