Most of the interface and output stayed the same. However, v2 is breaking backwards compatibility. The main reasons are:
- the jsonapi specification started to recommend CamelCase in their v1.1, thus all method names changed
- php7 marks
resource
a reserved keyword, thus the main class name changed (php5 is still supported) - the current implementation offers too little flexibility, in v2 the output changed
The main feature v2 introduces is two different ways of building the json:
- a human-friendly way (already in v1): a way to build the json without needing to understand the specification
- a specification-based way (new in v2): to easier define the small details of each part of the output
See the README.md and the examples for more information.
Note: v2.0 of the library doesn't yet support v1.1 of the specification.
As v2 uses completely new files the files for v1 could be left intact. This means a composer update can be done to v2 without any impact. A migration to the new code can be made step-by-step.
However, the old code will be removed in a future minor release of v2, and will not be seen as a BC break.
Names of all starter classes to build the output (e.g. collection
) have 'Document' appended.
Old:
$document = new resource();
$document = new collection();
$document = new errors();
New:
$document = new ResourceDocument();
$document = new CollectionDocument();
$document = new ErrorsDocument();
All methods changed to using camelCase.
Old:
$document->add_link();
$document->add_meta();
$document->send_response();
New:
$document->addLink();
$document->addMeta();
$document->sendResponse();
The methods to add the primary property to documents or objects now use the shorter add()
vs addX()
.
Old:
$resourceDocument->add_data();
$errorsDocument->add_error();
New:
$resourceDocument->add();
$errorsDocument->add();
Adding an array of key-value pairs changes from ->fill_x()
to ::fromArray()
.
And thus is only possible when starting an object, not to append on it.
Old:
$document = new resource($type, $id);
$document->fill_data($array);
$document->add_data($key, $value);
New:
$document = ResourceDocument::fromArray($array, $type, $id);
$document->add($key, $value);
What is thus not possible anymore is to first do add_data()
followed by fill_data()
.
If you really need this, the workaround is to foreach over the array and call add()
.
Methods now use a single $options
argument, instead of multiple loose arguments, to adjust logic.
Note this is not used for changing content, only for changing logic.
Old:
$document->add_relation($key, $relatedResource, $skip_include=true);
$document->get_json($encode_options=JSON_PRETTY_PRINT);
$document->send_response($content_type='application/json', $encode_options=JSON_PRETTY_PRINT, $response='{"data":[]}', $jsonp_callback='callback');
New:
$document->addRelationship($key, $relatedResource, $links=[], $meta=[], $options=['skipIncluding' => true]);
$document->toJson($options['encodeOptions' => JSON_PRETTY_PRINT]);
$document->sendResponse($options[
'contentType' => 'application/json',
'encodeOptions' => JSON_PRETTY_PRINT,
'json' => '{"data":[]}',
'jsonpCallback' => 'callback'
]);
Some specific methods changed name.
Old:
$document->add_relation('foo', $relatedResource);
$document->get_array();
$document->get_json();
New:
$document->addRelationship('foo', $relatedResource); // note relation*ship* postfix
$document->toArray();
$document->toJson();
Transforming an exception to jsonapi output changed.
Only $exception->getCode()
is used outside meta, $exception->getMessage()
(and everything else) is now placed inside meta.
Also, this is only done when $options['exceptionExposeDetails']
is passed, previously $debug
mode needed to be turned on.
Old
$exception = new \Exception($message='user not found', $code=404);
$document = new errors($exception);
$document->send_response();
{
"errors": [
{
"status": "404 Not Found",
"code": "user not found",
"meta": {
"file": "UPGRADE_1_TO_2.md",
"line": 177
}
}
]
}
New:
$exception = new \Exception($message='user not found', $code=404);
$document = ErrorsDocument::fromException($exception);
$document->sendResponse();
{
"errors": [
{
"status": "404",
"code": "404",
"title": "Exception",
"meta": {
"message": "user not found",
"file": "UPGRADE_1_TO_2.md",
"line": 177
}
}
]
}
There's multiple changes here.
Note: these levels can now also be used for adding meta.
Old:
$document->add_link('foo', 'https://jsonapi.org', $meta, $level=resource::LINK_LEVEL_DATA);
$document->add_link('foo', 'https://jsonapi.org', $meta, $level=resource::LINK_LEVEL_ROOT);
New:
$document->addLink('foo', 'https://jsonapi.org', $meta, $level=Document::LEVEL_RESOURCE);
$document->addLink('foo', 'https://jsonapi.org', $meta, $level=Document::LEVEL_ROOT);
Old:
$jsonapi->add_link('foo', 'https://jsonapi.org', $meta); // defaulted to LINK_LEVEL_DATA
$jsonapi->add_link('foo', 'https://jsonapi.org', $meta, $level=resource::LINK_LEVEL_ROOT); // set to LINK_LEVEL_ROOT explicitly
New:
$jsonapi->addLink('foo', 'https://jsonapi.org', $meta, $level=Document::LEVEL_RESOURCE); // set to LEVEL_RESOURCE explicitly
$jsonapi->addLink('foo', 'https://jsonapi.org', $meta); // defaults to LEVEL_ROOT
The self
link is set at LEVEL_ROOT
for collections, and at LEVEL_RESOURCE
for resources, not both anymore
Old:
$resourceDocument->set_self_link('/example'); // defaulted to LINK_LEVEL_BOTH (root & resource)
$collectionDocument->set_self_link('/example'); // defaulted to LINK_LEVEL_ROOT
New:
$resourceDocument->setSelfLink('/example'); // defaults to LEVEL_RESOURCE only
$collectionDocument->setSelfLink('/example'); // defaults to LEVEL_ROOT still
The \jsonapi\exception
class to generate error documents is removed.
Old:
$jsonapiException = new jsonapi\exception($message, $code, $previous, $friendly_message, $about_link);
$jsonapiException->send_response();
New:
$exception = new \Exception($message, $code, $previous);
$errorObject = ErrorObject::fromException($exception);
$errorObject->setHumanExplanation($genericTitle, $specificDetails=null, $specificAboutLink); // replaces $friendly_message and $about_link
$document = new ErrorsDocument($errorObject);
$document->sendResponse();
The resource::LINK_LEVEL_BOTH
is removed.
Old:
$document->add_link('foo', 'https://jsonapi.org', $meta, $level=resource::LINK_LEVEL_BOTH);
New:
$document->addLink('foo', 'https://jsonapi.org', $meta, $level=Document::LEVEL_RESOURCE);
$document->addLink('foo', 'https://jsonapi.org', $meta, $level=Document::LEVEL_ROOT);
Adding data via fill_data()
and other fill_*()
methods is removed.
See Adding multiple key-value pairs at construction only.
Debug mode is removed as an all-or-nothing setting, and replaced by specific options. See Change logic via single options argument and Exception handling.
It was automatically guessed based on the display_errors
directive, and managing multiple things:
- encode json with
JSON_PRETTY_PRINT
// in v2, use one of: $document->sendResponse($options=['prettyPrint' => true]); $document->toJson($options=['prettyPrint' => true]);
- send
application/json
instead ofapplication/vnd.api+json
// in v2, use: $document->sendResponse($options=['contentType' => Document::CONTENT_TYPE_DEBUG]);
- output
code
from error objects, and exception detailsfile
,line
,trace
(hidden if debug was false)// in v2, use one of: $errorsDocument->addException($exception, $options=['exceptionExposeDetails' => true]); ErrorsDocument::fromException($exception, $options=['exceptionExposeDetails' => true]); ErrorObject::fromException($exception, $options=['exceptionExposeDetails' => true]);
The self
link at root, the self
link at the resource, and the self
and related
links for relationships are not automatically added anymore.
When actually supported, add them explicitly.
Old:
$document = new resource('user', 42);
$document->add_relation('foo', new resource('user', 24));
{
"links": {
"self": "/UPGRADE_1_TO_2.md"
},
"data": {
"type": "user",
"id": 42,
"relationships": {
"foo": {
"data": {
"type": "user",
"id": 24
},
"links": {
"self": "/UPGRADE_1_TO_2.md/relationships/foo",
"related": "/UPGRADE_1_TO_2.md/foo"
}
}
},
"links": {
"self": "/UPGRADE_1_TO_2.md"
}
}
}
New, same code, without links:
$document = new ResourceDocument('user', 42);
$document->addRelationship('foo', new ResourceObject('user', 24));
{
"data": {
"type": "user",
"id": "42",
"relationships": {
"foo": {
"data": {
"type": "user",
"id": "24"
}
}
}
}
}
New, with links:
$document = new ResourceDocument('user', 42);
$document->setSelfLink('https://example.org/user/42'); // default at LEVEL_RESOURCE only
$document->addLink('self', 'https://example.org/user/42', $meta=[], Document::LEVEL_ROOT);
$relationshipLinks = [
'self' => 'https://example.org/user/42/relationships/foo',
'related' => 'https://example.org/user/42/foo',
];
$document->addRelationship('foo', new ResourceObject('user', 24), $relationshipLinks);
{
"links": {
"self": "https://example.org/user/42"
},
"data": {
"type": "user",
"id": "42",
"relationships": {
"foo": {
"links": {
"self": "https://example.org/user/42/relationships/foo",
"related": "https://example.org/user/42/foo"
},
"data": {
"type": "user",
"id": "24"
}
}
},
"links": {
"self": "https://example.org/user/42"
}
}
}
Specification-based methods are available to adjust each part of the output in the small details.
In general there's two types you can use: Documents and Objects.
Documents are what v1 also used, a class to build the output with.
Next to the human-friendly methods (like add()
), there's methods using terms of the specification (like setAttributesObject()
).
Objects are used for these new methods. There's an Object for each part the specification describes.
Mostly you'll use the human-friendly methods, as they are usually easier and need less code. But the specification-based ones are needed to adjust some parts and make you understand more.
See the examples/resource_human_api and examples/resource_spec_api.
Every document by defaults get a jsonapi object in the output:
{
"jsonapi": {
"version": "1.0"
}
}
This helps discovery and lets clients know which version of the specification to use.
The object can be changed:
$jsonapiObject = new JsonapiObject();
$jsonapiObject->setVersion(Document::JSONAPI_VERSION_1_1);
$jsonapiObject->addMeta('foo', 'bar');
$document->setJsonapiObject($jsonapiObject);
{
"jsonapi": {
"version": "1.1",
"meta": {
"foo": "bar"
}
}
}
Or removed:
$document->unsetJsonapiObject();
A new level Document::LEVEL_JSONAPI
is added for when adding meta.
$document = new ResourceDocument('user', 42);
$document->addMeta('foo', 'root', $level=Document::LEVEL_ROOT);
$document->addMeta('foo', 'resource', $level=Document::LEVEL_RESOURCE);
$document->addMeta('foo', 'jsonapi', $level=Document::LEVEL_JSONAPI);
{
"jsonapi": {
"version": "1.0",
"meta": {
"foo": "jsonapi"
}
},
"meta": {
"foo": "root"
},
"data": {
"type": "user",
"id": "42",
"meta": {
"foo": "resource"
}
}
}
Tests are added to:
- exception are thrown when using the library incorrectly
- options for changing logic are applied correctly
- make sure the output is how it should be
The code is tested against php7. But will continue to support php5.
Old | New |
---|---|
base | n/a |
base::$debug; |
See Debug mode |
base::$appRoot; |
Use $options['exceptionStripBasePath'=>'...'] on ErrorObject::fromException() or ErrorsDocument::fromException() or $errorsDocument = new ErrorsDocument(); $errorsDocument->addException() |
collection | CollectionDocument |
$collection = new collection(); |
$collectionDocument = new CollectionDocument(); |
$collection->add_resource(); |
$collectionDocument->addResource(); |
$collection->fill_collection(); |
$collectionDocument = CollectionDocument::fromResources(); |
error | ErrorObject |
$error = new error(); |
$errorObject = new ErrorObject(); Same arguments, same order, skipping the third argument. |
$error->set_http_status(); |
$errorObject->setHttpStatusCode(); |
$error->set_error_message(); |
$errorObject->setApplicationCode(); |
$error->set_friendly_message(); |
$errorObject->setHumanTitle(); |
$error->set_friendly_detail(); |
$errorObject->setHumanDetails(); |
$error->blame_post_body(); |
$errorObject->blameJsonPointer(); Or $errorObject->blamePostData(); |
$error->blame_get_parameter(); |
$errorObject->blameQueryParameter(); |
$error->set_about_link(); |
$errorObject->setAboutLink(); |
$error->set_identifier(); |
$errorObject->setUniqueIdentifier(); |
$error->add_meta(); |
$errorObject->addMeta(); |
$error->fill_meta(); |
$errorObject->setMetaObject(MetaObject::fromArray()); |
errors | ErrorsDocument |
$errors = new errors(); |
$errorsDocument = new ErrorsDocument(); $errorsDocument->add(); Same arguments, same order, skipping the third argument |
$errors->send_response(); |
$errorsDocument->sendResponse(); See Change logic via single options argument. |
$errors->set_http_status(); |
$errorsDocument->setHttpStatusCode(); |
$errors->add_error(); |
$errorsDocument->add(); Same arguments, same order, skipping the third argument. |
$errors->fill_errors(); |
Removed. |
$errors->add_exception(); |
$errorsDocument->addException(); |
exception | Removed, see Removed - \jsonapi\exception class. |
resource | ResourceDocument |
resource::RELATION_TO_MANY |
RelationshipObject::TO_MANY; |
resource::RELATION_TO_ONE |
RelationshipObject::TO_ONE; |
resource::RELATION_LINKS_ resource::LINK_LEVEL_ resource::SELF_LINK_ resource::$self_link_data_level resource::$relation_links |
See Links are not auto generated anymore. |
$resource = new resource(); |
$resourceDocument = new ResourceDocument(); |
$resource->add_data(); |
$resourceDocument->add(); |
$resource->fill_data(); |
$resourceDocument = ResourceDocument::fromArray(); |
$resource->add_relation(); |
$resourceDocument->addRelationship(); See Change logic via single options argument. |
$resource->fill_relations(); |
No direct replacement. |
$resource->add_link(); |
$resourceDocument->addLink(); |
$resource->set_self_link(); |
$resourceDocument->setSelfLink(); |
$resource->add_self_link_meta(); |
$resourceDocument->setSelfLink(); Also see Links are not auto generated anymore. |
$resource->add_meta(); |
$resourceDocument->addMeta(); |
$resource->fill_meta(); |
$resourceDocument->setMetaObject(MetaObject::fromArray()); |
response | Document, MetaDocument or ResourceDocument |
response::STATUS_* |
Use own supplied hard-coded http status codes. |
response::CONTENT_TYPE_OFFICIAL; |
Document::CONTENT_TYPE_OFFICIAL; |
response::CONTENT_TYPE_DEBUG; |
Document::CONTENT_TYPE_DEBUG; |
response::CONTENT_TYPE_JSONP |
Document::CONTENT_TYPE_JSONP; |
response::ENCODE_DEFAULT; |
Use $options['encodeOptions'=>JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE] on sendResponse() or toJson() |
response::ENCODE_DEBUG; |
Use $options['encodeOptions'=>JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT] on sendResponse() or toJson() |
response::JSONP_CALLBACK_DEFAULT |
Use $options['jsonpCallback'=>'...'] on sendResponse() or toJson() |
response::$send_status_headers |
Removed, instead don't call sendResponse() |
$response = new response(); |
$metaDocument = new MetaDocument(); |
$response->__toString(); |
$metaDocument->toJson(); |
$response->get_json(); |
$metaDocument->toJson(); See Change logic via single options argument. |
$response->send_response(); |
$metaDocument->sendResponse(); See Change logic via single options argument. |
$response->set_http_status(); |
$metaDocument->setHttpStatusCode(); |
$response->set_redirect_location(); |
Removed, set redirect headers manually. |
$response->add_link(); |
$metaDocument->addLink(); |
$response->fill_links(); |
$metaDocument->setLinksObject(LinksObject::fromArray()); |
$response->set_self_link(); |
$resourceDocument->setSelfLink(); |
$response->add_self_link_meta(); |
$resourceDocument->setSelfLink(); Also see Links are not auto generated anymore. |
$response->add_meta(); |
$metaDocument->addMeta(); |
$response->fill_meta(); |
$metaDocument = MetaDocument::fromArray(); |