-
Notifications
You must be signed in to change notification settings - Fork 33
Presentation of API v2 Overview
- Controllers manage the entry point for methods used for a response and generate operations to complete for the request as seen in QcAssaysController.
- Resources define how resources should present themselves, which values they can accept when being created or updated and how to get values in and out of the models, as seen in TransferResource.
- OperationProcessors work alongside the controller to perform the actions given in the request. These give us a way to perform non-standard operations for a request as seen in QcFileProcessor.
-
Routing is similar to standard Rails, but uses the special
jsonapi_resources
keyword, like in the routes.rb file.
Controllers use the plural form, but processors and resources use the singular. Definition of the pluralisation of complicated words like Labware or Person/People are defined in the inflections.rb file.
- Getting all resources of a type.
- Filtering resources.
- Including relationships.
- Creating new resources.
- Missing required parameter.
- Unrecognised parameters.
- Custom errors like bad combinations of parameters for TagLayoutResource.
-
immutable
anywhere in the resource ensures that only theGET
method work on the endpoint. See TransferRequestResource. -
jsonapi_resources
can be marked to disallow specific actions, or to only allow a list of actions. See TagLayouts in the routes.rb file.
Permissions about which fields can be fetched, created or updated is defined by methods on the resource.
fetchable_field()
self.updatable_fields(context)
self.creatable_fields(context)
The default implementations return the symbols for all the fields, but we have overrides in the BaseResource class which populate them using properties on the fields.
readonly: true
write_once: true
writeonly: true
Set this property to true
on a field to always be given the "type"
and "id"
of the related object, even if it hasn't been requested to be included. See
RequestResource for an example of this being used.
Beware how the gem used by Limber interprets this result. It's only useful if you don't intend to get the rest of the data for the related resource.
You can declare custom methods, but you must parse the incoming request yourself and respond with a JSON:API compliant response, without help from the gem. This is necessary if you want to create endpoints like the preview
one on BaitLibraryLayoutsController though.
Documentation is written using YARD docs. This is focussed mainly on the resources and we should try to follow some of the patterns already used. See QcFileResource for a comprehensively documented resource.
- Classes should document what the resource is used for, how to call its endpoint, what the permissions are like for the resource and links to JSON:API documentation.
- Attributes should use the
@!attribute
YARD directive, indicating the permissions for the attribute, the return type and a good description of what the attribute is used for. - Relationships should be documented similarly to attributes. In some legacy resources, there is both an attribute and a relationship for a related item. See BaitLibraryLayoutResource for an example. In these cases, the attribute should be marked as deprecated and should yield to values passed by the relationship. The attribute should also not be fetchable.
- Filters should use the
@!method
YARD directive, should list what the intention of the filter is and should give an example of the request you might want to use to apply the filter.
The documentation is available on GitHub pages and can be updated when we want using a pipeline.
We have test matchers for resources that can test the model name for a resource, the behaviour of attributes, the behaviour of relationships and whether a filter has been defined. See QcFileResource specs for an example of many of these. The below are examples of the sort of thing available.
- Model name
have_model_name
- Attributes
have_readonly_attribute
have_write_once_attribute
have_writeonly_attribute
- Relationships
have_a_readonly_has_one
have_a_write_once_has_one
have_a_readonly_has_many
have_a_write_once_have_many
- These can all be chained with
with_class_name
- Filters
filter
Requests should cover a range of tests on how the resource can be manipulated via the API. The Plates spec gives a good overview of the sorts of tests you might want to perform. These are usually a bit specific to the resource, but try to follow a standard pattern like the following.
- Confirm API authentication applies to the endpoint.
- Create a number of the resource.
- Can you get all of them back via the base endpoint with a
GET
request?
- Can you get all of them back via the base endpoint with a
- Create a single instance of the resource.
- When you get the single instance back, are all the expected fields there?
- Do the fields contain the correct values?
- Are the write-only fields missing like they should be?
- Are relationships in the response?
- If you ask for them, are the related resources included in the response?
- Attempt to
PATCH
an existing resource.- Is the endpoint blocked when it should be?
- If not blocked, is the model updated?
- If not blocked, is the response representative of the updated resource?
- Attempt to
POST
a new resource.- If the endpoint should be blocked, is it?
- Has the model record been created?
- Is the response representative of the created model?
- Have related resources had their model records associated with the new resource?
- Are read-only fields generating an error when included in the request?
- Are any custom handling of requests generating the appropriate errors?
TBC