plexus / yaks

Ruby library for building hypermedia APIs
http://rubygems.org/gems/yaks
MIT License
236 stars 26 forks source link

Supporting the `include` query parameter for JSON-API #83

Closed janko closed 9 years ago

janko commented 9 years ago

One other thing I was thinking about was somehow adding the support for automatic include recognition. This is also part of JSON-API specification; it is under MAY (so servers don't have to implement it), but I think many people will want to use it, and IMO that's for me one of main advantages of JSON-API, because it really makes the API flexible.

The nice thing is that Yaks already supports passing in env, in which case we have the "QUERY_STRING" available. This is what I did in my application:

require "rack/utils"

class BaseMapper < Yaks::Mapper
  def self.has_one(name, **options)
    super name, **options, if: -> { include_association?(name) }
  end

  def self.has_many(name, **options)
    super name, **options, if: -> { include_association?(name) }
  end

  private

  def include_association?(name)
    includes.any? do |relationship|
      relationship.split(".")[mapper_stack.size] == name.to_s
    end
  end

  def includes
    query = Rack::Utils.parse_query(env["QUERY_STRING"])
    query["include"].to_s.split(",")
  end
end

You see that this is relatively easy to implement. This now nicely supports e.g. /posts/1?include=author,comments.author (mapper_stack was a life saver, maybe we could document it somewhere). Naturally, it should be opt-in, and possible to set per-association (sometimes user may want one association to always be included).

What I was most impressed about Yaks was its already great support for JSON-API, and that everything just worked without me having to do anything. So I want to continue that line, what do you think?

plexus commented 9 years ago

That's pretty cool stuff. At this point I would say to just stick it in the COOKBOOK. Yaks is deliberately unopinionated about how you structure your API. In other words we stay away at this point from request handling, which this comes close to.

Pagination and error handling are similar. I haven't found a good sweet spot yet about how to build it into Yaks without dictating how people should structure their API.

I can see a space for other projects to sit on top of Yaks but with stronger conventions, specific framework integrations, etc.

What we definitely should do though is make things easy, and provide good docs and examples. There's still a lot that could be documented better. So what I suggest

plexus commented 9 years ago

Also cool that mapper_stack was useful for this. The main reason we have it is to detect if we're rendering a top-level resource or a nested resource. Documenting it would obviously be a good thing. Maybe we need an "Advanced Mapper Writing" section in the README?

plexus commented 9 years ago

I've given this some more thought, and I think there could be a place for having these kind of "behaviors" as modules that you can include in your mappers.

include Yaks::Behavior::OptionalIncludes

janko commented 9 years ago

Cool, it'd be great ship this with Yaks, because it's my favourite "feature" of JSON-API (and I guess it could be general for any spec). I was intending to add it to the cookbook anytime now, but I will work on the behaviour idea now, I will have time on tuesday (need to help clean my own issue/PR tickets :P).

danelowe commented 9 years ago

Hey @janko-m I'm pinching your code here. I was doing something very similar, but had forgotten about the ability to include sub-sub-resources e.g. comments.author :bow:

janko commented 9 years ago

@plexus and I agreed we could put it in a separate module and ship with Yaks. I will try to do this today or tomorrow.

danelowe commented 9 years ago

:tada: