upd: notice.api:3.0 (began updating api:3.0)
This commit is contained in:
parent
0a945431b7
commit
ae41ff9a5e
|
@ -6,7 +6,7 @@ requires:
|
||||||
- error: 2.0
|
- error: 2.0
|
||||||
```
|
```
|
||||||
|
|
||||||
Links
|
Plan
|
||||||
====
|
====
|
||||||
|
|
||||||
[**I.** Overview](#i-overview)
|
[**I.** Overview](#i-overview)
|
||||||
|
@ -44,6 +44,7 @@ Links
|
||||||
|
|
||||||
# **I.** Overview
|
# **I.** Overview
|
||||||
|
|
||||||
|
----
|
||||||
## **1** Introduction & features
|
## **1** Introduction & features
|
||||||
|
|
||||||
The `api` package (v3.0) allows you to easily create and manage an API for your applications. It can be used as an HTTP API (REST, or other kind), and you can use it as an internal core for your system.
|
The `api` package (v3.0) allows you to easily create and manage an API for your applications. It can be used as an HTTP API (REST, or other kind), and you can use it as an internal core for your system.
|
||||||
|
@ -51,9 +52,9 @@ The `api` package (v3.0) allows you to easily create and manage an API for your
|
||||||
The aim of this package is to make your life easier working with APIs and internal delegation. The only things you have to do is to implement your processes and write the configuration, the package will do the rest.
|
The aim of this package is to make your life easier working with APIs and internal delegation. The only things you have to do is to implement your processes and write the configuration, the package will do the rest.
|
||||||
|
|
||||||
Things you **have** to do :
|
Things you **have** to do :
|
||||||
- implement your processes (obviously)
|
- write the configuration file (cf. [configuration](#iii-configuration))
|
||||||
- implement your authentication system (cf. [AuthSystem](#1-permissions--authsystem))
|
- implement your authentication system (cf. [AuthSystem](#1-permissions--authsystem))
|
||||||
- setup the configuration file (cf. [configuration](#iii-configuration))
|
- implement your processes (obviously)
|
||||||
|
|
||||||
Things you **don't have** to do :
|
Things you **don't have** to do :
|
||||||
- input type check (cf. [Checker](#4-checker))
|
- input type check (cf. [Checker](#4-checker))
|
||||||
|
@ -64,11 +65,11 @@ Things you **don't have** to do :
|
||||||
- before and after scripts
|
- before and after scripts
|
||||||
- and a lot more ...
|
- and a lot more ...
|
||||||
|
|
||||||
> ## **2** Basic knowledge
|
## **2** Basic knowledge
|
||||||
|
|
||||||
The api is made of paths that binds to a *php class*, each `path` can manage multiple **HTTP METHODS** each will correspond to a *method* of the bound class.
|
The api is made of paths that binds to a *php class*, each `path` can manage multiple **HTTP METHODS** each will correspond to a *method* of the bound class.
|
||||||
|
|
||||||
So each of your functionalities must have a `method` and a corresponding a `path`.
|
So each of your functionalities must have a dedicated `HTTP method` and a corresponding a `path`.
|
||||||
|
|
||||||
<u>Example:</u>
|
<u>Example:</u>
|
||||||
* the module `article` contains methods:
|
* the module `article` contains methods:
|
||||||
|
@ -84,139 +85,63 @@ So each of your functionalities must have a `method` and a corresponding a `path
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
> # **II.** Usage
|
# **II.** Usage
|
||||||
|
|
||||||
> ## **1** Setup
|
----
|
||||||
|
|
||||||
In order to make the API work, you have to :
|
## **1** REST API
|
||||||
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
|
|
||||||
|
|
||||||
|
In order for the API to catch **URI**, you must use a router. It will allow the API to get the requested URI.
|
||||||
|
|
||||||
> ## **2** Php requirements
|
*Important*: You must use `$_SERVER['REQUEST_URI']` because it will (instead of other methods) keep some useful format.
|
||||||
|
|
||||||
> ### 1) include the `autoloader` file
|
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php require_once '../autoloader.php';
|
<?php
|
||||||
```
|
|
||||||
|
|
||||||
> ### 2) load useful classes
|
require_once '../autoloader.php';
|
||||||
|
|
||||||
```php
|
|
||||||
// for API use
|
|
||||||
use \api\core\Request;
|
|
||||||
use \api\core\Response;
|
|
||||||
|
|
||||||
// for error handling
|
|
||||||
use \error\core\Err;
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
/* (1) Create the request */
|
||||||
|
$request = \api\core\Loader::remote($_SERVER['REQUEST_URI']);
|
||||||
|
|
||||||
|
/* (2) Process the response (execute your implementation) */
|
||||||
> ## **3** From php internally
|
|
||||||
|
|
||||||
|
|
||||||
> ### 1) create a request
|
|
||||||
|
|
||||||
```php
|
|
||||||
// creates a request @path with params
|
|
||||||
$request = new \api\core\Request('some/path', [
|
|
||||||
'param1' => 10,
|
|
||||||
'param2' => 'somevalue'
|
|
||||||
], 'POST'); // wanted HTTP method to emulate
|
|
||||||
```
|
|
||||||
|
|
||||||
> ### 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 `/@path`
|
|
||||||
|
|
||||||
```php
|
|
||||||
// let's suppose the url is `/api/@path`
|
|
||||||
$url = '/api/some/path/1/2/';
|
|
||||||
$uri = substr($url, strlen('/api'));
|
|
||||||
// $uri = /some/path/1/2/
|
|
||||||
```
|
|
||||||
|
|
||||||
> ### 2) give the url to the HTTP manager
|
|
||||||
|
|
||||||
```php
|
|
||||||
// create request from HTTP data
|
|
||||||
$request = \api\core\Loader::remote($uri);
|
|
||||||
|
|
||||||
// execute request and catch response
|
|
||||||
// note that request errors will propagate through response
|
|
||||||
$response = $request->dispatch();
|
$response = $request->dispatch();
|
||||||
|
|
||||||
// return response as HTTP body
|
/* (3) Serialize the response */
|
||||||
die( $response->serialize() );
|
echo $response->serialize();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
*Note:* `Request` or `Response` errors will propagate to *serialize()* method into the JSON output.
|
||||||
|
|
||||||
|
## **2** Internal use
|
||||||
|
|
||||||
|
You can also use the API from within your code (not from URI).
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once '../autoloader.php';
|
||||||
|
|
||||||
|
|
||||||
Then can handle various kinds of URL :
|
/* (1) Emulate API data */
|
||||||
|
$emu_uri = '/some/target/uri';
|
||||||
|
$emu_params = [ 'p1' => 'param1', 'URL0' => 'uri param 0' ];
|
||||||
|
$emu_method = 'DELETE';
|
||||||
|
|
||||||
- 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 :
|
/* (2) Create the request */
|
||||||
> 1. `http://www.host.com/@path/{param3}`
|
$request = new \api\core\Request($emu_uri, $emu_params, $emu_method);
|
||||||
```json
|
|
||||||
"post-data": {
|
|
||||||
"param1": "{value1}",
|
|
||||||
"param2": "{value2}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
> 2. `http://www.host.com/@path/{param1}/{param2}`
|
/* (3) Process the response (execute your implementation) */
|
||||||
```json
|
$response = $request->dispatch();
|
||||||
"post-data": {}
|
|
||||||
```
|
|
||||||
|
|
||||||
> 3. `http://www.host.com/@path/1,`
|
/* (4) [OPTIONAL] Check for errors */
|
||||||
```json
|
if( $response->error->get() != \error\core\Err::Success )
|
||||||
"post-data": {
|
die('encountered error: '.$response->error->explicit());
|
||||||
"param1": "{value1}",
|
|
||||||
"param2": "{value2}"
|
/* (5) Fetch response data */
|
||||||
}
|
$all_response_fields = $response->getAll();
|
||||||
|
$specific_response_field = $response->get('specific_field_name');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -224,68 +149,152 @@ Then can handle various kinds of URL :
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
> # **III.** Configuration
|
# **III.** Configuration
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
|
||||||
|
The documentation consists of a _chain_ of urls each one containing no or several HTTP method specifications.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## **1** - configuration format
|
||||||
|
|
||||||
|
The configuration is a set of `uri` paths that can contain up to 4 method types: **POST**, **DELETE**, **PUT**, **GET** or `uri` subpaths.
|
||||||
|
|
||||||
|
For instance the 4 methods directly inside `uri1` will be triggered when the calling URI is `/uri1`, the ones directly inside `uri2` will be triggered when calling `/uri1/uri2` and so on..
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
"uri1" : {
|
||||||
|
"GET": method.definition,
|
||||||
|
"POST": method.definition,
|
||||||
|
"PUT": method.definition,
|
||||||
|
"DELETE": method.definition,
|
||||||
|
|
||||||
"{module_name}": {
|
"uri2": {
|
||||||
|
"GET": method.definition,
|
||||||
|
"POST": method.definition,
|
||||||
|
"PUT": method.definition,
|
||||||
|
"DELETE": method.definition,
|
||||||
|
|
||||||
"{http_method}::{method_name}": {
|
"uri3": {}
|
||||||
"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|
|
**Note**: It is possible to trigger the *root uri* (`/`), so you can set methods directly at the root of the JSON file.
|
||||||
|-------|-------|------|
|
|
||||||
|`{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.
|
## **2** - method.definition
|
||||||
> `api/module/method/URL_0/URL_1/URL_2/`
|
```json
|
||||||
|
{
|
||||||
|
"des": method.description,
|
||||||
|
"per": method.permissions,
|
||||||
|
"par": method.parameters,
|
||||||
|
"out": method.output_format,
|
||||||
|
"opt": method.options
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## **2.1** - method.description
|
||||||
|
|
||||||
|
The *description* field must be a **string** containing the human-readable description of what the method does.
|
||||||
|
|
||||||
|
## **2.2** - method.permissions
|
||||||
|
|
||||||
|
The *permissions* field must be an array. You can manage **OR** and **AND** permission combinations.
|
||||||
|
|
||||||
|
- **OR** is applied between each **0-depth** array
|
||||||
|
- **AND** is applied between each **1-depth** array
|
||||||
|
|
||||||
|
For instance the following permission `[ ["a","b"], ["c"] ]` means you need the permissions **a** and **b** combined or only the permission **c**.
|
||||||
|
|
||||||
|
## **2.3** - method.parameters
|
||||||
|
|
||||||
|
The *parameters* field must be an object containing each required or optional parameter needed for the implementation.
|
||||||
|
|
||||||
|
```json
|
||||||
|
"parameter.name": {
|
||||||
|
"des": parameter.description,
|
||||||
|
"typ": parameter.checker_type,
|
||||||
|
"opt": parameter.is_optional,
|
||||||
|
"ren": parameter.rename,
|
||||||
|
"def": parameter.default_value,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### parameter.name
|
||||||
|
|
||||||
|
The *name* field must be a **string** containing variable name that will be asked for the caller.
|
||||||
|
|
||||||
|
Note that you can set any string for **body parameters**, but **GET parameters** must be named `URL#`, where `#` is the index within the URI, beginning with 0.
|
||||||
|
#### parameter.description
|
||||||
|
|
||||||
|
The *description* field must be a **string** containing the human-readable description of what the parameter is or must be.
|
||||||
|
#### parameter.checker_type
|
||||||
|
|
||||||
|
The *checker_type* field must be a **string** corresponding to a `\api\core\Checker` type that will be checked before calling the implementation.
|
||||||
|
|
||||||
|
#### parameter.is_optional
|
||||||
|
|
||||||
|
The *is_optional* field must be a **boolean** set to `true` if the parameter can be ommited. By default, the field is set to `false` so each parameter is required.
|
||||||
|
|
||||||
|
#### parameter.rename
|
||||||
|
|
||||||
|
The *rename* field must be a **string** corresponding to the *variable name* given to the implementation. It is useful for **GET parameters** because they need to be called `URL#`, where `#` is the position in the URI.
|
||||||
|
|
||||||
|
If ommited, by default, `parameter.name` will be used.
|
||||||
|
#### parameter.default_value
|
||||||
|
|
||||||
|
The *default_value* field must be of any type according to the *checker_type* field, it will be used only for **optional** parameters when ommited by the caller
|
||||||
|
|
||||||
|
By default, each optional parameter will exist and will be set to `null` to the implementation.
|
||||||
|
|
||||||
|
## **2.4** - method.output_format
|
||||||
|
|
||||||
|
The *output_format* field must have the same format as `method.parameters` but will only be used to generate a documentation or to tell other developers what the method returns if no error occurs.
|
||||||
|
|
||||||
|
## **2.5** - method.options
|
||||||
|
|
||||||
|
The *options* field must be an **object** containing the available options.
|
||||||
|
|
||||||
|
The only option available for now is:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"download": true
|
||||||
|
```
|
||||||
|
|
||||||
|
Your implementation must return 2 fields:
|
||||||
|
- `body` a string containing the file body
|
||||||
|
- `headers` an array containing as an associative array file headers
|
||||||
|
|
||||||
|
If the API is called with HTTP directly, it will not print the **json** response (only on error), but will instead directly return the created file.
|
||||||
|
|
||||||
|
*AJAX:* If called with ajax, you must give the header `HTTP_X_REQUESTED_WITH` set to `XMLHttpRequest`. In that case only, it will return a normal JSON response with the field `link` containing the link to call for downloading the created file. **You must take care of deleting not used files** - there is no such mechanism.
|
||||||
|
|
||||||
|
|
||||||
|
# **IV.** Implementation
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
## **1** - permissions : AuthSystem
|
||||||
|
|
||||||
|
|
||||||
> # **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`.
|
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 :
|
You must register your custom authentification system before each api call.
|
||||||
|
|
||||||
|
For instance, lets suppose your implementation is called `myAuthSystem`.
|
||||||
```php
|
```php
|
||||||
// let's suppose your auth system class is "AuthSystemDefault"
|
\api\core\Request::setAuthSystem(new myAuthSystem);
|
||||||
\api\core\Request::setAuthSystem(new AuthSystemDefault);
|
|
||||||
```
|
```
|
||||||
|
**Note**: By default the API will try to find `\api\core\AuthSystemDefault`.
|
||||||
|
|
||||||
> ## **2** Modules & methods
|
|
||||||
|
|
||||||
### Module implementation
|
## **2** - core implementation
|
||||||
|
|
||||||
|
### each path
|
||||||
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**.
|
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
|
### Method implementation
|
||||||
|
@ -309,9 +318,9 @@ If you don't return the 'error' field, by default it is set to `new Error(Err::S
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
> # **V.** Class documentation
|
# **V.** Class documentation
|
||||||
|
|
||||||
> ## **1** Request
|
## **1** Request
|
||||||
|
|
||||||
### Attributes
|
### Attributes
|
||||||
|
|
||||||
|
@ -365,7 +374,7 @@ Note: If the `HTTP_X_REQUESTED_WITH` header is present, it will create the downl
|
||||||
public function download() : Response; // if called by Ajax
|
public function download() : Response; // if called by Ajax
|
||||||
```
|
```
|
||||||
|
|
||||||
> ## **2** Response
|
## **2** Response
|
||||||
|
|
||||||
### Attributes
|
### Attributes
|
||||||
|
|
||||||
|
@ -402,7 +411,7 @@ It can be used for simple API response, it will add the *"error"* and *"ErrorDes
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
> ## **4** Checker
|
## **4** Checker
|
||||||
|
|
||||||
`Checker` checks the input values according to the type given in the configuration.
|
`Checker` checks the input values according to the type given in the configuration.
|
||||||
|
|
||||||
|
@ -437,7 +446,7 @@ To add a new type, just open the file `/build/api/Checker.php` and add an entry
|
||||||
**Ex.:** `array<array<id>>` - Will match array only containing arrays that only contains `id` entries.
|
**Ex.:** `array<array<id>>` - Will match array only containing arrays that only contains `id` entries.
|
||||||
|
|
||||||
|
|
||||||
> ## **5** Advanced
|
## **5** Advanced
|
||||||
|
|
||||||
### Before and After scripts
|
### Before and After scripts
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue