Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/pragmarb/pragma-decorator
Powerful and elegant model presenters with a twist.
https://github.com/pragmarb/pragma-decorator
api decorator pragma ruby ruby-on-rails trailblazer
Last synced: 13 days ago
JSON representation
Powerful and elegant model presenters with a twist.
- Host: GitHub
- URL: https://github.com/pragmarb/pragma-decorator
- Owner: pragmarb
- License: mit
- Created: 2016-11-15T17:29:23.000Z (almost 8 years ago)
- Default Branch: master
- Last Pushed: 2020-02-01T14:17:16.000Z (almost 5 years ago)
- Last Synced: 2024-04-23T18:34:23.035Z (7 months ago)
- Topics: api, decorator, pragma, ruby, ruby-on-rails, trailblazer
- Language: Ruby
- Homepage:
- Size: 190 KB
- Stars: 4
- Watchers: 1
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# Pragma::Decorator
[![Build Status](https://travis-ci.org/pragmarb/pragma-decorator.svg?branch=master)](https://travis-ci.org/pragmarb/pragma-decorator)
[![Coverage Status](https://coveralls.io/repos/github/pragmarb/pragma-decorator/badge.svg?branch=master)](https://coveralls.io/github/pragmarb/pragma-decorator?branch=master)
[![Maintainability](https://api.codeclimate.com/v1/badges/e51e8d7489eb72ab97ba/maintainability)](https://codeclimate.com/github/pragmarb/pragma-decorator/maintainability)Decorators are a way to easily convert your API resources to JSON with minimum hassle.
They are built on top of [ROAR](https://github.com/apotonick/roar). We provide some useful helpers
for rendering collections, expanding associations and much more.## Installation
Add this line to your application's Gemfile:
```ruby
gem 'pragma-decorator'
```And then execute:
```console
$ bundle
```Or install it yourself as:
```console
$ gem install pragma-decorator
```## Usage
Creating a decorator is as simple as inheriting from `Pragma::Decorator::Base`:
```ruby
module API
module V1
module User
module Decorator
class Instance < Pragma::Decorator::Base
property :id
property :email
property :full_name
end
end
end
end
end
```Just instantiate the decorator by passing it an object to decorate, then call `#to_hash` or
`#to_json`:```ruby
decorator = API::V1::User::Decorator::Instance.new(user)
decorator.to_json
```This will produce the following JSON:
```json
{
"id": 1,
"email": "[email protected]",
"full_name": "John Doe"
}
```Since Pragma::Decorator is built on top of [ROAR](https://github.com/apotonick/roar) (which, in
turn, is built on top of [Representable](https://github.com/apotonick/representable)), you should
consult their documentation for the basic usage of decorators; the rest of this section only covers
the features provided specifically by Pragma::Decorator.### Object Types
It is recommended that decorators expose the type of the decorated object. You can achieve this
with the `Type` mixin:```ruby
module API
module V1
module User
module Decorator
class Instance < Pragma::Decorator::Base
include Pragma::Decorator::Type
end
end
end
end
end
```This would result in the following representation:
```json
{
"type": "user",
"...": "..."
}
```You can also set a custom type name (just make sure to use it consistently!):
```ruby
module API
module V1
module User
module Decorator
class Instance < Pragma::Decorator::Base
def type
:custom_type
end
end
end
end
end
end
````Array` and `ActiveRecord::Relation` are already overridden as `list` to avoid exposing internal
details. If you want to specify your own global overrides, you can do it by adding entries to the
`Pragma::Decorator::Type.overrides` hash:```ruby
Pragma::Decorator::Type.overrides['Article'] = 'post'
```### Timestamps
[UNIX time](https://en.wikipedia.org/wiki/Unix_time) is your safest bet when rendering/parsing
timestamps in your API, as it doesn't require a timezone indicator (the timezone is always UTC).You can use the `Timestamp` mixin for converting `Time` instances to UNIX times:
```ruby
module API
module V1
module User
module Decorator
class Instance < Pragma::Decorator::Base
include Pragma::Decorator::Timestamptimestamp :created_at
end
end
end
end
end
```This will render a user like this:
```json
{
"type": "user",
"created_at": 1480287994
}
```The `#timestamp` method supports all the options supported by `#property`.
### Associations
`Pragma::Decorator::Association` allows you to define associations in your decorator (currently,
only `belongs_to`/`has_one` associations are supported):```ruby
module API
module V1
module Invoice
module Decorator
class Instance < Pragma::Decorator::Base
include Pragma::Decorator::Associationbelongs_to :customer, decorator: API::V1::Customer::Decorator::Instance
end
end
end
end
end
```Rendering an invoice will now create the following representation:
```json
{
"customer": 19
}
```You can pass `expand[]=customer` as a request parameter and have the `customer` property expanded
into a full object!```json
{
"customer": {
"id": 19,
"...": "..."
}
}
```This also works for nested associations. For instance, if the customer decorator had a `company`
association, you could pass `expand[]=customer&expand[]=customer.company` to get the company
expanded too.Note that you will have to pass the associations to expand as a user option when rendering:
```ruby
decorator = API::V1::Invoice::Decorator::Instance.new(invoice)
decorator.to_json(user_options: {
expand: ['customer', 'customer.company', 'customer.company.contact']
})
```Needless to say, this is done automatically for you when you use all components together through
the [pragma](https://github.com/pragmarb/pragma) gem! :)Associations support all the options supported by `#property`. Additionally, `decorator` can be a
callable object, which is useful for polymorphic associations:```ruby
module API
module V1
module Discount
module Decorator
class Instance < Pragma::Decorator::Base
include Pragma::Decorator::Associationbelongs_to :discountable, decorator: -> (discountable) {
"API::V1::#{discountable.class}::Decorator::Instance".constantize
}
end
end
end
end
end
```### Collection
`Pragma::Decorator::Collection` wraps collections in a `data` property so that you can include
metadata about them:```ruby
module API
module V1
module Invoice
module Decorator
class Collection < Pragma::Decorator::Base
include Pragma::Decorator::Collection
decorate_with Instance # this is optional, the default is 'Instance'property :total_cents, exec_context: :decorator
def total_cents
represented.sum(:total_cents)
end
end
end
end
end
end
```You can now do this:
```ruby
API::V1::Invoice::Decorator::Collection.new(Invoice.all).to_json
```Which will produce the following JSON:
```json
{
"data": [{
"id": 1,
"total_cents": 1500,
}, {
"id": 2,
"total_cents": 3000,
}],
"total_cents": 4500
}
```This is very useful, for instance, when you have a paginated collection, but want to include data
about the entire collection (not just the current page) in the response.### Pagination
Speaking of pagination, you can use `Pragma::Decorator::Pagination` in combination with
`Collection` to include pagination data in your response:```ruby
module API
module V1
module Invoice
module Decorator
class Collection < Pragma::Decorator::Base
include Pragma::Decorator::Collection
include Pragma::Decorator::Paginationdecorate_with Instance
end
end
end
end
end
```Now, you can run this code:
```ruby
API::V1::Invoice::Decorator::Collection.new(Invoice.all).to_json
```Which will produce the following JSON:
```json
{
"data": [{
"id": 1,
"...": "...",
}, {
"id": 2,
"...": "...",
}],
"total_entries": 2,
"per_page": 30,
"total_pages": 1,
"previous_page": null,
"current_page": 1,
"next_page": null
}
```It works with both [will_paginate](https://github.com/mislav/will_paginate) and
[Kaminari](https://github.com/kaminari/kaminari)!### Restricting property visibility
If you want to show or hide certain properties programmatically, you can do it with the `if` option:
```ruby
module API
module V1
module User
module Decorator
class Instance < Pragma::Decorator::Base
property :id
property :first_name
property :last_name
property :email, if: -> (user_options:, decorated:, **) {
# Only show the email to admins or to the same user.
user_options[:current_user].admin? || user_options[:current_user] == decorated
}
end
end
end
end
end
```## Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/pragmarb/pragma-decorator.
## License
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).