Skip to content

Commit

Permalink
Improve resource inclusion, encoding and error handling
Browse files Browse the repository at this point in the history
- Streamline show URLs logic. Having related controller data and self controller data requirement in schema are obsolete.
- Streamline include resource logic. INCLUDE key and defaultParseDepth are obsolete. Include paths could be set in schema and encoder can override them with EncodingParametersInterface.
- Add support for meta in linkage objects
- Add support for rendering JSON API Errors in exception handler
  • Loading branch information
neomerx committed May 18, 2015
1 parent 433c03c commit 43801b1
Show file tree
Hide file tree
Showing 37 changed files with 488 additions and 587 deletions.
56 changes: 32 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@

A good API is one of most effective ways to improve the experience for your clients. Standardized approaches for data formats and communication protocols increase productivity and make integration between applications smooth.

This framework agnostic package fully implements [JSON API](http://jsonapi.org/) specification and helps you to focus on core application functionality rather than on protocol implementation. It supports document structure, errors and data fetching as described in [JSON API Format](http://jsonapi.org/format/). As it is designed to stay framework agnostic for practical usage it requires framework integration. [Limoncello](https://github.com/neomerx/limoncello) is an example of integration with Symfony based projects.
This framework agnostic package fully implements [JSON API](http://jsonapi.org/) specification and helps focusing on core application functionality rather than on protocol implementation. It supports document structure, errors and data fetching as described in [JSON API Format](http://jsonapi.org/format/). As it is designed to stay framework agnostic for practical usage it requires framework integration. [Limoncello](https://github.com/neomerx/limoncello) is an example of integration with Symfony based projects.

If you are looking for quick start application consider [Limoncello collins](https://github.com/neomerx/limoncello-collins) which is a pre-configured Laravel-based quick start application.
If you are looking for quick start application consider [Limoncello Collins](https://github.com/neomerx/limoncello-collins) which is a pre-configured Laravel-based quick start application.

Encoding fully support
Encoding fully support specification. In particular

* Resource attributes and complex attributes
* Compound documents with included resources
Expand All @@ -24,7 +24,7 @@ Encoding fully support
* Pagination links
* Errors

The package covers all the complexity of parsing and checking request parameters and headers. For instance it helps to correctly respond with ```Unsupported Media Type``` (HTTP code 415) and ```Not Acceptable``` (HTTP code 406) to invalid requests. You don't need to manually validate all input parameters on every request. You can configure what parameters are supported by your services and this package will check incoming requests automatically. It greatly simplifies API development. All parameters from the specification are supported
The package covers all the complexity of parsing and checking HTTP request parameters and headers. For instance it helps to correctly respond with ```Unsupported Media Type``` (HTTP code 415) and ```Not Acceptable``` (HTTP code 406) to invalid requests. You don't need to manually validate all input parameters on every request. You can configure what parameters are supported by your services and this package will check incoming requests automatically. It greatly simplifies API development. All parameters from the specification are supported

* Inclusion of related resources
* Sparse fields
Expand All @@ -43,7 +43,7 @@ Thank you for your support :star:.
Via Composer

```
$ composer require neomerx/json-api ~0.2
$ composer require neomerx/json-api ~0.3
```

## Usage
Expand Down Expand Up @@ -294,12 +294,33 @@ class PostSchema extends SchemaProvider

Apart from ```self::DATA``` the following keys are supported

* ```self::INCLUDED``` (bool) - if resource(s) from this link should be added to ```included``` section.
* ```self::SHOW_META``` (bool) - if resource meta information should be added to output link description.
* ```self::SHOW_LINKAGE``` (bool) - if linkage information should be added to output link description.
* ```self::SHOW_SELF``` (bool) - if link ```self``` URL should be added to output link description. Setting this option to ```true``` requires ```self::SELF_CONTROLLER``` (```mixed```) to be set as well.
* ```self::SHOW_RELATED``` (bool) - if link ```self``` URL should be added to output link description. Setting this option to ```true``` requires ```self::RELATED_CONTROLLER``` (```mixed```) to be set as well.
* ```self::SHOW_AS_REF``` (bool) - if this key is set to ```true``` the link will be rendered as a reference.
* ```self::SHOW_AS_REF``` (bool) - if this key is set to ```true``` the link will be rendered as a reference. Default ```false```.
* ```self::SHOW_META``` (bool) - if resource meta information should be added to output link description. Default ```false```.
* ```self::SHOW_LINKAGE``` (bool) - if linkage information should be added to output link description. Default ```true```.
* ```self::SHOW_SELF``` (bool) - if link ```self``` URL should be added to output link description. Default ```false```.
* ```self::SHOW_RELATED``` (bool) - if link ```related``` URL should be added to output link description. Default ```false```.

### Include linked resources

By default linked resources will not be included to ```included``` output section. However you can change this behaviour by defining 'include paths'. Nested links should be separated by a dot ('.'). For instance

```php
class PostSchema extends SchemaProvider
{
...
public function getIncludePaths()
{
return [
'posts',
'posts.author',
'posts.comments',
];
}
...
}
```

If you specify ```EncodingParametersInterface``` with 'included paths' set to ```Encoder::encode``` method it will override include paths in the ```Schema```.

### Provide resource's meta information

Expand Down Expand Up @@ -348,19 +369,6 @@ class YourSchema extends SchemaProvider
}
```

### Limit depth of resource inclusion

By default the inclusion depth is unlimited thus all the data you pass to encoder will be put to json. You can limit the parsing depth for resource and its links by setting ```$defaultParseDepth```.

```php
class YourSchema extends SchemaProvider
{
...
protected $defaultParseDepth = 1;
...
}
```

### Show top level links and meta information

```php
Expand Down
4 changes: 2 additions & 2 deletions sample/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ If your system has debug assertions enabled it is recommended to turn them off.

|Debug asserts mode |Command |Execution time|
|---------------------|--------------------------------------------------|--------------|
|Enabled |```$ php -d assert.active=1 sample.php -t=10000```|16.208s |
|Disabled |```$ php -d assert.active=0 sample.php -t=10000```|3.990s |
|Enabled |```$ php -d assert.active=1 sample.php -t=10000```|12.877s |
|Disabled |```$ php -d assert.active=0 sample.php -t=10000```|6.758s |

The following command could be used for performance profiling with [blackfire.io](https://blackfire.io/)

Expand Down
2 changes: 1 addition & 1 deletion sample/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@
},
"minimum-stability": "dev",
"require": {
"neomerx/json-api": "0.2.2"
"neomerx/json-api": "0.3.0"
}
}
2 changes: 1 addition & 1 deletion sample/schemas/CommentSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public function getLinks($comment)
{
/** @var Comment $comment */
return [
'author' => [self::DATA => $comment->author, self::INCLUDED => true],
'author' => [self::DATA => $comment->author],
];
}
}
4 changes: 2 additions & 2 deletions sample/schemas/PostSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ public function getLinks($post)
{
/** @var Post $post */
return [
'author' => [self::DATA => $post->author, self::INCLUDED => true],
'comments' => [self::DATA => $post->comments, self::INCLUDED => true],
'author' => [self::DATA => $post->author],
'comments' => [self::DATA => $post->comments],
];
}
}
11 changes: 10 additions & 1 deletion sample/schemas/SiteSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,16 @@ public function getLinks($site)
{
/** @var Site $site */
return [
'posts' => [self::DATA => $site->posts, self::INCLUDED => true],
'posts' => [self::DATA => $site->posts],
];
}

