454 lines
13 KiB
Markdown
454 lines
13 KiB
Markdown
|
```yaml
|
||
|
module: api
|
||
|
version: 3.0
|
||
|
requires:
|
||
|
- http: 1.0
|
||
|
- error: 2.0
|
||
|
```
|
||
|
|
||
|
Links
|
||
|
====
|
||
|
|
||
|
[**I.** Overview](#i-overview)
|
||
|
|
||
|
- [**1** Introduction & features](#1-introduction--features)
|
||
|
- [**2** Basic knowledge](#2-basic-knowledge)
|
||
|
|
||
|
[**II.** Usage](#ii-usage)
|
||
|
|
||
|
- [**1** Setup](#1-setup)
|
||
|
- [**2** Php requirements](#2-php-requirements)
|
||
|
- [**3** From php internally](#3-from-php-internally)
|
||
|
- [**4** From HTTP requests](#4-from-http-requests)
|
||
|
|
||
|
[**III.** Configuration](#iii-configuration)
|
||
|
|
||
|
- [**1** Basic usage](#1-basic-usage)
|
||
|
- [**2** Advanced usage](#2-advanced-usage)
|
||
|
|
||
|
[**IV.** Implementation](#iv-implementation)
|
||
|
|
||
|
- [**1** Permissions : AuthSystem](#1-permissions--authsystem)
|
||
|
- [**2** Modules & methods](#2-modules--methods)
|
||
|
- [**3** Automatic type check](#3-automatic-type-check)
|
||
|
|
||
|
[**V.** Class documentation](#v-class-documentation)
|
||
|
|
||
|
- [**1** Request](#1-request)
|
||
|
- [**2** Response](#2-response)
|
||
|
- [**3** AuthSystem](#4-authsystem)
|
||
|
- [**4** Checker](#4-checker)
|
||
|
- [**5** ModuleFactory](#4-modulefactory)
|
||
|
|
||
|
|
||
|
|
||
|
> # **I.** Overview
|
||
|
|
||
|
> ## **1** Introduction & features
|
||
|
|
||
|
The `api` package (v2.2) allows you to easily create and manage an API. It could be used for an HTTP API (REST, or other kind), or you can use it as an internal core for your system.
|
||
|
|
||
|
The aim of this package is to make your life easier working with APIs or internal delegation. The only things you have to do is to implement your processes and edit the configuration, the package will do the rest.
|
||
|
|
||
|
Things you have to do :
|
||
|
- implement your processes (obviously)
|
||
|
- implement your authentication system (cf. [AuthSystem](#1-permissions--authsystem))
|
||
|
- edit the configuration file (cf. [configuration](#iii-configuration))
|
||
|
|
||
|
Things you **don't have** to do :
|
||
|
- input type check (cf. [Checker](#4-checker))
|
||
|
- API multiple permission management
|
||
|
- optional or required inputs
|
||
|
- before and after scripts
|
||
|
- catch both in-URL and `multipart/form-data` input
|
||
|
|
||
|
> ## **2** Basic knowledge
|
||
|
|
||
|
The API is based over a 2-level delegation structure :
|
||
|
1. `module` which is a set of methods
|
||
|
2. `method` which have input, output, permissions, and is bound to a function
|
||
|
|
||
|
So each of your functionalities must have a `method` name and be inside a `module`.
|
||
|
|
||
|
<u>Example:</u>
|
||
|
* the module `article` contains methods:
|
||
|
* `read` with argument `article_id` (to identify the wanted article)
|
||
|
* `write` with arguments `title` and `body` (data to write into the new created article)
|
||
|
* `edit` with arguments `article_id` and `body` (to identify and replace the body)
|
||
|
* `delete` with argument `article_id` (to identify which article to delete)
|
||
|
|
||
|
If you want to delete the article of id `52`, you must request `article/delete` passing `article_id`=`52`.
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
> # **II.** Usage
|
||
|
|
||
|
> ## **1** Setup
|
||
|
|
||
|
In order to make the API work, you have to :
|
||
|
1. Edit the configuration file according to your needs (cf. [configuration](#iii-configuration))
|
||
|
2. Implement the Authentication System to manage permissions (cf. [AuthSystem](#1-permissions--authsystem))
|
||
|
3. Implement the code of the methods according to the configuration
|
||
|
|
||
|
|
||
|
> ## **2** Php requirements
|
||
|
|
||
|
> ### 1) include the `autoloader` file
|
||
|
|
||
|
```php
|
||
|
<?php require_once '../autoloader.php';
|
||
|
```
|
||
|
|
||
|
> ### 2) load useful classes
|
||
|
|
||
|
```php
|
||
|
// for API use
|
||
|
use \api\core\Request;
|
||
|
use \api\core\Response;
|
||
|
|
||
|
// for error handling
|
||
|
use \error\core\Err;
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
> ## **3** From php internally
|
||
|
|
||
|
|
||
|
> ### 1) create a request
|
||
|
|
||
|
```php
|
||
|
// creates a request for the module {module} and its method {method} with params
|
||
|
$request = new Request('{module}/{method}', [
|
||
|
'param1' => 10,
|
||
|
'param2' => 'somevalue'
|
||
|
]);
|
||
|
```
|
||
|
|
||
|
> ### 2) catch possible errors (optional)
|
||
|
|
||
|
```php
|
||
|
// if error is not Err::Success
|
||
|
if( $request->error->get() !== Err::Success )
|
||
|
'do something';
|
||
|
```
|
||
|
|
||
|
> ### 3) execute the request and catch response
|
||
|
|
||
|
```php
|
||
|
$response = $request->dispatch();
|
||
|
```
|
||
|
|
||
|
> ### 4) catch response errors (optional)
|
||
|
|
||
|
```php
|
||
|
// if error is not Err::Success
|
||
|
if( $response->error->get() !== Err::Success )
|
||
|
'do something';
|
||
|
```
|
||
|
|
||
|
> ### 5) catch response output
|
||
|
|
||
|
```php
|
||
|
// fetch all outputs
|
||
|
$output = $response->getAll();
|
||
|
|
||
|
// fetch specific output
|
||
|
$specific = $response->get('someOutputName');
|
||
|
```
|
||
|
|
||
|
|
||
|
> ## **4** From HTTP requests
|
||
|
In order to setup an automatic bound from HTTP requests to API directly, you must use a **router**.
|
||
|
|
||
|
|
||
|
> ### 1) Format url so it must begin with `/{module}/{method}`
|
||
|
|
||
|
```php
|
||
|
// let's suppose the url is `/api/{module}/{method}`
|
||
|
$url = '/api/somemodule/somemethod/1/2/';
|
||
|
$uri = substr($url, strlen('/api'));
|
||
|
// $uri = /somemodule/somemethod/1/2/
|
||
|
```
|
||
|
|
||
|
> ### 2) give the url to the HTTP manager
|
||
|
|
||
|
```php
|
||
|
// create request from HTTP data
|
||
|
$request = Request::remote($url);
|
||
|
|
||
|
// execute request and catch response
|
||
|
// note that request errors will propagate through response
|
||
|
$response = $request->dispatch();
|
||
|
|
||
|
// return response as HTTP body
|
||
|
die( $response->serialize() );
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
Then can handle various kinds of URL :
|
||
|
|
||
|
- request and parameters can be in URL (separated by `/`)
|
||
|
- request and parameters can be in `multipart/form-data` or `x-www-form-urlencoded`
|
||
|
- request and parameters of both URL, post data, and form-data are caught
|
||
|
|
||
|
### The following examples can work :
|
||
|
> 1. `http://www.host.com/{module}/{method}/`
|
||
|
```json
|
||
|
"post-data": {
|
||
|
"param1": "{value1}",
|
||
|
"param2": "{value2}"
|
||
|
}
|
||
|
```
|
||
|
> 2. `http://www.host.com/{module}/{method}/{param1}/{param2}`
|
||
|
```json
|
||
|
"post-data": {}
|
||
|
```
|
||
|
> 3. `http://www.host.com/apiOrParentUrl/`
|
||
|
```json
|
||
|
"post-data": {
|
||
|
"module": "{module}",
|
||
|
"method": "{method}",
|
||
|
"param1": "{value1}",
|
||
|
"param2": "{value2}"
|
||
|
}
|
||
|
```
|
||
|
> 4. `http://www.host.com/apiOrParentUrl/{value1}/{value2}`
|
||
|
```json
|
||
|
"post-data": {
|
||
|
"module": "{module}",
|
||
|
"method": "{method}",
|
||
|
}
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
> # **III.** Configuration
|
||
|
|
||
|
```json
|
||
|
{
|
||
|
|
||
|
"{module_name}": {
|
||
|
|
||
|
"{http_method}::{method_name}": {
|
||
|
"description": "{method_description}",
|
||
|
"permissions": ["{method_perm}"],
|
||
|
"options": { "download": "{is_downloadable}" },
|
||
|
"parameters": {
|
||
|
"{name_param}": { "description": "{desc_param}", "type": "{type_param}", "optional": "{is_optional}" }
|
||
|
},
|
||
|
"output": {
|
||
|
"{name_output}": { "description": "{desc_output}", "type": "{type_output}" }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
|variable|description|exemple|
|
||
|
|-------|-------|------|
|
||
|
|`{module_name}`|alphanumeric module name|"publications"|
|
||
|
|`{http_method}`|uppercase HTTP method|"POST"|
|
||
|
|`{method_name}`|alphanumeric method name|"article"|
|
||
|
|`{method_description}`|textual description|"Returns a specific article"|
|
||
|
|`{method_perm}`|permission array|`["poster", "admin", "user"]`|
|
||
|
|`{is_downloadable}`|If you want this method to return a file|`true`, `false`|
|
||
|
|`{name_param}`|Your param's name _*_|"id_article"|
|
||
|
|`{desc_param}`|Your param's description|"Wanted article's id"|
|
||
|
|`{type_param}`|Your param's type (cf. Checker)|"Wanted article's type"|
|
||
|
|`{is_optional}`|Whether to make your param _required_|`true`, `false`|
|
||
|
|`{name_output}`|Your output's name|"article"|
|
||
|
|`{desc_output}`|Your output's description|"Article content"|
|
||
|
|
||
|
_*_ If you want URL (GET) parameters, the {param_name} must be `URL_0`, `URL_1` and so on according to the index wanted in the URL.
|
||
|
> `api/module/method/URL_0/URL_1/URL_2/`
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
> # **IV.** Implementation
|
||
|
|
||
|
> ## **1** Permissions : AuthSystem
|
||
|
|
||
|
In order to implement your _Authentification System_ you have to implement the **interface** `AuthSystem` located in `/build/api/core/AuthSystem`.
|
||
|
|
||
|
You must register your custom authentification system before each api call with :
|
||
|
```php
|
||
|
// let's suppose your auth system class is "AuthSystemDefault"
|
||
|
\api\core\Request::setAuthSystem(new AuthSystemDefault);
|
||
|
```
|
||
|
|
||
|
> ## **2** Modules & methods
|
||
|
|
||
|
### Module implementation
|
||
|
Each module's implementation is represented as a **file** so as a **class** located in `/build/api/module/`. In order for the autoloader to work, you must name the **file** the same name as the **class**.
|
||
|
|
||
|
### Method implementation
|
||
|
Each method is represented as a method in its module's class.
|
||
|
|
||
|
### Input arguments
|
||
|
|
||
|
Arguments are passed to the method as a single argument which an associative array according to the documentation.
|
||
|
|
||
|
_Notes_:
|
||
|
* Optional parameters if not given are set to `null`
|
||
|
* parameters of type `FILE` are given by reference but the use is the same as normal parameters
|
||
|
* URL parameters are called `URL_0`, `URL_1` and so on according to their order.
|
||
|
|
||
|
### Ouput required
|
||
|
|
||
|
You must return an associative array containing at least the field `error` containing an instance of `/api/core/Error`, then you can add whatever you want to return in the array.
|
||
|
|
||
|
If you don't return the 'error' field, by default it is set to `new Error(Err::Success)`.
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
> # **V.** Class documentation
|
||
|
|
||
|
> ## **1** Request
|
||
|
|
||
|
### Attributes
|
||
|
|
||
|
The attribute `error` will contain the current `Error` instance.
|
||
|
|
||
|
```php
|
||
|
<?php
|
||
|
public $error;
|
||
|
```
|
||
|
|
||
|
### Methods
|
||
|
|
||
|
Creates a new `Request` object, you must give it a path following the pattern "module/method", the params must be an associative array. Note that the path can be inside the `$params` variable.
|
||
|
|
||
|
It checks missing params and each needed params' type according to the **Checker** implementation (cf. [Checker](#4-checker)). It also checks the permissions you have according to the **AuthSystem** implementation (cf. [AuthSystem](#1-permissions--authsystem)).
|
||
|
|
||
|
```php
|
||
|
<?php
|
||
|
public function __construct(String $path, Array $params) : Request;
|
||
|
```
|
||
|
|
||
|
Creates a new `Request` object but from the URL. It will seek for the *path* in the URL, then in the data. (it will call itself the **\_\_construct()** method).
|
||
|
|
||
|
```php
|
||
|
<?php
|
||
|
public static function remote(String $url, Array $data) : Request;
|
||
|
```
|
||
|
|
||
|
Registers the **AuthSystem** you want, must be done before any construction.
|
||
|
|
||
|
```php
|
||
|
<?php
|
||
|
public static function setAuthSystem(Request $instance) : bool;
|
||
|
```
|
||
|
|
||
|
Executes the current `Request` object and returns a `Response` object.
|
||
|
```php
|
||
|
<?php
|
||
|
public function dispatch() : Response;
|
||
|
```
|
||
|
|
||
|
Same as `dispatch()` but manages the **download** option (cf. [Configuration](#iii-configuration)). It will use 2 of the parameters you must return on success : `body`, and `headers`. The first one must contain the content of the file to create, the second the headers in an associative array.
|
||
|
|
||
|
The call will become the file itself.
|
||
|
|
||
|
Note: If the `HTTP_X_REQUESTED_WITH` header is present, it will create the downloadable file as **/tmp/download_{some\_hash}** and return a normal `Response` object with the field `link` containing the file absolute path.
|
||
|
|
||
|
```php
|
||
|
<?php
|
||
|
public function download() : null;
|
||
|
public function download() : Response; // if called by Ajax
|
||
|
```
|
||
|
|
||
|
> ## **2** Response
|
||
|
|
||
|
### Attributes
|
||
|
|
||
|
The attribute `error` will contain the current `Error` instance.
|
||
|
|
||
|
```php
|
||
|
<?php
|
||
|
public $error;
|
||
|
```
|
||
|
|
||
|
### Methods
|
||
|
|
||
|
Returns an associative array containing the whole response data (excluding the error).
|
||
|
|
||
|
```php
|
||
|
<?php
|
||
|
public function getAll() : Array;
|
||
|
```
|
||
|
|
||
|
Returns only the field from the response data (if it exists).
|
||
|
```php
|
||
|
<?php
|
||
|
public function get(String $key) : mixed; // on success
|
||
|
public function get(String $key) : null; // on error
|
||
|
```
|
||
|
|
||
|
Sets the `HTTP_CODE` according to the `Error` argument, also it sets the header for **application/json**.
|
||
|
|
||
|
It can be used for simple API response, it will add the *"error"* and *"ErrorDescription"* fields to the data and set the headers so you can display the result of the API call.
|
||
|
|
||
|
```php
|
||
|
<?php
|
||
|
public function serialize() : String;
|
||
|
```
|
||
|
|
||
|
|
||
|
> ## **4** Checker
|
||
|
|
||
|
`Checker` checks the input values according to the type given in the configuration.
|
||
|
|
||
|
The default types below are available in the default package.
|
||
|
To add a new type, just open the file `/build/api/Checker.php` and add an entry in the `switch` statement.
|
||
|
|
||
|
### Default types
|
||
|
|Type|Example|Description|
|
||
|
|---|---|---|
|
||
|
|`mixed`|`[9,"a"]`, `"a"`|Any content (can be simple or complex)|
|
||
|
|`id`|`10`, `"23"`|Positive integer number between `0` and `2147483647`|
|
||
|
|`numeric`|`-10.2`, `"23"`|Any number, `null` and the string `"null"`|
|
||
|
|`text`|`"Hello!"`|String that can be of any length (even empty)|
|
||
|
|`hash`|`"4612473aa81f93a878674f9ebffa8d63a1b51ea28dcdcdb1e89eb512aae9b77e"`|String with a length of 40 or 64, containing only hexadecimal characters|
|
||
|
|`alphanumeric`|`"abc029.-sd9"`|String containing only alphanumeric, ___, _-_, and _._ characters|
|
||
|
|`letters`|`"abc -sd"`|String containing only letters, _-_, and space characters|
|
||
|
|`mail`|`"a.b@c.def"`|Valid email address|
|
||
|
|`number`|`0102030405`|Phone number, following formats allowed : `06`, `+336`, `+33 6`|
|
||
|
|`array`|`[1, 3]`|Non-empty array|
|
||
|
|`object`|_works only within php_|Non-empty object|
|
||
|
|`boolean`|`true`, `false`|Boolean|
|
||
|
|`varchar(a,b)`|`"Hello!"`|String with a length between `a` and `b` (included)|
|
||
|
|`varchar(a,b,c)`|`"abc"`|String with a length between `a` and `b` (included) and matching the `c` type|
|
||
|
|
||
|
### Complex type : chainable array
|
||
|
|
||
|
|Type|Sub-Type|Description|
|
||
|
|---|---|---|
|
||
|
|`array<a>`|`a`|Array containing only entries matching the type `a`|
|
||
|
|
||
|
> **Note:** It is possible to chain `array` type as many as needed.
|
||
|
**Ex.:** `array<array<id>>` - Will match array only containing arrays that only contains `id` entries.
|
||
|
|
||
|
|
||
|
> ## **5** Advanced
|
||
|
|
||
|
### Before and After scripts
|
||
|
|
||
|
Each time a **method** is called, the api **creates an instance** from the class, and after the execution, the class is **destroyed**. So you can implement the methods `__construct` and `__destruct` to add before and after scripts.
|