Version: current

# Class RestfulServer

Sapphire's generic RESTful server.

This class gives your application a RESTful API for free. All you have to do is define static $api_access = true on the appropriate DataObjects. You will need to ensure that all of your data manipulation and security is defined in your model layer (ie, the DataObject classes) and not in your Controllers. This is the recommended design for Sapphire applications.

Enabling restful access on a model will also enable a SOAP API, see `SOAPModelAccess`.

Example DataObject with simple api access, giving full access to all object properties and relations, unless explicitly controlled through model permissions.

    class Article extends DataObject {
            static $db = array('Title'=>'Text','Published'=>'Boolean');
            static $api_access = true;
    }

- Example DataObject with advanced api access, limiting viewing and editing to Title attribute only:

    class Article extends DataObject {
            static $db = array('Title'=>'Text','Published'=>'Boolean');
            static $api_access = array(
                    'view' => array('Title'),
                    'edit' => array('Title'),
            );
    }

Supported operations: - GET /api/v1/(ClassName)/(ID) - gets a database record - GET /api/v1/(ClassName)/(ID)/(Relation) - get all of the records linked to this database record by the given reatlion - GET /api/v1/(ClassName)?(Field)=(Val)&(Field)=(Val) - searches for matching database records - POST /api/v1/(ClassName) - create a new database record - PUT /api/v1/(ClassName)/(ID) - updates a database record - PUT /api/v1/(ClassName)/(ID)/(Relation) - updates a relation, replacing the existing record(s) (NOT IMPLEMENTED YET) - POST /api/v1/(ClassName)/(ID)/(Relation) - updates a relation, appending to the existing record(s) (NOT IMPLEMENTED YET)
- DELETE /api/v1/(ClassName)/(ID) - deletes a database record (NOT IMPLEMENTED YET) - DELETE /api/v1/(ClassName)/(ID)/(Relation)/(ForeignID) - remove the relationship between two database records, but don't actually delete the foreign object (NOT IMPLEMENTED YET)
- POST /api/v1/(ClassName)/(ID)/(MethodName) - executes a method on the given object (e.g, publish)

You can trigger searches based on the fields specified on `DataObject::$searchable_fields` and passed through `DataObject::getDefaultSearchContext()`. Just add a key-value pair with the search-term to the url, e.g. /api/v1/(ClassName)/?Title=mytitle.

Other url-modifiers:

- &limit=<numeric>: Limit the result set
- &relationdepth=<numeric>: Displays links to existing has-one and has-many relationships to a certain depth (Default: 1)
- &fields=<string>: Comma-separated list of fields on the output object (defaults to all database-columns). Handy to limit output for bandwidth and performance reasons.
- &sort=<myfield>&dir=<asc|desc>
- &add_fields=<string>: Comma-separated list of additional fields, for example dynamic getters.

Access control is implemented through the usual Member system with Basicauth authentication only. By default, you have to bear the ADMIN permission to retrieve or send any data.

You should override the following built-in methods to customize permission control on a class- and object-level:

- `DataObject::canView()`
- `DataObject::canEdit()`
- `DataObject::canDelete()`
- `DataObject::canCreate()`

See `DataObject` documentation for further details.

You can specify the character-encoding for any input on the HTTP Content-Type. At the moment, only UTF-8 is supported. All output is made in UTF-8 regardless of Accept headers.

  Object
  ViewableData implements IteratorAggregate
  RequestHandler
  Controller
  RestfulServer

Package: sapphire\api
Located at sapphire/api/RestfulServer.php

## Methods summary

