Rest¶
The REST module implements a basic CRUD,
with an authentication system, directly testable in the administration part.
REST and routing¶
The router is essential to the REST module, since REST (Respresentation State Transfer) is based on URLs and HTTP methods.
Note
For performance reasons, REST routes are cached independently of other routes.
It is therefore necessary to start the router in a particular way to activate the REST routes and not to obtain a recurring 404 error.
The router is started in services.php
.
Without activation of REST routes:
...
Router::start();
To enable REST routes in an application that also has a non-REST part:
...
Router::startAll();
To activate only Rest routes:
Router::startRest();
It is possible to start routing conditionally (this method will only be more efficient if the number of routes is large in either part):
...
if($config['isRest']()){
Router::startRest();
}else{
Router::start();
}
Resource REST¶
A REST controller can be directly associated with a model.
Note
If you do not have a mysql database on hand, you can download this one: messagerie.sql
Creation¶
With devtools:
Ubiquity rest RestUsersController -r=User -p=/rest/users
Or with webtools:
Go to the REST section and choose Add a new resource:

The created controller :
1 2 3 4 5 6 7 8 9 10 | namespace controllers;
/**
* Rest Controller RestUsersController
* @route("/rest/users","inherited"=>true,"automated"=>true)
* @rest("resource"=>"models\\User")
*/
class RestUsersController extends \Ubiquity\controllers\rest\RestController {
}
|
Since the attributes automated and inherited of the route are set to true, the controller has the default routes of the parent class.
Test interface¶
Webtools provide an interface for querying datas:

Getting an instance¶
A user instance can be accessed by its primary key (id):

Inclusion of associated members: the organization of the user

Inclusion of associated members: organization, connections and groups of the user

Getting multiple instances¶
Getting all instances:

Setting a condition:

Including associated members:

Adding an instance¶
The datas are sent by the POST method, with a content type defined at application/x-www-form-urlencoded
:
Add name and domain parameters by clicking on the parameters button:

The addition requires an authentication, so an error is generated, with the status 401:

The administration interface allows you to simulate the default authentication and obtain a token, by requesting the connect method:

The token is then automatically sent in the following requests.
The record can then be inserted.

Updating an instance¶
The update follows the same scheme as the insertion.
Deleting an instance¶

Authentification¶
Ubiquity REST implements an Oauth2 authentication with Bearer tokens.
Only methods with @authorization
annotation require the authentication, these are the modification methods (add, update & delete).
/**
* Update an instance of $model selected by the primary key $keyValues
* Require members values in $_POST array
* Requires an authorization with access token
*
* @param array $keyValues
* @authorization
* @route("methods"=>["patch"])
*/
public function update(...$keyValues) {
$this->_update ( ...$keyValues );
}
The connect method of a REST controller establishes the connection and returns a new token.
It is up to the developer to override this method to manage a possible authentication with login and password.

Simulation of a connection with login¶
In this example, the connection consists simply in sending a user variable by the post method.
If the user is provided, the connect
method of $server
instance returns a valid token that is stored in session (the session acts as a database here).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | namespace controllers;
use Ubiquity\utils\http\URequest;
use Ubiquity\utils\http\USession;
/**
* Rest Controller RestOrgas
* @route("/rest/orgas","inherited"=>true,"automated"=>true)
* @rest("resource"=>"models\\Organization")
*/
class RestOrgas extends \Ubiquity\controllers\rest\RestController {
/**
* This method simulate a connection.
* Send a <b>user</b> variable with <b>POST</b> method to retreive a valid access token
* @route("methods"=>["post"])
*/
public function connect(){
if(!URequest::isCrossSite()){
if(URequest::isPost()){
$user=URequest::post("user");
if(isset($user)){
$tokenInfos=$this->server->connect ();
USession::set($tokenInfos['access_token'], $user);
$tokenInfos['user']=$user;
echo $this->_format($tokenInfos);
return;
}
}
}
throw new \Exception('Unauthorized',401);
}
}
|
For each request with authentication, it is possible to retrieve the connected user (it is added here in the response headers) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | namespace controllers;
use Ubiquity\utils\http\URequest;
use Ubiquity\utils\http\USession;
/**
* Rest Controller RestOrgas
* @route("/rest/orgas","inherited"=>true,"automated"=>true)
* @rest("resource"=>"models\\Organization")
*/
class RestOrgas extends \Ubiquity\controllers\rest\RestController {
...
public function isValid($action){
$result=parent::isValid($action);
if($this->requireAuth($action)){
$key=$this->server->_getHeaderToken();
$user=USession::get($key);
$this->server->_header('active-user',$user,true);
}
return $result;
}
}
|
Use the webtools interface to test the connection:

