Giter Site home page Giter Site logo

json-api's Issues

Nested selfSubUrl

Is it possible to have a 'selfSubUrl' such as /users/{id}/followers.

Apologies if I missed it in the docs.

Support resource types that can behave as a proxy (e.x. Doctrine Proxies etc.)

Hi,

There are some use cases where the resource type that is defined with Encoder::instance() will not match the one that another schema is returning, but instead is a subclass. One of them is when you return a proxy object in the getRelationships method of a schema.

I will give a code example. Let's say we have a PostSchema that has the following relationships:

public function getRelationships($post)
{
    return [
        'author' => [
            self::DATA => $post->getAuthor() // will not return an Author object, but an AuthorProxy which extends Author
        ]
    ];
}

Now when you want to encode a Post, it will give you an error, saying that there is no provider for AuthorProxy. You see the problem? AuthorProxy IS an Author, but the encoder cannot handle this.

This is caused by Container::getSchema($resource):

public function getSchema($resource)
{
    $resourceType = get_class($resource);
    // ...
}

I can propose two solutions. One is that we check with instanceof if it can provide a schema for $resource. The second solution is that it supports Doctrine natively, we can do this by extending the Container with:

public function getSchema($resource)
{
    $resourceType = get_class($resource);

    // support for Doctrine Proxies
    if (class_exists('Doctrine\Common\Util\ClassUtils')) {
        $resourceType = ClassUtils::getRealClass($resourceType);
    }

    // ...
}

Also, it could have it's own ClassUtils class that will get the correct class name if there is __CG__ (common marker name for proxy classes) in the name. Then it will support Doctrine too and probably more libraries that implement the Proxy pattern.

PHP 5.5+ required?

Hi.

I am getting:

"FatalErrorException in Encoder.php line 145:
syntax error, unexpected 'class' (T_CLASS), expecting identifier (T_STRING) or variable
(T_VARIABLE) or '{' or '$'"

when I try to instantiate the Encoder using:

$encoder = Encoder::instance([
    '\My\Path\Models\MyModel' => '\My\Path\Schemas\MyModelSchema',
], new EncoderOptions(JSON_PRETTY_PRINT));

I am running PHP 5.4. Is "json-api" compatible with this version or do I need to upgrade to 5.5 please?

Thanks.

If you have an associative array, the encoder will choke when trying to get the schema of the first element

Hi,

When you have an associative array somewhere in your $data array that you pass to the Encoder, the Parser will choke when trying to get the schema.

// Parser.php
if (is_array($data) === true) {
    $isOriginallyArrayed = true;
    $schema = $this->container->getSchema($data[0]); // better would be to use reset($data)
} else {
    $isOriginallyArrayed = false;
    $schema = $this->container->getSchema($data);
    $data   = [$data];
}

Buggy enhancement #52