`public` | # `index( )` This handler acts as the switchboard for the controller. Since no $Action url-param is set, all requests are sent here. This handler acts as the switchboard for the controller. Since no $Action url-param is set, all requests are sent here.
`protected String` | # `getHandler( String $className, `Int` $id, String $relationName )` Handler for object read. Handler for object read. The data object will be returned in the following format: <ClassName> <FieldName>Value</FieldName> ... <HasOneRelName id="ForeignID" href="LinkToForeignRecordInAPI" /> ... <HasManyRelName> <ForeignClass id="ForeignID" href="LinkToForeignRecordInAPI" /> <ForeignClass id="ForeignID" href="LinkToForeignRecordInAPI" /> </HasManyRelName> ... <ManyManyRelName> <ForeignClass id="ForeignID" href="LinkToForeignRecordInAPI" /> <ForeignClass id="ForeignID" href="LinkToForeignRecordInAPI" /> </ManyManyRelName> </ClassName> Access is controlled by two variables: - static $api_access must be set. This enables the API on a class by class basis - $obj->canView() must return true. This lets you implement record-level security #### Parameters $className String $className $id Int $id $relationName String $relation #### Returns `String` The serialized representation of the requested object(s) - usually XML or JSON.
`protected `DataObjectSet`` | # `getSearchQuery( string $className, array $params = null, mixed $sort = null, mixed $limit = null, mixed $existingQuery = null )` Uses the default `SearchContext` specified through `DataObject::getDefaultSearchContext()` to augument an existing query object (mostly a component query from `DataObject`) with search clauses. Uses the default `SearchContext` specified through `DataObject::getDefaultSearchContext()` to augument an existing query object (mostly a component query from `DataObject`) with search clauses. #### Parameters $className string $className $params array $params $sort $limit $existingQuery #### Returns ``DataObjectSet`` DataObjectSet
`protected `DataFormatter`` | # `getDataFormatter( boolean $includeAcceptHeader = false )` Returns a dataformatter instance based on the request extension or mimetype. Falls back to `RestfulServer::$default_extension`. Returns a dataformatter instance based on the request extension or mimetype. Falls back to `RestfulServer::$default_extension`. #### Parameters $includeAcceptHeader boolean $includeAcceptHeader Determines wether to inspect and prioritize any HTTP Accept headers #### Returns ``DataFormatter`` DataFormatter
`protected` | # `getRequestDataFormatter( )`
`protected` | # `getResponseDataFormatter( )`
`protected` | # `deleteHandler( mixed $className, mixed $id )` Handler for object delete Handler for object delete
`protected` | # `putHandler( mixed $className, mixed $id )` Handler for object write Handler for object write
`protected` | # `postHandler( mixed $className, mixed $id, mixed $relation )` Handler for object append / method call. Handler for object append / method call.
`protected `DataObject`` | # `updateDataObject( `DataObject` $obj, `DataFormatter` $formatter )` Converts either the given HTTP Body into an array (based on the DataFormatter instance), or returns the POST variables. Automatically filters out certain critical fields that shouldn't be set by the client (e.g. ID). Converts either the given HTTP Body into an array (based on the DataFormatter instance), or returns the POST variables. Automatically filters out certain critical fields that shouldn't be set by the client (e.g. ID). #### Parameters $obj DataObject $obj $formatter DataFormatter $formatter #### Returns ``DataObject`` The passed object
`protected `SQLQuery`` | # `getObjectQuery( string $className, integer $id, array $params )` Gets a single DataObject by ID, through a request like /api/v1/<MyClass>/<MyID> Gets a single DataObject by ID, through a request like /api/v1/<MyClass>/<MyID> #### Parameters $className string $className $id int $id $params array $params #### Returns ``SQLQuery`` SQLQuery
`protected `SQLQuery`` | # `getObjectsQuery( `DataObject` $className, array $params, integer|array $sort, integer|array $limit )` #### Parameters $className DataObject $obj $params array $params $sort int|array $sort $limit int|array $limit #### Returns ``SQLQuery`` SQLQuery
`protected `SQLQuery`|boolean` | # `getObjectRelationQuery( `DataObject` $obj, array $params, integer|array $sort, integer|array $limit, string $relationName )` #### Parameters $obj DataObject $obj $params array $params $sort int|array $sort $limit int|array $limit $relationName string $relationName #### Returns ``SQLQuery`|boolean` SQLQuery|boolean
`protected` | # `permissionFailure( )`
`protected` | # `notFound( )`
`protected` | # `methodNotAllowed( )`
`protected` | # `unsupportedMediaType( )`
`protected` | # `authenticate( )` #### Used by ``RestfulServer::$member``
`protected array` | # `getAllowedRelations( string $class, `Member` $member = null )` Return only relations which have $api_access enabled. Return only relations which have $api_access enabled. #### Parameters $class string $class $member Member $member #### Returns `array` array

### Methods inherited from Controller

