Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

foxdie/plankton

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

128 Commits

Repository files navigation

Plankton: a RESTful API microframework

Requirements

  • PHP >= 7.2
  • PHP cURL extension
  • Apache HTTP Server >= 2.4
  • Apache mod_rewrite enabled

Installation

composer require foxdie/rest

Table of content

Client

Creating a client

use Plankton\Client\Client;
	
$client = new Client(API_ENDPOINT);

Full example here: https://github.com/foxdie/rest/blob/master/Test/public/simple-client.php

GET example

$response = $client->get("/users");

using callback

$client->get("/users", function(Response $response){
	echo $response;
});

using magic

$response = $client->getUsers();

POST example

$response = $client->post("/users", ["email" => "foo@bar.com"]);

using callback

$client->post("/users", ["email" => "foo@bar.com"], function(Response $response){
	echo $response->getLocation();
});

using magic

$response = $client->postUsers(["email" => "foo@bar.com"]);

PUT, PATCH and DELETE examples

Full example here: https://github.com/foxdie/rest/blob/master/Test/public/simple-client.php

Magic calls

Spinal case

If you want to use magic calls, your routes must use the spinal case Example:

$client->getUserAccounts()

will match the following route:

GET /user-accounts

camel case and snake case are not supported

Examples

call route
$client->getUsers(); GET /users
$client->groups(1)->getUsers(); GET /groups/1/users
$client->groups(1)->getUsers(2); GET /groups/1/users/2
$client->postUsers([]); POST /users
$client->groups(1)->postUsers([]); POST /groups/1/users
$client->deleteUsers(1); DELETE /users/1
$client->users(1)->delete(); DELETE /users/1
$client->groups(1)->deleteUsers(2); DELETE /groups/1/users/2
$client->groups(1)->users(2)->delete(); DELETE /groups/1/users/2
$client->groups(1)->users()->delete(2); DELETE /groups/1/users/2

Content types

When you are using magic calls (e.g. $client->postUsers([]);) or one of the methods Client::post(), Client::put(), Client::patch(), a Content-Type header is automatically added to the request. The Content-Type is automatically guessed according to the data you send to the server :

data type Content-Type
array application/x-www-form-urlencoded
object application/json
valid json string application/json
valid xml string application/xml
string text/plain

However, you still can set the Content-Type manually with a customized request

Custom request example

use Plankton\Client\Client;
use Plankton\Request;
$request = new Request(API_ENDPOINT . "/users");
$request
 ->setMethod(Request::METHOD_POST)
 ->setParameter("foo", "bar")
 ->setHeader("User-Agent", "Mozilla/5.0")
 ->setContentType(Request::CONTENT_TYPE_JSON)
 ->setData(["email" => "foo@bar.com"]);
$client = new Client(API_ENDPOINT);
$client->send($request, function(Response $response){
 // ...
});

Automatic data conversion

For readability reasons, you can use arrays or objects with the Request::setData() method, regardless of the content-type you use. The data will be automatically converted according to the rules below :

Content-Type Data type Conversion
Request::CONTENT_TYPE_JSON array json string
Request::CONTENT_TYPE_JSON object json string
other array URL-encoded query string
other object URL-encoded query string

Authentication strategy

anonymous auth

$client = new Client(API_ENDPOINT);

basic auth

use Plankton\Client\Strategy\BasicAuthentication;
$client = new Client(API_ENDPOINT, new BasicAuthentication(USER, PASSWORD));

client credentials

use Plankton\Client\Strategy\ClientCredentialsAuthentication;
$client = new Client(API_ENDPOINT, new ClientCredentialsAuthentication(
	CLIENT_ID, 
	CLIENT_SECRET,
	AUTHENTICATION_URL
));

The authorize and access/refresh token requests will be performed automatically. The 3rd parameter is optionnal, the default value is "/token"

Server

Creating a server

use Plankton\Server\Server;
$server = new Server();
$server->run();

Full example here: https://github.com/foxdie/rest/blob/master/Test/public/simple-server.php

Creating controllers

You must create at least one controller which extends the abstract class Plankton\Server\Controller

use Plankton\Server\Controller;
class APIController extends Controller{
	public function getUsers(int $id, Request $request): Response{
	}
	
	public function postUsers(Request $request): Response{
	}
}

Your controller will contain one public method for each action of your API.

You can create routes in 2 different ways:

  • using a config file
  • using annotations

Using a config file

This will automatically disable the annotation parser. The routes are described in a YAML file

Example of config file
routes:
 get-user:
 path: /users/{id}
 method: GET
 controller: Test\Controller\APIController::getUser
 create-user:
 path: /users
 method: POST
 controller: Test\Controller\APIController::createUser

Full example here: https://github.com/foxdie/plankton/blob/master/Test/config/server.yml

Configuring the server
use Plankton\Server\{Server, Config};
$server = new Server(new Config(CONFIG_PATH));

Full example here: https://github.com/foxdie/plankton/blob/master/Test/public/config-server.php

Using annotations

use Plankton\Server\Controller;
class APIController extends Controller{
	/**
	 * @Route(/users/{id})
	 * @Method(GET)
	 */
	public function getUser(int $id, Request $request): Response{
	}
	
	/**
	 * @Route(/users)
	 * @Method(POST)
	 */
	public function createUser(Request $request): Response{
	}
}

The routes will be created automatically according to the annotations @Route and @Method.

Full example here : https://github.com/foxdie/rest/blob/master/Test/Controller/APIController.php