public function getIncludePaths()
{
return [
'posts',
'posts.author',
'posts.comments',
];
}
}
6 changes: 3 additions & 3 deletions src/Contracts/Encoder/Handlers/HandlerFactoryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ interface HandlerFactoryInterface
/**
* Create parser reply interpreter.
*
* @param DocumentInterface $document
* @param EncodingParametersInterface|null $parameters
* @param DocumentInterface $document
* @param EncodingParametersInterface $parameters
*
* @return ReplyInterpreterInterface
*/
public function createReplyInterpreter(DocumentInterface $document, EncodingParametersInterface $parameters = null);
public function createReplyInterpreter(DocumentInterface $document, EncodingParametersInterface $parameters);
}
8 changes: 0 additions & 8 deletions src/Contracts/Encoder/Stack/StackFrameReadOnlyInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,4 @@ public function getLevel();
* @return string|null
*/
public function getPath();

/**
* If all resources on frame path have 'should be included' flag set to true.
* For root resource (level 1) it returns null as it does not have a link object.
*
* @return bool|null
*/
public function isPathIncluded();
}
11 changes: 10 additions & 1 deletion src/Contracts/Exceptions/RenderContainerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,16 @@ public function registerRender($exceptionClass, Closure $render);
*
* @return void
*/
public function registerMapping(array $exceptionMapping);
public function registerHttpCodeMapping(array $exceptionMapping);

/**
* Register JSON API Error object renders mapping for exceptions.
*
* @param array $exceptionMapping
*
* @return void
*/
public function registerJsonApiErrorMapping(array $exceptionMapping);