In limoncello-collins tests fail as it calls the render with $request and $exception as first two parameters (it's kinda interface for all renders). Render should be fixed accordingly.

Related to #52

Invalid page and filter params aren't validated

If you decide to add in a non-spec parameter to the request such as page=2, the application errors out. This should be handled and result in a 400 Bad Request instead.

The affected parameters I'm aware of are:

  • page
  • filter

This is the from the error log:

[2015-08-05 13:50:57] local.ERROR: exception 'ErrorException' with message 'Argument 6 passed to Neomerx\JsonApi\Factories\Factory::createParameters() must be of the type array, string given, called in /home/vagrant/www/work/lyf/vendor/neomerx/json-api/src/Parameters/ParametersParser.php on line 100 and defined' in /home/vagrant/www/work/lyf/vendor/neomerx/json-api/src/Factories/Factory.php:173
Stack trace:
#0 /home/vagrant/www/work/lyf/vendor/neomerx/json-api/src/Factories/Factory.php(173): Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(4096, 'Argument 6 pass...', '/home/vagrant/w...', 173, Array)
#1 /home/vagrant/www/work/lyf/vendor/neomerx/json-api/src/Parameters/ParametersParser.php(100): Neomerx\JsonApi\Factories\Factory->createParameters(Object(Neomerx\JsonApi\Parameters\Headers\Header), Object(Neomerx\JsonApi\Parameters\Headers\AcceptHeader), NULL, NULL, NULL, '2', NULL, NULL)
#2 /home/vagrant/www/work/lyf/vendor/neomerx/limoncello/src/Http/JsonApiTrait.php(305): Neomerx\JsonApi\Parameters\ParametersParser->parse(Object(Lyf\Http\Controllers\JsonApi\LaravelIntegration), Object(Neomerx\Limoncello\Errors\ExceptionThrower))
#3 /home/vagrant/www/work/lyf/vendor/neomerx/limoncello/src/Http/JsonApiTrait.php(316): Lyf\Http\Controllers\JsonApi\JsonApiController->getUncheckedParameters()
#4 /home/vagrant/www/work/lyf/vendor/neomerx/limoncello/src/Http/JsonApiTrait.php(334): Lyf\Http\Controllers\JsonApi\JsonApiController->checkParameters()
#5 /home/vagrant/www/work/lyf/vendor/neomerx/limoncello/src/Http/JsonApiTrait.php(398): Lyf\Http\Controllers\JsonApi\JsonApiController->getParameters()
#6 /home/vagrant/www/work/lyf/app/Http/Controllers/JsonApi/JsonApiController.php(46): Lyf\Http\Controllers\JsonApi\JsonApiController->getContentResponse(Array, 200, NULL, NULL)
#7 /home/vagrant/www/work/lyf/app/Http/Controllers/Api/UsersController.php(31): Lyf\Http\Controllers\JsonApi\JsonApiController->getResponse(Object(Illuminate\Database\Eloquent\Collection))
#8 [internal function]: Lyf\Http\Controllers\Api\UsersController->index()

Easier encoding for paging links

That's an issue for discussion how to make pagination links generation easier.

As JSON-API spec says it is agnostic about the pagination strategy as there are at least a few possibilities e.g. page-based, offset-based, and cursor-based. For this reason pagination strategy is not detailed in the spec.

Currently paging links could be generated like this

$links = [
    Link::FIRST => new Link('/authors?page=1'),
    Link::LAST  => new Link('/authors?page=4'),
    Link::NEXT  => new Link('/authors?page=6'),
    Link::LAST  => new Link('/authors?page=9'),
];
$encoder->withLinks($links)->encodeData($authors);

While this approach is almost fine it would've better if Encoder looked into $authors and took sub-URL part /authors from AuthorSchema.

The question is what interface such a method could have to be flexible and easy to use? There are a few thinks that should be in mind: URLs might be relative as in the sample above or absolute http://example.com/api/authors?..., links might have meta information and different paging strategies are possible.

One of the possible approach

$encoder
    ->withPagingLinks([Link::FIRST, Link::LAST, ...], $pageLinksGenerator)
    ->encodeData(...);

Where first parameter is a list of desired links (all possible values are defined by the spec) and $pageLinksGenerator is an instance of a class which implements

interface PageLinksGeneratorInterface
{
    public function getLink(string $linkKey, string $schemaSubUrl);
}

So PageLinksGeneratorInterface implementation e.g. PageBasedLinksGenerator will do it for particular strategy and user can chose which one to use.

Semver

To follow semver, shouldn't the version numbers be more like 0.2.0, so that you can do something like ~0.2.0 in composer.json. Not that it matters much as long as the version isn't 1.0.

I'm guessing you're planning to tag v1.0.0 when the spec becomes stable?

Add aliases support for relationships

From spec: A server MAY choose to expose a deeply nested relationship such as comments.author as a direct relationship with an alias such as comment-authors. This would allow a client to request /articles/1?include=comment-authors instead of /articles/1?include=comments.author. By abstracting the nested relationship with an alias, the server can still provide full linkage in compound documents without including potentially unwanted intermediate resources.

It used to be excluded by default for nested relationships (and it is implemented in RC3). Now this functionality has to be changed to work with aliases. See related #15

Lazy load relationship data

I have the following code:

    public function getRelationships($user)
    {
        return [
            'followers' => [
                self::SHOW_DATA    => false,
                self::DATA         => function () use ($user) {
                    return $user->followers;
                },
                self::SHOW_RELATED => true,
            ]
        ];
    }

It would be nice if that closure wasn't evaluated until needed. In my case when include=followers in which case you would then call and render.

It seems like I have to potentially run multiple SQL statements even if the data isn't returned in the JSON.

Relationship without a data object, but only with links. Is this possible?

Hi,

I am trying to have a relationship that does not include the data object and only use the links. This way my API can async load them later.

This is what I tried, but my relationship does not have any value, just null:

public function getRelationships($product)
{
    return [
        'translations' => [
            self::SHOW_SELF => true,
            self::SHOW_RELATED => true
        ];
}

Is this possible and how would I accomplish this?

Encoder fails to encode empty data if field set is specified

Test snippet

$actual = $endcoder->encode([], null, null, new EncodingParameters(null, [
    // include only these attributes and links
    'authors' => [Author::ATTRIBUTE_FIRST_NAME, Author::LINK_COMMENTS],
]));

PHP Fatal error: Call to a member function getIncludePaths() on a non-object in /json-api/src/Encoder/Encoder.php on line 196

Documentation Improvements: README

It's not clear from the examples in the README what exactly the instance method requires for input. A DocBlock or a standard function description including data types would be the minimum requirement here, but it appears that the inputs are complex enough to merit more thorough descriptions.

For example, in the following snippet:

$encoder = Encoder::instance([
    Author::class  => AuthorSchema::class,
], new JsonEncodeOptions(JSON_PRETTY_PRINT));

echo $encoder->encode($author) . PHP_EOL;

What exactly is "Author::class" or "AuthorSchema::class"? Is "::class" a class constant that was not defined in the code included in the "sample" directory? Or are you trying to demonstrate that the input format should map a model class with a schema class? Even after looking at the source code, I'm not entirely sure. Also, since the $author instantiation isn't shown, it's unclear what exactly it is.

A few more explanations here would go a long way and be much appreciated. Thanks.

Filter nested attributes

Given the following attributes:

"attributes": {
    "username": "vivalacrowe",
    "private": {
        "email": "[email protected]",
        "name": "Rob"
    }
}

How do you filter to only get the email address. I've tried:

$params = new \Neomerx\JsonApi\Parameters\EncodingParameters(
    null,
    [
        'user' => ['private.email']
    ]
);

But this returns:

{
    "data": {
        "type": "user",
        "id": "12287",
        "links": {
            "self": "https:\/\/api.crowdcube.com\/users\/12287\/followers"
        }
    }
}

Filtering seems to only work on top level keys?

Relationships with single item arrays are converted to single object

If relationship data is array and the array contains only 1 item the array is converted into single object.

Instead of

{
    "data" : {
        "type"  : "posts",
        "id"    : "1",
        "attributes" : {
            "title" : "Title",
            "body"  : "Body"
        },
        "relationships" : {
            "comments" : {
                "data" : [
                    { "type":"comments", "id":"5" }
                ]
            }
        },
        "links" : {
            "self" : "http://example.com/posts/1"
        }
    }
}

The encoder returns (note: relationships --> comments --> data)

{
    "data" : {
        "type"  : "posts",
        "id"    : "1",
        "attributes" : {
            "title" : "Title",
            "body"  : "Body"
        },
        "relationships" : {
            "comments" : {
                "data" :  { "type":"comments", "id":"5" }
            }
        },
        "links" : {
            "self" : "http://example.com/posts/1"
        }
    }
}

Cursor pagination and attributes object

Hey there,

looking at various packages to implement an API conform to the JSON-API spec atm and it seems yours is the most complete one so far. Looking through the readme, the only things I noticed missing were cursor-based pagination and the attributes top-level object to hold information about the resource. Would you be interested in PRs for these things or is this maybe already in development? Cheers!

Revert exclusion of intermediate resources

It used to be that intermediate resources had to be excluded.

Now: Because compound documents require full linkage, intermediate resources in a multi-part path must be returned along with the leaf nodes. For example, a response to a request for comments.author should automatically include comments as well as the author of each of those comments.

However they should be excluded within relationships with 'aliases'. See related #16

Adding multiple errors

According to the wiki it's possible to do something like:

$error = new Error(
    'some-id',
    new Link('about-link'),
    'some-status',
    'some-code',
    'some-title',
    'some-detail',
    ['source' => 'data'],
    ['some'   => 'meta']
);

Encoder::instance([])->encodeError($error);

but it does not seem possible to add multiple errors. Or is it? If so what would be the way to do so?

My use case is the following:

  • A user sends a domain/ip address as part of an HTTP request (JSON encoded in the request body). I want to validate both parameters before proceeding further with the request. I want to return all possible errors (i.e, invalid domain and invalid ip address, etc).

Is this possible?

For deeply nested duplicates assert in ElementPresenter fails

in method setRelationshipTo assert('$parentExists === true') fails

way to reproduce

Encoder::instance([
            Author::class  => AuthorSchema::class,
            Comment::class => CommentSchema::class,
            Post::class    => PostSchema::class,
            Site::class    => SiteSchema::class,
        ], $this->encoderOptions)->encode([$this->site, $this->site]);

Author must have null relationship to Comments otherwise the error does no occures

Adding Links to resources and included

How can one add links to a resource object such as

{
    "data": {
        "type": "leads",
        "id": "29",
        "attributes": {
            "status": 0
        },
        "links": {
            "self": "localhost:4000\/leads\/29",
            "somelink": "link"
        }
    }
}

where "somelink" is the link to be added? Thanks!

Github badge glitch

Github shows there is a problem with build when Travis says it's totally fine. Must be a caching issue.

The lib restricts links on resource level to 'self' only

spotted by @yoanisgil in #54

Not very often used feature however it should give options to add custom links on resource level

{
  "data": 
  {
    "type": "someType",
    "id": "123",
    "attributes": {
      "name": "some name"
    },
    "links": {
        "custom-link": "..." 
    }
  }
}

Links on 'relationships' level could be used while it's not added

Relationships with empty data might have links and meta

Current implementation uses JSON API RC3 convention that relations with empty data ([] or null) are encoded as null or []. Since version 1.0 relationship can have links and meta with data set to null or [].

Thus instead of

{
    ...
    "relationships" : {
        "author" : null
    },
    ...
}

It should be

{
    ...
    "relationships" : {
        "author" : {"data" : null}
    },
    ...
}

Encoding Relationships

Hi,

Just wondering how relationship endpoints are meant to be encoded? The encoder interface doesn't seem to have a method for encoding relationships, and I can't find any mention in your wiki about it.

The example instance from the JSON-API spec would be:

GET /articles/1/relationships/author HTTP/1.1
Accept: application/vnd.api+json
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "links": {
    "self": "/articles/1/relationships/author",
    "related": "/articles/1/author"
  },
  "data": {
    "type": "people",
    "id": "12"
  }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.