Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow flexible binding of scope output to configurable elements #15

Closed
opengeek opened this issue Jan 6, 2014 · 11 comments
Closed

Allow flexible binding of scope output to configurable elements #15

opengeek opened this issue Jan 6, 2014 · 11 comments

Comments

@opengeek
Copy link

opengeek commented Jan 6, 2014

I'm really loving this library, but I am having to currently rewrite the scope output to the structure my API needs. For instance, you output the Item properties into a data element, but my API expects the properties in the root JSON object (following HAL standards) of each Item (including in Collections). Likewise, embedded data needs to go into an _embedded element in the HAL spec, vs. embed.

I'm wondering if it might be possible to allow each scope to output the data, embed and pagination elements in a more flexible way. I think just allowing a way to extend the Scope::toArray() method would be sufficient, though I have not yet considered if that is the best approach.

I assume if you are planning to support the HAL draft standard, or any of the various other HATEOAS media source specifications, the same issue will be encountered. Thoughts?

@philsturgeon
Copy link
Member

I have been considering adding a "format" or "Structure" system to allow things to be structured in certain ways, but embedded (nested) verses compound documents is not something we can really do. Compound documents all go in a flat-file structure, where as embedded are supposed to be inside the document and allow unlimited nesting. 

So HAL won't really work here.

Also "embeds" is not __embedded, thats something totally different. They are just a list of available scopes, no something that any spec outlines.

-- 
Phil Sturgeon
Sent with Airmail

On January 6, 2014 at 11:27:37 AM, Jason Coward (notifications@github.com) wrote:

I'm really loving this library, but I am having to currently rewrite the scope output to the structure my API needs. For instance, you output the Item properties into a data element, but my API expects the properties in the root JSON object (following HAL standards) of each Item (including in Collections). Likewise, embedded data needs to go into an _embedded element in the HAL spec, vs. embed.

I'm wondering if it might be possible to allow each scope to output the data, embed and pagination elements in a more flexible way. I think just allowing a way to extend the Scope::toArray() method would be sufficient, though I have not yet considered if that is the best approach.

I assume if you are planning to support the HAL draft standard, or any of the various other HATEOAS media source specifications, the same issue will be encountered. Thoughts?


Reply to this email directly or view it on GitHub.

@opengeek
Copy link
Author

opengeek commented Jan 6, 2014

Not sure I understand... here is a HAL Item response body...

{
     "_links": {
       "self": { "href": "/orders/523" },
       "warehouse": { "href": "/warehouse/56" },
       "invoice": { "href": "/invoices/873" }
     },
     "currency": "USD",
     "status": "shipped",
     "total": 10.20
   }

My main problem here is that the properties are not stuffed into a data element IOW. You seem to have adopted some arbitrary format for the resulting JSON here and I was hoping to be able to easily mutate the format based on Accept headers for specific media types.

Consider another arbitrary format, this time for a Collection instead of an Item...

{
    meta: {
        href: "/people"
    },
    total: 2,
    limit: 25,
    offset: 0,
    first: {
        meta: {
            href: "/people"
        }
    },
    previous: null,
    next: null,
    last: {
        meta: {
            href: "/people"
        }
    },
    items: [{
        meta: {
            href: "/people/user1"
        },
        username: "user1"
    },{
        meta: {
            href: "/people/user2"
        },
        username: "user2"
    }]
}

Right now, I have to rewrite all the properties coming back from Scope::toArray() in order to achieve this format. It would be much easier if we could transform the properties coming back from the Scope in a way similar to how the Transforms work with each Item.

@philsturgeon
Copy link
Member

Well that is different.

Links

Links are not done yet, in any format. They will be applied soon, but they're on the todo list.

Embedded Data

You said:

Likewise, embedded data needs to go into an _embedded element in the HAL spec, vs. embed

I was explaining that embed is nothing to do _embedded, they are different things. Fractal just has those there for now as a way to highlight what embeds are possible. They could be considered meta data.

Scope::toArray()

Yeah absolutely. toArray() was made initially with the intention of letting folks change things around, but it grew more complex.

I'd consider abstracting it out so that structures can be changed, but it will always be "embedding" and never support "sideloading". Do we agree there? :)

public function toArray()
{
    $output = array(
        'data' => $this->runAppropriateTransformer()
    );

    if ($this->availableEmbeds) {
        $output['embeds'] = $this->availableEmbeds;
    }

    if ($this->resource instanceof Collection) {
        $paginator = $this->resource->getPaginator();

        if ($paginator !== null and $paginator instanceof PaginatorInterface) {
            $output['pagination'] = $this->outputPaginator($paginator);
        }
    }

    return $output;
}

This would simply need to be turned into a "Serializer" class with an interface, which is sent in as a getter/setting in the Manager class to override.

By default it be my arbitrary Facebook-like format, with HAL and JSON-API spec available too if somebody could be arsed writing it.

@opengeek
Copy link
Author

opengeek commented Jan 6, 2014

Sorry, I used arbitrary too much there...

I'll see if I can realize what you are describing.

@opengeek
Copy link
Author

opengeek commented Jan 6, 2014

Re:

I'd consider abstracting it out so that structures can be changed, but it will always be "embedding" and never support "sideloading". Do we agree there?

Indeed, I originally thought that the point of "embedding" in Fractal was to be able to include a full, partial, or inconsistent representation of object structures related to the main object being transformed. So you are saying this is not the case and it just describes what related objects might be available to load? If so, we can agree. I think I'm just getting confused by all the different formats for JSON HATEOAS...

@philsturgeon
Copy link
Member

standards

@joshuajabbour
Copy link
Contributor

Yes, I'm definitely looking for the ability to remove the top-level envelope as well. I don't need true HAL _embedded properties, but definitely want to be able to specify the output format. For an example of my desired output, see GitHub's API.

Your plan outlined above with different output formats sounds great. (Right now, I'm manipulating the data in my base controller before outputting the response, but a cleaner interface would be nice.)

@philsturgeon
Copy link
Member

If anyone would like to take this on I’ll be happy to discuss it. Right now I’m in between projects. My next project will use Fractal again, so I’ll be able to devote more efforts to it, but to try doing it in the next few weeks would lead to a half-arsed solution which is in nobodies best interests.

@RSully
Copy link

RSully commented Feb 4, 2014

I don't know if I could devote the time to it, but I've been following this issue closely as I am very interested in the outcome.

The 2 pieces I am interested in the most are:

  • data, embed, etc. are hardcoded names and can't be changed
  • There is no easy way to add custom properties to the root besides going ->toArray()

I'm sure instead of addressing these head-on there might be a better way to allow this functionality by way of other refactoring/changes that allow for easier additions going forward (if that makes any sense).

@joshuajabbour
Copy link
Contributor

Do you have a particular idea of how you'd prefer to implement this, so I can take a crack?

I really need this, as I'm trying to recreate an existing API, which doesn't have a 'data' wrapper. It's easy enough to get rid of the hierarchy in a controller for the top level, but once embeds are involved, I'll need to start parsing down multi-dimensional arrays. And I'd rather just figure out the "right" way to do this.

@joshuajabbour
Copy link
Contributor

Nevermind, I re-read your comments and it is quite clear. :)

I've got a good, working implementation of the current toArray as a pluggable serializer. I'll push it tomorrow after; as now it's beer time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants