Create a Singleton Resource for JSONAPI with jsonapi-resources ruby gem

The Jsonapi Resources gem is a resource-focused Rails library for developing JSON API compliant servers.

The Jsonapi-Resources makes having your server compliant with JSON API specification much easier but i found the myself wanting to use a signleton resource. (Note: singletons are not supported by the json-api spec, you probably should not use them.)

A singleton resource is a api url call that will always lead to only one resource. A real world use case would be “GET /profile” and “PATCH /profile” which (respectively) would get the profile record of the current user and update the record of the current record.

As mentioned in the gem’s README documentation in the routes section you need a singular resource route without an id:

config/routes.rb:

1
jsonapi_resource :profile

you need to record the current logged in user via a context method on one of your controllers or across all controllers using ApplicationController:

1
2
3
def
   context { user: current_user }
end

and then you need to override the find_by_key method on the profile resource:

1
2
3
4
5
6
def self.find_by_key(key, options = {})
      context = options[:context]
      model = context[:user]
      fail JSONAPI::Exceptions::RecordNotFound.new(key) if model.nil?
      resource_for_model(model).new(model, context)
end

Note that your controller will also be in the singular `profile_controler.rb` not `profiles_controler.rb’

then the singleton calls ( GET /profile, POST /profile, PUT /profile, DELETE /profile ) will work ( although the json api type will still be plural type: ‘profiles’, )

Note: singletons are not supported by the json-api spec, so there may be (many?) clients that are not compatible with this approach. That inculdes the Ember Data JSONAPIAdapter :/

The json-api spec dropped singletons when it went final, and because the Jsonapi-Resources gem was built prior to the final spec to still includes the ability to create a singular resource route. You probably should not use it!

Leave a Reply