Download the PHP package juklicek/restful without Composer
On this page you can find all versions of the php package juklicek/restful. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Informations about the package restful
Nette REST API
This repository is being developed.
Content
- Requirements
- Installation & setup
- Neon configuration
- Sample usage
- Simple CRUD resources
- Accessing input data
- Input data validation
- Error presenter
- Security & authentication
- Secure your resources with OAuth2
- JSONP support
- Utilities that make life better
Requirements
Drahak/Restful requires PHP version 5.3.0 or higher. The only production dependency is Nette framework 2.0.x. The Restful also works well with my Drahak\OAuth2 provider (see Secure your resources with OAuth2)
Installation & setup
The easiest way is to use Composer
$ composer require drahak/restful:@dev
Then register the extension by adding this code to bootstrap.php
(before creating container):
or register it in config.neon
:
Neon configuration
You can configure Drahak\Restful library in config.neon in section restful
:
cacheDir
: not much to say, just directory where to store cachejsonpKey
: sets query parameter name, which enables JSONP envelope mode. Set this to FALSE if you wish to disable it.prettyPrintKey
: API prints every resource with pretty print by default. You can use this query parameter to disable itconvention
: resource array keys conventions. Currently supported 3 values:snake_case
,camelCase
&PascalCase
which automatically converts resource array keys. You can write your own converter. Just implementDrahak\Restful\Resource\IConverter
interface and tag your service withrestful.converter
.routes.generateAtStart
: generating routes at start of Router (only for auto generated routes and if is Router set over config.neon)routes.prefix
: mask prefix to resource routes (only for auto generated routes)routes.module
: default module to resource routes (only for auto generated routes)routes.autoGenerated
: ifTRUE
the library auto generate resource routes from Presenter action method annotations (see below)routes.panel
: ifTRUE
the resource routes panel will appear in your nette debug barmappers
: replace existing mappers or add new mappers for different content-typessecurity.privateKey
: private key to hash secured requestssecurity.requestTimeKey
: key in request body, where to find request timestamp (see below - Security & authentication)security.requestTimeout
: maximal request timestamp age
Tip: Use gzip compression for your resources. You can enable it simply in neon:
Resource routes panel
It is enabled by default but you can disable it by setting restful.routes.panel
to FALSE
. This panel show you all REST API resources routes (exactly all routes in default route list which implements IResourceRouter
interface). This is useful e.g. for developers who develop client application, so they have all API resource routes in one place.
Sample usage
Resource output is determined by Accept
header. Library checks the header for application/xml
, application/json
, application/x-data-url
and application/www-form-urlencoded
and keep an order in Accept
header.
Note: If you call $presenter->sendResource()
method with a mime type in first parameter, API will accept only this one.
Also note: There are available annotations @GET
, @POST
, @PUT
, @HEAD
, @DELETE
. This allows Drahak\Restful library to generate API routes for you so you don't need to do it manually. But it's not necessary! You can define your routes using IResourceRoute
or its default implementation such as:
There is only one more parameter unlike the Nette default Route, the request method. This allows you to generate same URL for e.g. GET and POST method. You can pass this parameter to route as a flag so you can combine more request methods such as ResourceRoute::GET | ResourceRoute::POST
to listen on GET and POST request method in the same route.
You can also define action names dictionary for each request method:
Simple CRUD resources
Well it's nice but in many cases I define only CRUD operations so how can I do it more intuitively? Use CrudRoute
! This child of ResourceRoute
pre-defines base CRUD operations for you. Namely, it is Presenter:create
for POST method, Presenter:read
for GET, Presenter:update
for PUT and Presenter:delete
for DELETE. Then your router will look like this:
Note the second parameter, metadata. You can define only Presenter not action name. This is because the action name will be replaced by value from actionDictionary ([CrudRoute::POST => 'create', CrudRoute::GET => 'read', CrudRoute::PUT => 'update', CrudRoute::DELETE => 'delete']
) which is property of ResourceRoute
so even of CrudRoute
since it is its child. Also note that we don't have to set flags. Default flags are set to CrudRoute::CRUD
so the route will match all request methods.
Then you can simple define your CRUD resource presenter:
Note: every request method can be overridden if you specify X-HTTP-Method-Override
header in request or by adding query parameter __method
to URL.
Let there be relations
Relations are pretty common in RESTful services but how to deal with it in URL? Our goal is something like this GET /articles/94/comments[/5]
while ID in brackets might be optional. The route will be as follows:
Request parameters in action name
It's a quite long. Therefore, there is an option how to generalize it. Now it will look like this:
Much better but still quite long. Let's use CrudRoute
again:
This is the shortest way. It works because action dictionary in CrudRoute
is basically as follows.
Also have a look at few examples for this single route:
Of course you can add more then one parameter to action name and make even longer relations.
Note: if relation or any other parameter in action name does not exist, it will be ignored and name without the parameter will be used.
Also note: parameters in action name are NOT case-sensitive
Accessing input data
If you want to build REST API, you may also want to access query input data for all request methods (GET, POST, PUT, DELETE and HEAD). So the library defines input parser, which reads data and parse it to an array. Data are fetched from query string or from request body and parsed by IMapper
. First the library looks for request body. If it's not empty it checks Content-Type
header and determines correct mapper (e.g. for application/json
-> JsonMapper
etc.) Then, if request body is empty, try to get POST data and at the end even URL query data.
Good thing about it is that you don't care of request method. Nette Drahak REST API library will choose correct Input parser for you but it's still up to you, how to handle it. There is available InputIterator
so you can iterate through input in presenter or use it in your own input parser as iterator.
Input data validation
First rule of access to input data: never trust client! Really this is very important since it is key feature for security. So how to do it right? You may already know Nette Forms and its validation. Lets do the same in Restful! You can define validation rules for each input data field. To get field (exactly Drahak\Restful\Validation\IField
), just call field
method with field name in argument on Input
(in presenter: $this->input
). And then define rules (almost) like in Nette:
That's it! It is not exact the way like Nette but it's pretty similar. At least the base public interface.
Note: the validation method validateCreate
. This new lifecycle method validate<Action>()
will be processed for each action before the action method action<Action>()
. It's not required but it's good to use for defining some validation rules or validate data. In case if validation failed throws exception BadRequestException with code HTT/1.1 422 (UnproccessableEntity) that can be handled by error presenter.
Error presenter
The simplest but yet powerful way to provide readable error response for clients is to use $presenter->sendErrorResponse(Exception $e)
method. The simplest error presenter could look like as follows:
Clients can determine preferred format just like in normal API resource. Actually it only adds data from exception to resource and send it to output.
Security & authentication
Restful provides a few ways how to secure your resources:
BasicAuthentication
This is completely basic but yet powerful way how to secure you resources. It's based on standard Nette user's authentication (if user is not logged in then throws security exception which is provided to client) therefore it's good for trusted clients (such as own client-side application etc.) Since this is common Restful contains SecuredResourcePresenter
as a children of ResourcePresenter
which already handles BasicAuthentication
for you. See example:
Tip: Be careful using this authentication (and standard things such as user's Identity). Remember to keep REST API stateless. Being pragmatic, this is not a good approach but it's the simplest one.
SecuredAuthentication
When third-party clients are connected you have to find another way how to authenticate these requests. SecuredAuthentication
is more or less the answer. It's based on sending hashed data with private key. Since the data is already encrypted, it not depends on SSL. Authentication process is as follows:
Understanding authentication process
- Client: append request timestamp to request body.
- Client: hash all data with
hash_hmac
(sha256 algorithm) and with private key. Then append generated hash to request asX-HTTP-AUTH-TOKEN
header (by default). - Client: sends request to server.
- Server: accepts client's request and calculate hash in the same way as client (using abstract template class
AuthenticationProcess
) - Server: compares client's hash with hash that it generated in previous step.
- Server: also checks request timestamp and make difference. If it's bigger then 300 (5 minutes) throws exception. (this avoid something called Replay Attack)
- Server: catches any
SecurityException
that throwsAuthenticationProcess
and provides error response.
Default AuthenticationProcess
is NullAuthentication
so all requests are unsecured. You can use SecuredAuthentication
to secure your resources. To do so, just set this authentication process to AuthenticationContext
in restful.authentication
or $presenter->authentication
.
Never send private key!
Secure your resources with OAuth2
If you want to secure your API resource with OAuth2, you will need some OAuth2 provider. I've implemented OAuth2 provider bundle for Nette framework so you can use it with Restful. To do so just add dependency "drahak/oauth2": "dev-master"
to your composer and then use OAuth2Authentication
which is AuthenticationProcess
. If you wish to use any other OAuth2 provider, you can write your own AuthenticationProcess
.
Note: this is only Resource server so it handles access token authorization. To generate access token you'll need to create OAuth2 presenter (Resource owner and authorization server - see Drahak\OAuth2 documentation).
JSONP support
If you want to access your API resources by JavaScript on remote host, you can't make normal AJAX request on API. So JSONP is alternative how to do it. In JSONP request you load your API resource as a JavaScript using standard script
tag in HTML. API wraps JSON string to a callback function parameter. It's actually pretty simple but it needs special care. For example you can't access response headers or status code. You can wrap these headers and status code to all your resources but this is not good for normal API clients, which can access header information. The library allows you to add special query parameter jsonp
(name depends on your configuration, this is default value). If you access resource with ?jsonp=callback
API automatically determines JSONP mode and wraps all resources to following JavaScript:
Note : the function name. This is name from jsonp
query parameter. This string is "webalized" by Nette\Utils\Strings::webalize(jsonp, NULL, FALSE)
. If you set jsonpKey
to FALSE
or NULL
in configuration, you totally disable JSONP mode for all your API resources. Then you can trigger it manually. Just set IResource
$contentType
property to IResource::JSONP
.
Also note : if this option is enabled and client adds jsonp
parameter to query string, no matter what you set to $presenter->resource->contentType
it will produce JsonpResponse
.
Utilities that make life better
Filtering API requests is rut. That's why it's boring to do it all again. Restful provides RequestFilter
which parses the most common things for you. In ResourcePresenter
you can find RequestFilter
in $requestFilter
property.
Paginator
By adding offset
& limit
parameters to query string you can create standard Nette Paginator
. Your API resource then response with Link
header (where "last page" part of Link
and X-Total-Count
header are only provided if you set total items count to a paginator)
Fields list
In case you want to load just a part of a resource (e.g. it's expensive to load whole resource data), you should add fields
parameter to query params with list of desired fields (e.q. fields=user_id,name,email
). In RequestFilter
, you can get this list (array('user_id', 'name', 'email')
) by calling getFieldsList()
method.
Sort list
If you want to sort data provided by resource you will probably need properties according to which you sort it. To make it as easy as possible you can get it from sort
query parameter (such as sort=name,-created_at
) as array('name' => 'ASC', 'created_at' => 'DESC')
by calling RequestFilter
method getSortList()
So that's it. Enjoy and hope you like it!
All versions of restful with dependencies
nette/application Version ~3.0
nette/bootstrap Version ~3.0
nette/caching Version ~3.0
nette/deprecated Version ~3.0
nette/di Version ~3.0
nette/http Version ~3.0
nette/reflection Version ~2.0
nette/robot-loader Version ~3.0
nette/security Version ~3.0
nette/utils Version ~3.0