/**
* Get registered or default render for exception.
Expand Down
21 changes: 0 additions & 21 deletions src/Contracts/Schema/LinkObjectInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,6 @@ public function isShowLinkage();
*/
public function getRelatedSubUrl();

/**
* If link object should be included.
*
* @return bool
*/
public function isShouldBeIncluded();

/**
* If 'meta' should be shown.
*
Expand All @@ -98,20 +91,6 @@ public function isShowPagination();
*/
public function getLinkedData();

/**
* Get 'self' controller data.
*
* @return mixed
*/
public function getSelfControllerData();

/**
* Get 'related' controller data.
*
* @return mixed
*/
public function getRelatedControllerData();

/**
* Get pagination information.
*
Expand Down
14 changes: 7 additions & 7 deletions src/Contracts/Schema/ResourceObjectInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,6 @@ public function getMeta();
*/
public function getSelfUrl();

/**
* Get 'self' controller data.
*
* @return mixed
*/
public function getSelfControllerData();

/**
* If 'self' endpoint URL should be shown for resource in 'data' section.
*
Expand Down Expand Up @@ -91,6 +84,13 @@ public function isShowSelfInIncluded();
*/
public function isShowMetaInIncluded();

/**
* If 'meta' should be shown in linkages.
*
* @return bool
*/
public function isShowMetaInLinkage();

/**
* If resources links should be shown for included resources.
*
Expand Down
12 changes: 3 additions & 9 deletions src/Contracts/Schema/SchemaFactoryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ public function createContainer(array $providers = []);
* @param array $attributes
* @param mixed $meta
* @param string $selfUrl
* @param mixed $selfControllerData
* @param bool $isShowSelf
* @param bool $isShowMeta
* @param bool $isShowSelfInIncluded
* @param bool $isShowLinksInIncluded
* @param bool $isShowMetaInIncluded
* @param bool $isShowMetaInLinkage
*
* @return ResourceObjectInterface
*/
Expand All @@ -55,12 +55,12 @@ public function createResourceObject(
array $attributes,
$meta,
$selfUrl,
$selfControllerData,
$isShowSelf,
$isShowMeta,
$isShowSelfInIncluded,
$isShowLinksInIncluded,
$isShowMetaInIncluded
$isShowMetaInIncluded,
$isShowMetaInLinkage
);

/**
Expand All @@ -76,9 +76,6 @@ public function createResourceObject(
* @param bool $isShowLinkage
* @param bool $isShowMeta
* @param bool $isShowPagination
* @param bool $isIncluded
* @param mixed $selfControllerData
* @param mixed $relatedControllerData
* @param PaginationLinksInterface|null $pagination
*
* @return LinkObjectInterface
Expand All @@ -94,9 +91,6 @@ public function createLinkObject(
$isShowLinkage,
$isShowMeta,
$isShowPagination,
$isIncluded,
$selfControllerData,
$relatedControllerData,
$pagination
);

Expand Down
28 changes: 24 additions & 4 deletions src/Contracts/Schema/SchemaProviderInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,20 @@ public function getLinkObjectIterator($resource);
*/
public function getMeta($resource);

/**
* If 'self' endpoint URL.
*
* @return bool
*/
public function isShowSelf();

/**
* If 'meta' should be shown for resource.
*
* @return bool
*/
public function isShowMeta();

/**
* If 'self' endpoint URL should be shown for included resources.
*
Expand All @@ -97,12 +111,11 @@ public function isShowLinksInIncluded();
public function isShowMetaInIncluded();

/**
* Get default depth for object inclusion to 'include' section.
* If any other setting is not available this value will be used as a limiter.
* If 'meta' should be shown in linkages.
*
* @return int
* @return bool
*/
public function getDefaultParseDepth();
public function isShowMetaInLinkage();

/**
* Create resource object.
Expand All @@ -114,4 +127,11 @@ public function getDefaultParseDepth();
* @return ResourceObjectInterface
*/
public function createResourceObject($resource, $isOriginallyArrayed, array $attributeKeysFilter = null);

/**
* Get schema default include paths.
*
* @return string[]
*/
public function getIncludePaths();
}
6 changes: 5 additions & 1 deletion src/Document/Presenters/ElementPresenter.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,14 @@ public function concatUrls($url, $subUrl)
*/
private function getLinkageRepresentation(ResourceObjectInterface $resource)
{
return [
$representation = [
Document::KEYWORD_TYPE => $resource->getType(),
Document::KEYWORD_ID => $resource->getId(),
];
if ($resource->isShowMetaInLinkage() === true) {
$representation[Document::KEYWORD_META] = $resource->getMeta();
}
return $representation;
}

/**
Expand Down
Loading

0 comments on commit 43801b1

Please sign in to comment.