@Route annotation
  • accepts regular expresssions
  • accepts placeholders: they will be passed as argument in the same order as they appear
  • the spinal case is strongly recommended

You can add a route prefix to your controller:

/**
 * @Route(/users)
 */
class APIController extends Controller{
	/**
	 * @Route(/{id})
	 * @Method(GET)
	 */
	public function getUser(int $id, Request $request): Response{
	}
	
	/**
	 * @Route(/)
	 * @Method(POST)
	 */
	public function createUser(Request $request): Response{
	}
}
@Method annotation

Possible values are:

  • GET
  • POST
  • PUT
  • PATCH
  • DELETE
@Exception annotation
class APIController extends Controller{
	/**
	 * This will catch any \CustomNameSpace\CustomException
	 * @Exception(CustomNameSpace\CustomException)
	 */
	public function catchCustomException(Exception $e, Request $request): Response{
	}
	
	/**
	 * This will catch all other exceptions
	 * @Exception(*)
	 */
	public function catchException(Exception $e, Request $request): Response{
	}
}

Registering controllers

use Plankton\Server\Server;
$server = new Server();
$server
	->registerController(new APIController());
	->registerController(...);
	->run();

Full example here: https://github.com/foxdie/rest/blob/master/Test/public/simple-server.php

Creating middlewares

(this is optionnal) You must implement the Plankton\Server\Middleware interface. The middlewares can handle both incoming requests and outgoing responses.

use Plankton\Server\{Request, Response};
use Plankton\Server\{Middleware, RequestDispatcher};
class BasicAuthenticationMiddleware implements Middleware{
	public function process(Request $request, RequestDispatcher $dispatcher): Response{
		// ...
		return $dispatcher->process($request);
	}
}

Full example here: https://github.com/foxdie/rest/blob/master/Test/Middleware/BasicAuthenticationMiddleware.php

Registering the middlewares

use Plankton\Server\Server;
$server = new Server();
$server
	->addMiddleware(new BasicAuthenticationMiddleware())
	->addMiddleware(...)
	->registerController(new APIController())
	->run();

OAuth2

Client Credentials Grant

Client

use Plankton\Client\Client;
use Plankton\Client\Strategy\ClientCredentialsAuthentication;
use Plankton\Response;
$client = new Client(API_ENDPOINT, new ClientCredentialsAuthentication(
	CLIENT_ID, 
	CLIENT_SECRET,
	AUTHENTICATION_URL
));

Full example here: https://github.com/foxdie/rest/blob/master/Test/public/oauth2-client.php

Server

use Plankton\Server\Server;
use OAuth2\Middleware\ClientCredentialsMiddleware;
use OAuth2\Provider\MemoryProvider;
use Test\Controller\APIController;
// Access Token provider
$provider = new MemoryProvider();
$provider->addClient(CLIENT_ID, CLIENT_SECRET);
$server = new Server();
$server
	->addMiddleware(new ClientCredentialsMiddleware($provider))
	->registerController(new APIController())
	->run();

Full example here: https://github.com/foxdie/rest/blob/master/Test/public/oauth2-server.php

Creating your own Access Token Provider

All you have to do is to implement the AccessTokenProvider interface:

use Plankton\OAuth2\Provider\AccessTokenProvider;
use Plankton\OAuth2\Token\{AccessToken, BearerToken};
class PDOProvider implements AccessTokenProvider{
	/**
	 * return a new/issued Access Token if you find a client matching the authentication parameters (id + secret)
	 */
	public function getAccessToken(string $client_id, string $client_secret): ?AccessToken{
	}
	/**
	 * return a new Access Token if the Refresh Token is valid
	 */
	public function refreshToken(string $refreshToken): ?AccessToken{
	}
	/**
	 * authorize or not the given Access Token
	 */
	public function isValidAccessToken(string $token): bool{
	}
}

Logging

Client side

Simple logger

use Plankton\Logging\SimpleLogger;
$client->setLogger(new SimpleLogger());
// ... do some requests
foreach ($client->getLogger()->getLogs() as $request) {
	$response = $client->getLogger()->getLogs()[$request];
}

Full example here: https://github.com/foxdie/rest/blob/master/Test/public/simple-client.php

XML logger

use Plankton\Logging\XMLLogger;
$client->setLogger(new XMLLogger());
// ... do some requests
header("Content-type: text/xml");
echo $client->getLogger()->getLogs()->asXML();

Full example here: https://github.com/foxdie/rest/blob/master/Test/public/oauth2-client.php

Custom logger

You have to implement the Plankton\Request\Logger interface:

use Plankton\{Request,Response};
use Plankton\Request\Logger
class CustomLogger implements Logger{
	public function log(Request $request, Response $response = NULL): void{
	}
}

Server side

You can easily log requests and responses by adding a middleware:

use Plankton\{Request,Response};
use Plankton\Server\{Middleware, RequestDispatcher};
class LogMiddleware implements Middleware{
	public function process(Request $request, RequestDispatcher $dispatcher): Response{		
		$response = $dispatcher->process($request);
		
		// log $request and $response here
		
		return $response
	}
}

and then register the middleware(#registering-the-middlewares)

use Plankton\Server\Server;
use Test\Controller\APIController;
use Test\Middleware\LogMiddleware;
$server = new Server();
$server
	->addMiddleware(new LogMiddleware())
	->registerController(new APIController())
	->run();

About

PHP REST API microframework

Topics

Resources

Stars

Watchers

Forks

Packages

Contributors

Languages

AltStyle によって変換されたページ (->オリジナル) /