A few weeks ago our team was building the android application associated to our timetracker system and we needed to integrate our existing rails app with the new mobile application.
We needed to expose an API end-point in the system in order to have a clean communication interface that would allow the mobile Android client to consume and push information to the system.
We began to work in our new API based on Grape. We liked all about Grape, specially its integration with swagger (documentation support). However, we had some discussions about how the information should be sent from server to the clients (in that moment, we had just an android client), the main concern was how to send to specific clients just the exact information that it needed. We thought about several approaches and finally we narrowed it down to two of them.
In summary, our problem’s context was focused on how to manipulate the information that would be sent from server to specific client by using existent information in our models. Also the problem was not strictly about representations (as decorators) but was related to transformations, which means, generating new information based on both internal and external criteria associated with the target model itself.
We knew how both query and path parameter types let us express variations in the URIs and how this allows identifying resources and its associated actions through a truly resource oriented API (i.e. REST).
Suppose that we have a model named User and we need to have two representations: a "default" one that will present the model information itself, and a "compact" one that will reduce the presented information and expose some transformations according to some specific data from the model. As mentioned before, we have two alternatives in order to fetch these representations: the first one is to follow a short convention to use transformations according to the query parameter types, however this approach contaminates the url with a param that will change the expected response schema, an example for that, is shown below:
this approach conflicts and breaks the resource representation consistency used along many common documentation tools (such as swagger, raml, blueprint, etc) which do not associate the documentation schemas to vary according to query parameters.
The second approach is to define transformations using path param types. As an example, we would have urls like the following:
in this case, we can have multiple transformations and we can define one schema for each of them much cleaner than the first approach in terms of documentation and usage and with the added benefit of not breaking the way this documentation is presented by automated tools. We created grape-transformations to help us follow this pattern and integrates with the Grape core generating a simple tool that defines a reusable structure also combining grape-entity with a simple DSL.
grape-transformations is a gem that works with Rails and Grape to organize and make possible the use of multiple Grape entities per model, while at the same time, decoupling them from your models.
Grape is a great framework for creating REST-like APIs, however the model representation based on grape-entity requires some coupling with a unique declaration per model; although you can have many entities per model, each time that you add a different representation or entity, your code will become repetitive and hard to maintain.
Multi-entities support per model enables you create multiple representations (transformations) of a single resource when your domain requires it to. There are many ways to confront this issue and there are many different API design styles that you can implement. grape-transformations proposes one way to solve this problem.
grape-transformations's main concern is about modularization and organization, the main idea is to automatically associate the models with their respective entity set through a group of conventions so that we can use these associations to easily build smart endpoints using transformations. The concept of smart endpoints in grape-transformations refers to the possibility of representing a single resource on multiple urls, each one rendering a different output programmatically.
Each model can have several representations or variations in the business domain, each of these multiple representations is known as a transformation in the grape-transformations' context. grape-transformations' can generate reusable endpoints associated to the specific model, for example, you can define the "compact" and "default" transformations using Grape::Entity as a facade approach and automatically access your transformations as individual endpoints.
Smart Endpoints are the grape-transformations’s concept associated with the way multiple endpoints are rendered based on a single original endpoint definition. However you should follow some conventions related to the naming and namespacing of entities for this to work automatically.
First of all, you need to define an entity set associated with the transformations that you want to use per model, these entities (classes that inherit Grape::Entity) should be defined into a specific namespace named “entities” in order to follow the internal conventions, so your folder structure should be similar to:
In the picture above, the "entities" folder groups all defined transformations for each model, in this case, the only available transformations belong to the User model. However you don’t have to build all of this from scratch, the grape-transformations gem helps you with easy to use generators so you don't have to.
Once you have created your entities in the right folders, you can use the smart endpoint definition within your API modules. Grape and grape-transformations is structured in this way, so that the API is decoupled through the use of entities and modules.
Secondly, you need to build another folder called “modules” and segregate the API's complexity through the division of endpoints grouped either by model or however you see fit according to your business domain. Finally your directory structure would be similar to:
In the picture above, we have the User module which typically defines the endpoints associated with the User stack. In this same module you can define the smart endpoints associated to the User model by using the DSL methods defined by grape-transformations which are: define_endpoints, define_non_transformable_endpoints and add_endpoints. Refer to the Usage section in Github for a detailed description of the syntax used.
The grape-transformations' DSL allows you to write your traditional endpoint structure associated with single endpoint behavior and will take your original definitions and add the smart endpoints (endpoints related with the transformations) for you. Bear in mind that the grape-entity gem allows you to create representations that can have attributes manipulated through blocks, which means that you can expose new attributes (e.g. virtual attributes, computed properties, and so on).
In summary, grape-transformations is able to provide the following features:
Hope you find this gem as useful as it was for us, check out the source code at github and let us know what you think in the comments!