racoon / api
Racoon is a basic API framework designed to make it quick and easy to put together a simple PHP API.
                                    Fund package maintenance!
                                                                            
                                                                                                                                        TomWright
                                                                                    
                                                                            
                                                                                                                                        www.buymeacoffee.com/TomWright
                                                                                    
                                                                
Installs: 394
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 2
Forks: 0
Open Issues: 0
pkg:composer/racoon/api
Requires
- nikic/fast-route: ^1.0
 - racoon/router: ^1.0.1
 - tomwright/validator: *
 
README
Racoon is a basic API framework designed to make it quick and easy to put together a simple PHP API. View the documentation.
Getting Started
Autoloading
Racoon depends on autoloading provided by Composer. If you do not use Composer then you will have to set up your own PSR autoloader or start using Composer.
Quickstart
Create an application, add some routes and run the application.
index.php
// Create an instance of Racoon $app = new Racoon\Api\App(); $router = $app->getRouter(); $router->addRouteFile('/path/to/my_routes.php'); $app->run();
/path/to/my_routes.php
$r->addRoute(['GET', 'POST'], '/users/list', '\\MyApp\\Users@list');
/MyApp/Users.php
namespace MyApp; class Users extends \Racoon\Api\Controller { public function list() { $userList = [ 'Tom', 'John', 'Jess', 'Jo', ]; return $userList; } }
Routing
Racoon uses racoon/router to deal with routing.
Defining where routes are stored
Routes need to be added in a routes file, which should be added to the Router.
$router = $app->getRouter(); $router->addRouteFile('/path/to/some_routes.php');
If you want to store routes in multiple locations you can do it as follows.
$router = $app->getRouter(); $router ->addRouteFile('/path/to/some_routes.php') ->addRouteFile('/path/to/more_routes.php') ->addRouteFile('/path/to/even_more_routes.php');
If you define multiple route locations, they will be included/added in the same order as you define them.
Setting up routes
Inside one of the route files that have been added to the router you need to define your routes in the following format.
$httpRequestMethod = ['GET', 'POST']; $requestUri = '/users/list'; $handlerString = '\\MyApp\\Users@list'; $r->addRoute($httpRequestMethod, $requestUri, $handlerString);
Handler Namespaces
If like me, all of your application controllers are under one namespace, you can use the following method to simplify your routes file.
$r->setHandlerNamespace('\\MyApp\\Controllers');
Before:
$r->addRoute('GET', '/asd', '\\MyApp\\Controllers\\Example@one'); $r->addRoute('GET', '/fgh', '\\MyApp\\Controllers\\Example@two'); $r->addRoute('GET', '/jkl', '\\MyApp\\Controllers\\Example@three');
After:
$r->setHandlerNamespace('\\MyApp\\Controllers'); $r->addRoute('GET', '/asd', '\\Example@one'); $r->addRoute('GET', '/fgh', '\\Example@two'); $r->addRoute('GET', '/jkl', '\\Example@three');
HTTP Request Method
The HTTP Request Method(s) that the route should match. This can be any HTTP request type such as GET or POST.
Can be a string or an array of strings.
Request URI
The request URI that the route should match.
You can define the request URI in multiple ways.
'/users/list' '/users/get/{userId}' '/users/get/{userId:\d+}'
For more information see the FastRoute Route Docs
Any wildcards/placeholders defined here will be passed into the Controller/Handler method.
Handler String
The handler string defines the class and method that should be executed should the current request match a route.
The required format is \MyApp\Users@list where \MyApp\Users is the full class name including the namespace, and list is the method inside of that class which you want to be executed.
Controllers
Your controllers should extend \Racoon\Api\Controller.
The Request
When your Controller is first instantiated it won't have access to the Request object, however, you can create a public function setupRequest() which will be called directly after adding the Request to the Controller. This will then allow you to set up your Controller based on any parameters stored in the Request.
Your Response
You shouldn't echo anything from your Controller. Instead, your method should return something and let Racoon deal with it.
Response Formatter
Racoon allows you choose how your response is to be formatted. By default the \Racoon\Api\Response\Format\JsonFormatter will be used.
You are free to use any Formatter you want, as long as it implements \Racoon\Api\Response\Format\FormatterInterface.
To use a different Formatter just do the following, where \Racoon\Api\Response\Format\JsonFormatter is your chosen Formatter.
$formatter = new \Racoon\Api\Response\Format\JsonFormatter(); $app->setResponseFormatter($formatter);
Returning Errors
In order to easily provide an error response back for a request all you need to do is throw an \Racoon\Api\Exception.
throw new \Racoon\Api\Exception( Request $request = null, // Not required, but could be useful at another time. $displayAsError = false, // True to provide the $message back in the response. False if the framework shouldn't handle it. $message, // Your error message. $code = 0, // If this is not 0 and $displayAsError is True, the http response code will be set to this. \Exception $previous = null // If this is as a result of a previous Exception you can pass that in here. );
If you extend \Racoon\Api\Exception however, you can simply things massively. To demonstrate this we can take a look at the \Racoon\Api\AuthenticationException.
namespace Racoon\Api\Exception; use Racoon\Api\Request; class AuthenticationException extends Exception { public function __construct(Request $request = null, $message, \Exception $previous = null) { parent::__construct($request, true, $message, 401, $previous); } }
This means that we can display an error as follows.
throw new \Racoon\Api\AuthenticationException(null, 'Missing API Key.');
Authentication
By default Racoon doesn't authenticate any requests that come into your application, but it can be easily set up.
You can override the authentication method by setting a new Authenticator before running the app.
$authenticator = new \Racoon\Api\Auth\ApiKeyAuthenticator(); $app->setAuthenticator($authenticator);
Available Authenticators
NoAuthenticator
This Authenticator will allow any request through as it does no authentication.
$authenticator = new \Racoon\Api\Auth\NoAuthenticator(); $app->setAuthenticator($authenticator);
ApiKeyAuthenticator
This Authenticator allows you to specify an array of valid API Keys which it will consider valid.
$authenticator = new \Racoon\Api\Auth\ApiKeyAuthenticator(); $authenticator->setApiKeyName('api_key'); // Tells it to look under api_key to find the api key. $authenticator->addValidApiKey('dsdasdasdasd'); // Add a valid API key. $app->setAuthenticator($authenticator);
Creating Custom Authenticators
You are free to create your own Authenticator, just make sure it implements \Racoon\Api\Auth\AuthInterface.
Schema
The have the ability to create a Schema to easily validate incoming requests, as well as provide some basic documentation to the end user when they are trying out API requests.
A Schema is made up of one or more Items and will be valid if all items pass their constraints.
The following should be run from a Controller and will set up and validate the Schema.
Username will need to be a string between 2 and 20 characters, and password will need to be a string with at least 6 characters.
use Racoon\Api\Schema\Schema; use Racoon\Api\Schema\Translator; $schema = Schema::create([ Translator::item('username')->isString(2, 20)->returnItem(), Translator::item('password')->isString(6)->returnItem(), ]); $this->validateSchema($schema);
You can build more robust rules by doing something like this... Username must be a string between 2 and 4 characters, OR between 10 and 12 characters.
use Racoon\Api\Schema\Schema; use Racoon\Api\Schema\Translator; $schema = Schema::create([ Translator::item('username')->isString(2, 4)->alt()->isString(10, 12)->returnItem(), ]); $this->validateSchema($schema);
The validation is done using TomWright/Validator so for more information please see the related GitHub page.
Request
The Request object contains most of the information about the current request such as the request URI, the data provided in the request, as well as the current Schema. The Request object can also be accessed from your Controller using $this->getRequest().
If for some reason you want to expand on the functionality of Racoon so as to store more data about the Request you can extend \Racoon\Api\Request and then tell Racoon to use your Request class instead.
namespace MyApp; class Request extends \Racoon\Api\Request { } $app->setRequestClass('\\MyApp\\Request');
Fetching Request Data
You can get the input data by using $request->getRequestData(), however there are also 2 helper methods to streamline things for you a little in the Controller.
// Fetches the username from the input data, and if it doesn't exist it will return 'unknown'. $request->getOptionalRequestData('username', 'unknown'); // Fetches the username from the input data. // If it doesn't exist or has a length of 0, an error message will be shown to the client. $request->getRequiredRequestData('username');
Using the API
Using the API is simple.
All data is passed to Racoon as JSON in a GET or POST variable named json.
If you want to send data under a different name rather than json, you can do the following.
$app->setJsonKeyName('new_json_key');
Let's say we have got things set up for mydomain.com, and we have a route that matches /users/get with a required item of user_id. If we were to make a GET request, the request should look something like this....
http://mydomain.com/users/get?json={"request":{"user_id": 5}}
Notice that the request is in it's own object inside of json. This allows you to separate authentication/test parameters from the actual data you want to use in your Controller.
E.g.
http://mydomain.com/users/get?json={"api_key": "easSdasesfWasd","request":{"user_id": 5}}
Response
When working with Racoon you will always get a formatted response that looks something like the following (depending on which Response Formatter you use).
{
    "success": false,
    "message": "Missing required field: asd",
    "schema": {
        "first_name": "first_name must be a string, be at least 3 characters in length."
    },
    "received": {
        "api_key": "qweqwe",
        "request": {
            "first_name": "Tom"
        }
    },
    "time_elapsed": "110.129",
    "response": null
}
Success
True if no Exception was thrown. False if an Exception was thrown.
Message
The message set by the Controller, or the Exception message.
Schema
The Schema that was set up in the Controller.
Received
The data that was sent to the API.
Time Elapsed
The time (in ms) that it took for the API request to be processed.
Response
The data that was returned by the Controller.
HTTP Response Code
In addition to the above, if an Exception is thrown that is set up to return the error, the code of that Exception will be used to set the HTTP response code.