`CurrentMember()`, `Now()`, `PastMember()`, `PastVisitor()`, `can()`, `curr()`, `defaultAction()`, `disableBasicAuth()`, `getAction()`, `getFormOwner()`, `getRequest()`, `getResponse()`, `getSession()`, `getURLParams()`, `getViewer()`, `handleAction()`, `handleRequest()`, `hasAction()`, `hasActionTemplate()`, `has_curr()`, `init()`, `isAjax()`, `join_links()`, `popCurrent()`, `pushCurrent()`, `redirect()`, `redirectBack()`, `redirectedTo()`, `render()`, `setSession()`, `setURLParams()`

### Methods inherited from RequestHandler

`__construct()`, `allowedActions()`, `checkAccessAction()`, `httpError()`

### Methods inherited from ViewableData

`ATT_val()`, `BaseHref()`, `CSSClasses()`, `ColumnBreak()`, `ColumnCalc()`, `ColumnNumber()`, `ColumnPad()`, `ColumnPos()`, `CurrentPage()`, `Debug()`, `Even()`, `EvenOdd()`, `First()`, `FirstLast()`, `HasPerm()`, `IsAjax()`, `JS_val()`, `Last()`, `Me()`, `Middle()`, `MiddleString()`, `Modulus()`, `MultipleOf()`, `Odd()`, `Pos()`, `RAW_val()`, `SQL_val()`, `ThemeDir()`, `ThemeName()`, `Top()`, `TotalItems()`, `XML_val()`, `__get()`, `__isset()`, `__set()`, `buildCastingCache()`, `cachedCall()`, `castingClass()`, `castingHelper()`, `castingHelperPair()`, `castingObjectCreator()`, `castingObjectCreatorPair()`, `customise()`, `defineMethods()`, `escapeTypeForField()`, `getField()`, `getIterator()`, `getSecurityID()`, `getXMLValues()`, `hasField()`, `hasValue()`, `i18nLocale()`, `iteratorProperties()`, `obj()`, `renderWith()`, `setCustomisedObj()`, `setField()`

### Methods inherited from Object

`__call()`, `__toString()`, `__wakeup()`, `addMethodsFrom()`, `addStaticVars()`, `addWrapperMethod()`, `add_extension()`, `add_static_var()`, `allMethodNames()`, `cacheToFile()`, `cacheToFileWithArgs()`, `clearCache()`, `combined_static()`, `create()`, `createMethod()`, `create_from_string()`, `exists()`, `extInstance()`, `extend()`, `getCustomClass()`, `getExtensionInstance()`, `getExtensionInstances()`, `get_extensions()`, `get_static()`, `hasExtension()`, `hasMethod()`, `has_extension()`, `invokeWithExtensions()`, `is_a()`, `loadCache()`, `parentClass()`, `parse_class_spec()`, `remove_extension()`, `sanitiseCachename()`, `saveCache()`, `set_stat()`, `set_static()`, `set_uninherited()`, `stat()`, `strong_create()`, `uninherited()`, `uninherited_static()`, `useCustomClass()`

### Magic methods summary

## Properties summary

`public static array` | $url_handlers | # Default URL handlers - (Action)/(ID)/(OtherID) Default URL handlers - (Action)/(ID)/(OtherID)
`protected static string` | $api_base | #
`public static string` | $default_extension | # If no extension is given in the request, resolve to this extension (and subsequently the `RestfulServer::$default_mimetype`. If no extension is given in the request, resolve to this extension (and subsequently the `RestfulServer::$default_mimetype`.
`protected static string` | $default_mimetype | # If no extension is given, resolve the request to this mimetype. If no extension is given, resolve the request to this mimetype.
`protected `Member`` | $member | # #### Uses ``RestfulServer::authenticate()``

### Properties inherited from Controller

`$action`, `$allowed_actions`, `$baseInitCalled`, `$basicAuthEnabled`, `$controller_stack`, `$request`, `$requestParams`, `$response`, `$session`, `$urlParams`

### Properties inherited from RequestHandler

`$brokenOnConstruct`

### Properties inherited from ViewableData

`$casting`, `$customisedObject`, `$default_cast`, `$failover`, `$iteratorPos`, `$iteratorTotalItems`

### Properties inherited from Object

`$class`, `$extension_instances`, `$extensions`

[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -