nilportugues / php-json-api Goto Github PK
View Code? Open in Web Editor NEWJSON API transformer outputting valid (PSR-7) API Responses.
Home Page: http://nilportugues.com
License: MIT License
JSON API transformer outputting valid (PSR-7) API Responses.
Home Page: http://nilportugues.com
License: MIT License
Allow specifying all mappings as an array and create the mapping variable injected to the transformer.
At
, each request is validated to ensure it has anattributes
member. However, the JSON API spec says resource objects MAY contain an attributes
member. There are cases where you might want to leave it out of a request, as when you don't want to modify any attributes but do have meta properties to PATCH.Support "relationships" in resource creation like shown here: http://jsonapi.org/format/#crud-creating
Get from "included" objects the relationship and append it to its parent.
In the provided example, comments from "included" should be in post's relationship.
This requires all classes to implement or have an add relationship method to construct the URI to the resource.
Actually only JSONAPI and HALJSON serializer are meant to support these, but JSON could support it too by adding a meta
attribute holding these.
$serializer->setSelfUrl('http://example.com/posts/9');
$serializer->setNextUrl('http://example.com/posts/10');
$serializer->addMeta(
'author',
[
['name' => 'Nil Portugués Calderó', 'email' => '[email protected]']
]
);
Output filtering is required to be done before transformation, but right after the key underscoring and the key aliasing.
This will be used when a URL contains ?filter[value]=key1,key2
Content-Type: application/vnd.api+json; supported-ext="bulk"
in src/Server/Data/DataObject.php, line 198
This
errorBag
local variable is declared but never used. You should remove it.
$mapping->getProperties()
);
foreach (array_keys($relationshipData[JsonApiTransformer::ATTRIBUTES_KEY]) as $property) {
if (false === in_array($property, $properties, true)) {
$errorBag[] = new InvalidAttributeError($property, $relationshipData[JsonApiTransformer::TYPE_KEY]);
}
}
}
}
}
Posted from SensioLabsInsight
While i originally decided to remove it as it is already available as in the standard
After some discussing in nilportugues/laravel5-jsonapi#75 (comment) users asked for to be included as standard says nothing about this, which is true.
Undefined index: XXX in /vendor/nilportugues/json-api/src/Helpers/DataIncludedHelper.php on line 77
Just as it's already allowed for the JSONAPI implementation
Pass the name of the attributes to hide.
Hiding attributes can make relationships and includes not to show up as data hidden will be not parsed or transformed.
in src/Server/Query/QueryObject.php, line 120
This
errorBag
local variable is declared but never used. You should remove it.
}
if (is_array($data)) {
foreach ($data as $subResource) {
if (null == $transformer->getMappingByAlias($subResource)) {
$errorBag[] = new InvalidParameterError($subResource, strtolower($paramName));
}
}
}
}
}
Posted from SensioLabsInsight
✅ If a POST request did not include a Client-Generated ID and the requested resource has been created successfully, the server MUST return a 201 Created status code.
🔴 The response SHOULD include a Location header identifying the location of the newly created resource.
🔴 The response MUST also include a document that contains the primary resource created.
🔴 If the resource object returned by the response contains a self key in its links member and a Location header is provided, the value of the self member MUST match the value of the Location header.
HTTP/1.1 201 Created
Location: http://example.com/photos/550e8400-e29b-41d4-a716-446655440000
Content-Type: application/vnd.api+json
{
"data": {
"type": "photos",
"id": "550e8400-e29b-41d4-a716-446655440000",
"attributes": {
"title": "Ember Hamster",
"src": "http://example.com/images/productivity.png"
},
"links": {
"self": "http://example.com/photos/550e8400-e29b-41d4-a716-446655440000"
}
}
}
Rename should be used to change the type key to the provided alias.
According to the JSON recommendation (http://jsonapi.org/recommendations/#naming) the preferred naming convention is to use hyphens to separate words in keys, eg 'modified-date'. Current implementation of the library has a dependency on nilportugues/php-api-transformer which converts camelCase words to underscore-separated words, eg: 'modifiedDate' to 'modified_date', which leaves no way to conform to the recommendation. It would be great to add an option that allows to choose which transformation logic is applied to the key names.
I have domain model with uuid
field and want use it as id
value for API mapping.
I put uuid
to getIdProperties
, it is work fine for set id and links values in json.
But I see uuid
in attributes:
Failed asserting that '{"data":{"type":"some_model","id":"foo-bar","attributes":{"name":"foo","uuid":"foo-bar"},"links":{"self":{"href":"/api/v1/some-models/foo-bar"}}},"links":{"self":{"href":"/api/v1/some-models/foo-bar"}},"jsonapi":{"version":"1.0"}}' matches JSON string "{
"data": {
"type": "some_model",
"id": "foo-bar",
"attributes": {
"name": "foo"
},
"links": {
"self": {
"href": "/api/v1/some-models/foo-bar"
}
}
},
"links": {
"self": {
"href": "/api/v1/some-models/foo-bar"
}
},
"jsonapi": {
"version": "1.0"
}
}".
--- Expected
+++ Actual
@@ @@
"type": "some_model",
"id": "foo-bar",
"attributes": {
- "name": "foo"
+ "name": "foo",
+ "uuid": "foo-bar"
},
"links": {
"self": {
I try hide this property and use aliases, but I could not succeed with my case.
I create repo with example:
https://github.com/samizdam/jsonapi-example/blob/master/tests/Samizdam/JsonApiExampleTest/ModelWithUuidMappingTest.php
I see this library supports doctrine entities as input to the serialiser.
https://github.com/nilportugues/php-json-api/blob/aa305a4ea7a9aef0be3cf243c1e2cf3c9efb3411/tests/Integrations/Doctrine/DoctrineTest.php
That example works without relationships. It seems I get into an infinite loop when I have two entities referencing each other.
identity has many preferences.
So either I am doing something wrong, perhaps I should not fetch eager or something. Or this is not possible with this library or I might have found a bug...
https://gist.github.com/basz/898f6981ac12a6a43c3edc19d607a29c
I have pinned it down to the serialiser::serializeData method in the serializer.
Hard title, easy to explain.
Given a mapping User
, with name user
as the type in the response, and a url template being /user/{user}/edit
... mapping to the id field (that being a class property named id
or user_id
) will fail.
Yet, it is possible to guess that is the type is user, and user
is in the url, the value should be the id
's, as we are following a convention.
This should be done as a second pass, after applying the id fields for the URL generation and getting the same result and before disregarding the URL.
Some parameters could:
If I had the following validation rule
protected $rules = [
'password' => 'required|valid_password|min:8'
];
And if I wished to hide that field from the response
protected $hidden = ['password'];
My password setter is:
public function setPasswordAttribute($value)
{
$validator = \Validator::make(['password'=>$value], $this->getRules(), $this->getMessages());
if ($validator->fails()) {
$this->attributes['password'] = $value;
return $this;
}
$this->attributes['password'] = password_hash($value, PASSWORD_BCRYPT);
return $this;
}
Then when testing this functionality with the following
$user = new User();
$user->password = 'xxx'
$user->isValid();
dd($user->getErrors());
I get the following error
Illuminate\Support\MessageBag {#328
#messages: array:1 [
"password" => array:1 [
0 => "The password field is required."
]
]
#format: ":message"
}
If I comment out the
protected $hidden = ['password'];
Everything works as expected
:-)
Change public name of a key or keys.
Looks like I missed forcing them to the under_score format.
Currently travelling but will give proper example when back home on PC.
Basically, post with many comments is ok but post with many comments each with many replies fails.
Remove the $serializer->setApiVersion('1.0')
method. Hard-code the output on the serializer, as there's no other possible value.
https://github.com/nilportugues/php-json-api/blob/master/src/Server/Data/DataObject.php#L51
While testing some stuff out in the Laravel wrapper, I realized that you can trigger an exception here by setting the type to text
instead of a JSON request. The data won't be filled out right, and the assert fails. Unfortunately, this line just eats the assertion, and happily lets it crash later.
A generic abstraction, cleaner code.
Reason: check all fields because URLs may be constructed with several ids not being part of the class's primary id values, which be considered attributes, yet necessary for the URL generation.
To be 💯 JSONAPI compilant this should be implemented.
http://jsonapi.org/format/#document-member-names-reserved-characters
plus:
Additionally, the following characters are allowed in member names,
except as the first or last character:
U+002D HYPHEN-MINUS, "-"
U+005F LOW LINE, "_"
U+0020 SPACE, " " (not recommended, not URL safe)
Given two DTO's (Identity and Preference) where Identity has a hidden field passwordHash.
I noticed that when I serialize the Identity DTO the passwordHash field is correctly hidden.
But when I serialize Preference with a relationship to to Identity the passwordHash is not hidden.
{
"data": {
"type": "identity/preference",
"id": "212dca7d-87be-500f-a269-0ddef0757415",
"attributes": {
"name": "restriction.ip.enabled",
"preference_id": "212dca7d-87be-500f-a269-0ddef0757415",
"value": false
},
"relationships": {
"identity": {
"data": {
"type": "identity/user",
"id": "fff1324d-1383-5363-a6db-b9b7d2f856e9"
}
}
}
},
"included": [
{
"type": "identity/user",
"id": "fff1324d-1383-5363-a6db-b9b7d2f856e9",
"attributes": {
"passwordHash": "$2y$14$Q0xLWS....",
"displayName": "Xxxxx Xx Xxx",
"emailAddress": "[email protected]",
"registrationDate": "2012-12-20T13:41:29+0100",
"emailStatus": "verified",
"accountStatus": "active",
"roles": [
"guest",
"member",
"admin",
"member.customer"
]
}
}
],
"jsonapi": {
"version": "1.0"
}
}
Before https://github.com/nilportugues/php-json-api/blob/master/src/Helpers/PropertyHelper.php#L47, make sure each member of the array is flat.
in src/Server/Query/QueryObject.php, line 91
This
errorBag
local variable is declared but never used. You should remove it.
}
}
if (false === empty($validateFields)) {
foreach ($validateFields as $type) {
$errorBag[] = new InvalidParameterError($type, strtolower($paramName));
}
}
}
}
Posted from SensioLabsInsight
I have not seen that there is Authentication and authorizations for CRUD operations, do you plan to implement it?
I am constantly getting for this code:
$mappings = array(OfferMapping::class); // Also tried with []
$mapper = new Mapper($mappings);
$transformer = new JsonApiTransformer($mapper);
$serializer = new JsonApiSerializer($transformer);
return response()->$serializer->serialize(Offer::all())
->header('Access-Control-Allow-Origin', '*');
This error message:
1/1
FatalThrowableError in MappingFactory.php line 93:
Type error: Argument 1 passed to NilPortugues\Api\Mapping\MappingFactory::fromArray() must be of the type array, string given, called in /var/www/vendor/nilportugues/api-transformer/src/Mapping/Mapper.php on line 53
in MappingFactory.php line 93
at MappingFactory::fromArray('App\Api\Mappings\OfferMapping') in Mapper.php line 53
at Mapper->buildMapping('App\Api\Mappings\OfferMapping') in Mapper.php line 36
at Mapper->__construct(array('App\Api\Mappings\OfferMapping')) in OfferController.php line 35
I have tried passing
$mapper = new Mapper([1]);
$mapper = new Mapper(array(OfferMapping::class, $othermapping))
And other example values with no result. It seems to internally unbox the first one all the time.
I am using laravel 5.2 and using php-json-api 2.6.0.
Will clean up the code a fair amount and we should obtain a tiny performance boost.
There's no relationship between the Comment in the array and the Post resource.
Should appear under relationships, as "comments", inside an array containing the relationship data.
Just the concept. Needs work
//To build a bundle we need to automate generating the array with postId => {postId}
$routeNameFromMappingFile = 'nilportugues_application_view_post';
$router = $this->get('router')->getRouteCollection()->get($routeNameFromMappingFile);
preg_match_all('/{(.*?)}/', $router->getPath(), $matches);
$pattern = [];
if(!empty($matches)) {
$pattern = array_combine($matches[1], $matches[0]);
}
$route = urldecode($this->generateUrl($routeNameFromMappingFile, $pattern, true));
//Mapping declaration
$mapping = new Mapping(ViewPostResponse::class, $route, ['postId']);
$mapping->setClassAlias('post');
$mapping->setPropertyNameAliases(['postTitle' => 'headline', 'postBody' => 'content']);
$mappings = [$mapping->getClassName() => $mapping];
//Serializer into action
$serializer = new Serializer(new JsonApiTransformer($mappings));
$response = $serializer->serialize($commandBus->getResult());
return new Response(
$response, 200, ['Content-type' => 'application/vnd.api+json; charset=utf-8']));
in src/Server/Data/DataAssertions.php, line 131
This
errorBag
local variable is declared but never used. You should remove it.
$hasErrors = false;
foreach ($inputAttributes as $property) {
if (false === in_array($property, $properties)) {
$hasErrors = true;
$errorBag[] = new InvalidAttributeError($property, $data[JsonApiTransformer::TYPE_KEY]);
}
}
if ($hasErrors) {
throw new DataException();
Posted from SensioLabsInsight
Having a property named "article", if it's a collection returning an array, should be renamed to "articles".
Inflectors should be defined prior to the transformation
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.