A "REST" webservice plugin for symfony 1.4 and Doctrine... if you think to REST as nice urls...
MIT License
The sfRestWebServicePlugin
offers an easy interface for REST API based on your domain model.
Use the default plugin installer procedure
php symfony plugin:install sfRestWebServicePlugin
then enable the plugin in your projectConfiguration class ( remember it needs the sfDoctrinePlugin
enabled too, cause the services are based on your Doctrine schema ):
public function setup()
{
$this->enablePlugins('sfDoctrinePlugin');
$this->enablePlugins('sfRestWebServicePlugin');
}
Last step, enable the module in the settings.yml of the application you want the webservices to be exposed into:
all:
...
enabled_modules: [sfRestWebService]
...
You can - obviously - override and extends plugin's classes by creating them in your application's module directory.
The sfRestWebServicePlugin
is based on the sfRestWebService
module bundled with the plugin, so you only need to replicate the module on your application:
$ mkdir apps/myApp/modules/sfRestWebService
For example, to override a template you will only need to create it on your application at the path:
apps/myApp/modules/sfRestWebService/templates/errorSuccess.json.php
The core configuration on the module lies in the config.yml that you have to locally override:
$ touch apps/myApp/modules/sfRestWebService/config/config.yml
all:
protected: true
allowed: [127.0.0.1]
protectedRoute: secure
services:
name:
model: user
methodForQuery: findActives
states: [GET, PUT]
Here's a brief explanation for every configuration parameter:
all: The environment
protected: boolean, the webservices are protected or not?
allowed: if the webservices are protected, specify a YAML array of IP addresses that can access the services
protectedRoute: sets the route that non-allowed IP addresses will be redirected to
services: an array of single services configurations
name: the service name ( used in the service URL )
model: the model of the service
methodForQuery: a method for GET requests. If not specified, doctrine will do a `->createQuery()->execute()`
states: allowed request states ( PUT, POST, GET, DELETE ). If not specified, all state are allowed
If you turn on authentication, remember to specify a secure route.
If you have module default
enabled, the route can be secure
( which is the name of the default/secure
route ).
This plugins requires PHP's short open tags
parameter set to OFF
.
It would not be such a difficult matter to make the plugin work also with short open tags
enabled, the point is that you shouldn't work this way.
Since PHP sucks in so many ways handling PUT requests this plugin handles them with symfony's native REST architecture ( so, not not real PUT requests, but requests with the additional parametere sf_method
set to PUT ).
Suppose a configuration like:
all:
protected: true
allowed: [127.0.0.1]
protectedRoute: secure
services:
users:
model: User
methodForQuery: ~
states: ~
The URLs that the sfRestWebService
module will match are:
From now on, we will refer to ask an entry, or ask a search and so on.
Here are just a few examples on how to query an imaginary service with CURL.
GET
$ curl -X GET http://domain.tld/index.php/api/user
POST
$ curl -X GET http://domain.tld/index.php/api/user -F name='John Doe' -F email='[email protected]'
GET
$ curl -X GET http://domain.tld/index.php/api/user/1
DELETE
$ curl -X DELETE http://domain.tld/index.php/api/user/1
PUT
$ curl -X POST http://domain.tld/index.php/api/user/1 -F sf_method=PUT -F name='John C.Hanged'
GET
$ curl -X GET http://domain.tld/index.php/api/user/search/email/gmail
http://domain.tld/app.php/api/user
Returns a collection of objects:
<?xml version="1.0" encoding="utf-8"?>
<objects>
<object id="1">
<id>1</id>
<name>John Doe</name>
</object>
<object id="2">
<id>2</id>
<name>Mark Madsen</name>
</object>
</objects>
an error if the service is available but the configuration is malformed:
<error>
Internal server error: unsupported service
</error>
or a 404 status code if the service doesn't exists.
Returns the just created object:
<object id="7">
<id>7</id>
<name>Alessandro Nadalin</name>
</object>
an error if the data passed via POST doesn't pass validation:
<error>
Validation failed in class User
1 field had validation error:
* 1 validator failed on name (notnull)
</error>
an error if the service is available but the configuration is malformed:
<error>
Internal server error: unsupported service
</error>
or a 404 status code if the service doesn't exists.
Not supported.
Not supported.
http://domain.tld/app.php/api/user/:id
Returns the requested resource by ID:
<object id="7">
<id>7</id>
<name>Alessandro Nadalin</name>
</object>
an error if the resource doesn't exist:
<error>
Unable to load the specified resource
</error>
an error if the service is available but the configuration is malformed:
<error>
Internal server error: unsupported service
</error>
or a 404 status code if the service doesn't exists.
Not supported.
Returns a simple feedback:
<object>
Object has been deleted
</object>
an error if the resource you are trying to delete doesn't exist:
<error>
Unable to load the specified resource
</error>
an error if the service is available but the configuration is malformed:
<error>
Internal server error: unsupported service
</error>
or a 404 status code if the service doesn't exists.
Returns the just updated object:
<object id="7">
<id>7</id>
<name>Alessandro Nadalin has been updated</name>
</object>
an error if the resource doesn't exist:
<error>
Unable to load the specified resource
</error>
an error if the service is available but the configuration is malformed:
<error>
Internal server error: unsupported service
</error>
or a 404 status code if the service doesn't exists.
http://domain.tld/app.php/api/user/search/:column/:value
Returns a collection of objects matching a where(":column LIKE ?", "%:value%")
statement:
<objects>
<object id="2">
<id>2</id>
<name>Mark Madsen</name>
</object>
<object id="7">
<id>7</id>
<name>Alessandro Nadalin</name>
</object>
</objects>
an error if the column you are trying to search by doesn't exist:
<error>
Invalid search column
</error>
an error if the service is available but the configuration is malformed:
<error>
Internal server error: unsupported service
</error>
or a 404 status code if the service doesn't exists.
Not supported.
Not supported.
Not supported.
The services send responses in:
methodForQuery
parameterIf specified, it's used in a case: processing a GET request on an entry.
Supposing your service's methodForQuery
is findItalian
and the model
parameter is user
you will need to create a new method in the UserTable
class:
public function findItalian(Doctrine_Query $query)
{
$query = // ...do stuff with the query...
return $query;
}
The $query
that the method receives is always:
Doctrine::getTable('model')->createQuery('wsmodel');
NOTE: do not execute the query.