xdrm-framework/notice/api/3.0.md

14 KiB

module: api
version: 3.0
requires:
  - http:  1.0
  - error: 2.0

Plan

I. Overview

II. Usage

III. Configuration

IV. Implementation

V. Class documentation

I. Overview

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 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 :

  • write the configuration file (cf. configuration)
  • implement your authentication system (cf. AuthSystem)
  • implement your processes (obviously)

Things you don't have to do :

  • input type check (cf. Checker)
  • multiple permission management
  • optional or required input
  • multipart and file input
  • URL input
  • before and after scripts
  • and a lot more ...

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.

So each of your functionalities must have a dedicated HTTP method and a corresponding a path.

Example:

  • the module article contains methods:
    • GET to get article data
    • POST to post a new article
    • PUT to edit an existing article
    • DELETE to delete an exisint article

Note that each method must be a valid HTTP METHOD.

II. Usage

1 REST API

In order for the API to catch URI, you must use a router. It will allow the API to get the requested URI.

Important: You must use $_SERVER['REQUEST_URI'] because it will (instead of other methods) keep some useful format.

<?php

require_once '../autoloader.php';


/* (1) Create the request */
$request = \api\core\Loader::remote($_SERVER['REQUEST_URI']);

/* (2) Process the response (execute your implementation) */
$response = $request->dispatch();

/* (3) Serialize the response */
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

require_once '../autoloader.php';


/* (1) Emulate API data */
$emu_uri    = '/some/target/uri';
$emu_params = [ 'p1' => 'param1', 'URL0' => 'uri param 0' ];
$emu_method = 'DELETE';


/* (2) Create the request */
$request = new \api\core\Request($emu_uri, $emu_params, $emu_method);

/* (3) Process the response (execute your implementation) */
$response = $request->dispatch();

/* (4) [OPTIONAL] Check for errors */
if( $response->error->get() != \error\core\Err::Success )
	die('encountered error: '.$response->error->explicit());

/* (5) Fetch response data */
$all_response_fields     = $response->getAll();
$specific_response_field = $response->get('specific_field_name');

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

{
	"uri1" : {
		"GET":    method.definition,
		"POST":   method.definition,
		"PUT":    method.definition,
		"DELETE": method.definition,

		"uri2": {
			"GET":    method.definition,
			"POST":   method.definition,
			"PUT":    method.definition,
			"DELETE": method.definition,

			"uri3": {}
		}
	}
}

Note: It is possible to trigger the root uri (/), so you can set methods directly at the root of the JSON file.

2 - method.definition

{
	"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.

"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:

"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

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.

For instance, lets suppose your implementation is called myAuthSystem.

\api\core\Request::setAuthSystem(new myAuthSystem);

Note: By default the API will try to find \api\core\AuthSystemDefault.

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.

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
	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). It also checks the permissions you have according to the AuthSystem implementation (cf. AuthSystem).

<?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
	public static function remote(String $url, Array $data) : Request;

Registers the AuthSystem you want, must be done before any construction.

<?php
	public static function setAuthSystem(Request $instance) : bool;

Executes the current Request object and returns a Response object.

<?php
	public function dispatch() : Response;

Same as dispatch() but manages the download option (cf. 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
	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
	public $error;

Methods

Returns an associative array containing the whole response data (excluding the error).

<?php
	public function getAll() : Array;

Returns only the field from the response data (if it exists).

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