Customizing¶
Api tokens¶
It is possible to customize the token generation, by overriding the getRestServer
method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | namespace controllers;
use Ubiquity\controllers\rest\RestServer;
class RestOrgas extends \Ubiquity\controllers\rest\RestController {
...
protected function getRestServer(): RestServer {
$srv= new RestServer($this->config);
$srv->setTokenLength(32);
$srv->setTokenDuration(4800);
return $srv;
}
}
|
Allowed origins¶
Allowed origins allow to define the clients that can access the resource in case of a cross domain request by defining The Access-Control-Allow-Origin response header.
1 2 3 4 5 6 7 8 9 10 | class RestOrgas extends \Ubiquity\controllers\rest\RestController {
...
protected function getRestServer(): RestServer {
$srv= new RestServer($this->config);
$srv->setAllowOrigin('http://mydomain/');
return $srv;
}
}
|
It is possible to authorize several origins:
1 2 3 4 5 6 7 8 9 10 | class RestOrgas extends \Ubiquity\controllers\rest\RestController {
...
protected function getRestServer(): RestServer {
$srv= new RestServer($this->config);
$srv->setAllowOrigins(['http://mydomain1/','http://mydomain2/']);
return $srv;
}
}
|
Response¶
To change the response format, it is necessary to create a class inheriting from ResponseFormatter
.
We will take inspiration from HAL, and change the format of the responses by:
- adding a link to self for each resource
- adding an
_embedded
attribute for collections - removing the
data
attribute for unique resources
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | namespace controllers\rest;
use Ubiquity\controllers\rest\ResponseFormatter;
use Ubiquity\orm\OrmUtils;
class MyResponseFormatter extends ResponseFormatter {
public function cleanRestObject($o, &$classname = null) {
$pk = OrmUtils::getFirstKeyValue ( $o );
$r=parent::cleanRestObject($o);
$r["links"]=["self"=>"/rest/orgas/get/".$pk];
return $r;
}
public function getOne($datas) {
return $this->format ( $this->cleanRestObject ( $datas ) );
}
public function get($datas, $pages = null) {
$datas = $this->getDatas ( $datas );
return $this->format ( [ "_embedded" => $datas,"count" => \sizeof ( $datas ) ] );
}
}
|
Then assign MyResponseFormatter
to the REST controller by overriding the getResponseFormatter
method:
1 2 3 4 5 6 7 8 | class RestOrgas extends \Ubiquity\controllers\rest\RestController {
...
protected function getResponseFormatter(): ResponseFormatter {
return new MyResponseFormatter();
}
}
|
Test the results with the getOne and get methods:


APIs¶
Unlike REST resources, APIs controllers are multi-resources.
SimpleRestAPI¶
JsonApi¶
Ubiquity implements the jsonApi specification with the class JsonApiRestController
.
JsonApi is used by EmberJS and others.
see https://jsonapi.org/ for more.
Creation¶
With devtools:
Ubiquity restapi JsonApiTest -p=/jsonapi
Or with webtools:
Go to the REST section and choose Add a new resource:

Test the api in webtools:

Getting an array of objects¶
By default, all associated members are included:

Including associated members¶
you need to use the include parameter of the request:
URL | Description |
---|---|
/jsonapi/user?include=false |
No associated members are included |
/jsonapi/user?include=organization |
Include the organization |
/jsonapi/user?include=organization,connections |
Include the organization and the connections |
/jsonapi/user?include=groupes.organization |
Include the groups and their organization |
Filtering instances¶
you need to use the filter parameter of the request,
filter parameter corresponds to the where part of an SQL statement:
URL | Description |
---|---|
/jsonapi/user?1=1 |
No filtering |
/jsonapi/user?firstname='Benjamin' |
Returns all users named Benjamin |
/jsonapi/user?filter=firstname like 'B*' |
Returns all users whose first name begins with a B |
/jsonapi/user?filter=suspended=0 and lastname like 'ca*' |
Returns all suspended users whose lastname begins with ca |
Pagination¶
you need to use the page[number] and page[size] parameters of the request:
URL | Description |
---|---|
/jsonapi/user |
No pagination |
/jsonapi/user?page[number]=1 |
Display the first page (page size is 1) |
/jsonapi/user?page[number]=1&&page[size]=10 |
Display the first page (page size is 10) |
Adding an instance¶
The datas, contained in data[attributes]
, are sent by the POST method, with a content type defined at application/json; charset=utf-8
.
Add your parameters by clicking on the parameters button:

The addition requires an authentication, so an error is generated, with the status 401 if the token is absent or expired.

Deleting an instance¶
Deletion requires the DELETE method, and the use of the id of the object to be deleted:
