sfRestWebServicePlugin

A "REST" webservice plugin for symfony 1.4 and Doctrine... if you think to REST as nice urls...

MIT License

Stars
9

sfRestWebServicePlugins

The sfRestWebServicePlugin offers an easy interface for REST API based on your domain model.

Installation and configuration

Installation

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]
  ...

Configuration

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 ).

Requirements

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.

A specification

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 ).

URLs

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.

Asking the services

Here are just a few examples on how to query an imaginary service with CURL.

Ask an entry

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]'

Ask a resource

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'

Ask a search

GET

$ curl -X GET http://domain.tld/index.php/api/user/search/email/gmail

Responses

Entry

http://domain.tld/app.php/api/user

GET

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.

POST

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.

DELETE

Not supported.

PUT

Not supported.

Resource

http://domain.tld/app.php/api/user/:id

GET

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.

POST

Not supported.

DELETE

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.

PUT

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.

Search

GET

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.

POST

Not supported.

DELETE

Not supported.

PUT

Not supported.

Formats

The services send responses in:

The methodForQuery parameter

If 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.