
rabl 0.8.6 + correzione per CVE-2014-4671
RABL (Ruby API Builder Language) è un sistema di templating Ruby per Rails e Padrino per generare JSON, XML, MessagePack, PList e BSON. Quando uso il metodo 'to_json' di ActiveRecord, mi ritrovo a desiderare una soluzione più espressiva e potente per generare API. Questo è particolarmente vero quando la rappresentazione JSON è complessa o non corrisponde allo schema esatto definito nel database.
In particolare, voglio facilmente:
Chiunque abbia provato il metodo 'to_json' usato in ActiveRecord per generare una risposta JSON ha sentito il dolore di questo approccio restrittivo. RABL è un sistema di templating generale creato per risolvere questi problemi affrontando la generazione di risposte API in un modo completamente nuovo.
Al cuore, RABL riguarda l'aderenza ai principi MVC delegando le rappresentazioni dei dati API al livello view della tua applicazione. Per una analisi delle idee sbagliate comuni su RABL, consulta la nostra guida Understanding RABL che può aiutare a chiarire eventuali confusioni su questo progetto.
v0.8.0 (rilasciata il 14 febbraio 2013) rimuove la dipendenza da multi_json e si basa su Oj (o JSON) come parser json. Semplifica il codice, rimuove una dipendenza ma potresti voler rimuovere qualsiasi riferimento a MultiJson.
v0.6.14 (rilasciata il 28 giugno 2012) richiede l'uso di render_views con RSpec per testare i template. Altrimenti, il controller passerà semplicemente attraverso il comando render come fa con i template ERB.
Installa RABL come gemma:``` gem install rabl
oppure aggiungi al tuo Gemfile:```ruby
# Gemfile
gem 'rabl'
# Also add either `oj` or `yajl-ruby` as the JSON parser
gem 'oj'
ed esegui bundle install per installare la dipendenza.
Se stai utilizzando Rails 2.3.8 (e successive), Rails 3.X o Padrino, RABL funziona senza configurazione.
Importante: Con Padrino, assicurati che il gem rabl sia elencato dopo il gem padrino nel tuo Gemfile, altrimenti Rabl non si registrerà correttamente come motore di template.
Con Sinatra, o qualsiasi altro framework basato su tilt, registra semplicemente:```ruby Rabl.register!
e RABL sarà inizializzato e pronto per l'uso. Per l'utilizzo con Sinatra, consulta la guida [Sinatra Usage](https://github.com/nesquena/rabl/wiki/Setup-for-Sinatra).
## Overview ##
Puoi utilizzare RABL per generare API basate su JSON e XML da qualsiasi oggetto Ruby. Con RABL, i dati sono tipicamente derivati principalmente dai modelli (indipendenti dall'ORM) e la rappresentazione dell'output dell'API è descritta all'interno di un template di vista usando un semplice DSL Ruby. Questo ti permette di mantenere i tuoi dati separati dal JSON o XML che desideri produrre.
Una volta installato RABL (come spiegato sopra), puoi costruire un template di vista RABL e poi renderizzare il template dalle tue applicazioni Sinatra, Padrino o Rails dal controller (o route) molto facilmente. Usando [Padrino](http://padrinorb.com) come esempio, supponendo di avere un modello `Post` pieno di post del blog, puoi renderizzare una rappresentazione API (sia JSON che XML) creando una route:```ruby
# app/app.rb
get "/posts", :provides => [:json, :xml] do
@user = current_user
@posts = Post.order("id DESC")
render "posts/index"
end
Quindi possiamo creare il seguente template RABL per esprimere l'output API di @posts:```ruby
collection @posts attributes :id, :title, :subject child(:user) { attributes :full_name } node(:read) { |post| post.read_by?(@user) }
Che produrrebbe il seguente JSON o XML quando si visita `http://localhost:3000/posts.json````js
[{ "post" :
{
"id" : 5, title: "...", subject: "...",
"user" : { full_name : "..." },
"read" : true
}
}]
Questa è una panoramica di base, ma c'è molto altro da vedere come partials, inheritance, custom nodes, ecc. Leggi i dettagli completi di RABL qui sotto.
RABL è pensato per richiedere poca o nessuna configurazione per funzionare. Questo è il caso nella maggior parte degli scenari, ma a seconda delle vostre esigenze potreste voler impostare le seguenti configurazioni globali nella vostra applicazione (questo blocco è completamente opzionale):```ruby
require 'rabl' Rabl.configure do |config|
end
Ogni opzione specifica un comportamento relativo all'output di RABL. Se `include_json_root` è disabilitato, viene rimosso il nodo radice per ogni oggetto radice nell'output, e `enable_json_callbacks` abilita il supporto per output di callback in stile 'jsonp' se la richiesta in entrata ha un parametro 'callback'.
Se `include_child_root` è impostato su false, gli oggetti figli nella risposta non includeranno per impostazione predefinita un nodo radice. Questo ti consente di ottimizzare ulteriormente la struttura della risposta desiderata.
Se `cache_engine` è impostato, dovresti assegnarlo a una classe con un metodo `fetch`. Vedi il [motore predefinito](https://github.com/nesquena/rabl/blob/master/lib/rabl/cache_engine.rb) per un esempio.
Se `perform_caching` è impostato su `true`, eseguirà la memorizzazione nella cache. Puoi ignorare questa opzione se stai usando Rails, è equivalente a `config.action_controller.perform_caching` di Rails.
Se `cache_sources` è impostato su `true`, le ricerche dei template verranno memorizzate nella cache per migliorare le prestazioni. La cache può essere resettata manualmente eseguendo `Rabl.reset_source_cache!` all'interno della tua applicazione.
Se `cache_all_output` è impostato su `true`, ogni template, incluso ogni singolo template utilizzato come parte di una collezione, verrà memorizzato nella cache separatamente. Inoltre, qualsiasi cosa all'interno di child, glue e partial verrà anch'essa memorizzata separatamente. Per memorizzare nella cache un singolo template, consulta la sezione intitolata 'Caching' più avanti.
Se `escape_all_output` è impostato su `true` e ActiveSupport è disponibile, l'output degli attributi verrà escapato utilizzando [ERB::Util.html_escape](http://corelib.rubyonrails.org/classes/ERB/Util.html). I nodi personalizzati non verranno escapati, usa `ERB::Util.h(value)`.
Se `view_paths` è impostato su un percorso, questo percorso di view verrà controllato per ogni template rabl all'interno della tua applicazione. Aggiungi a questo percorso specialmente quando si include Rabl in un engine e si utilizzano i percorsi di view all'interno di un'altra app Rails.
Se `raise_on_missing_attribute` è impostato su `true`, verrà sollevato un RuntimeError ogni volta che Rabl tenta di renderizzare un attributo che non esiste. Altrimenti, l'attributo verrà semplicemente omesso. Impostare questo su true durante lo sviluppo può aiutare ad aumentare la robustezza del tuo codice, ma usare `true` in codice di produzione non è raccomandato.
Se `replace_nil_values_with_empty_strings` è impostato su `true`, tutti i valori che sono `nil` e che normalmente verrebbero visualizzati come `null` nella risposta vengono convertiti in stringhe vuote.
Se desideri utilizzare [oj](https://github.com/ohler55/oj) come motore di codifica JSON primario, aggiungilo semplicemente al tuo Gemfile:```ruby
# Gemfile
gem 'oj'
e RABL userà automaticamente quel motore per codificare le tue risposte JSON. Imposta il tuo motore json personalizzato che definisce un metodo dump o encode per convertire da dati Ruby a JSON:```ruby
config.json_engine = ActiveSupport::JSON
### Configurazione dei Formati ###
RABL supporta la configurazione per MessagePack, BSON e Plist. Consulta la pagina
[Configurazione dei Formati](https://github.com/nesquena/rabl/wiki/Configuring-Formats) per maggiori dettagli.
## Utilizzo ##
### Assegnazione dell'Oggetto ###
Per dichiarare l'oggetto dati da utilizzare nel template:```ruby
# app/views/users/show.json.rabl
object @user
o specifica un alias per l'oggetto:```ruby object @user => :person
oppure passa una raccolta di oggetti:```ruby
collection @users
# => [ { "user" : { ... } } ]
oppure specifica un'etichetta del nodo radice per la collezione:```ruby collection @users => :people
o addirittura specificare sia le etichette figlie che quelle radice per una collezione:```ruby
collection @users, :root => "people", :object_root => "user"
# => { "people" : [ { "user" : { ... } } ] }
e questo sarà usato come dato predefinito per il rendering, oppure disabilita esplicitamente la radice dell'oggetto:```ruby collection @users, :root => "people", :object_root => false
Ci possono anche essere casi particolari in cui il livello radice della risposta non corrisponde direttamente a nessun oggetto:```ruby
object false
node(:some_count) { |m| @user.posts.count }
child(@user) { attribute :name }
In quei casi, l'oggetto può essere assegnato a 'false' e i nodi possono essere costruiti in forma libera.
Uso base del templater per definire alcuni semplici attributi per la risposta:```ruby
attributes :id, :foo, :bar
oppure utilizza con attributi alias:```ruby
# Take the value of model attribute `foo` and name the node `bar`
attribute :foo => :bar
# => { bar : 5 }
o anche attributi con alias multipli:```ruby attributes :bar => :baz, :dog => :animal
o mostra attributi solo se una condizione è vera:```ruby
# m is the object being rendered, also supports :unless
attributes :foo, :bar, :if => lambda { |m| m.condition? }
Named and aliased attributes can not be combined on the same line. This currently does not work:
Gli attributi con nome e alias non possono essere combinati sulla stessa riga. Attualmente questo non funziona:```ruby attributes :foo, :bar => :baz # throws exception
### Child Nodes ###
Spesso una risposta richiede di includere informazioni nidificate dai dati associati al modello genitore:```ruby
child :address do
attributes :street, :city, :zip, :state
end
Puoi anche disabilitare il root dell'oggetto per il nodo figlio:```ruby child :posts, :object_root => false do attributes :id, :title end
Puoi anche aggiungere nodi figlio da una fonte dati arbitraria:```ruby
child @posts => :foobar do
attributes :id, :title
end
oppure usa le associazioni del modello con un alias:```ruby
child :posts => :foobar do attributes :id, :title end
Puoi anche passare l'oggetto corrente:```ruby
object @user
child :posts do |user|
attribute :title unless user.suspended?
end
Puoi anche aggiungere attributi figli al nodo radice:```ruby
glue @post do attributes :id => :post_id, :name => :post_name end
Use glue per aggiungere attributi aggiuntivi all'oggetto genitore.
Puoi anche passare l'oggetto corrente:```ruby
object @user
glue(@post) {|user| attribute :title if user.active? }
Questo genererà una risposta json basata sul risultato del blocco node:```ruby
node :full_name do |u| u.first_name + " " + u.last_name end
o un nodo personalizzato che esiste solo se una condizione è vera:```ruby
# m is the object being rendered, also supports :unless
node(:foo, :if => lambda { |m| m.has_foo? }) do |m|
m.foo
end
oppure non passare un nome e avere il blocco nodo unito nella risposta:```ruby node do |u| { :full_name => u.first_name + " " + u.last_name }
end
Puoi utilizzare nodi personalizzati come questi per creare rappresentazioni flessibili di un valore utilizzando tutti i dati del modello.
### Partials ###
Spesso è necessario accedere ad altri oggetti dati per costruire nodi personalizzati in associazioni più complesse. Puoi ottenere l'accesso alla rappresentazione rabl di un altro oggetto dati renderizzando un partial RABL:```ruby
node :location do
{ :city => @city, :address => partial("users/address", :object => @address) }
end
o addirittura accedere a un oggetto associato al modello genitore:```ruby node :location do |m| { :city => m.city, :address => partial("users/address", :object => m.address) } end
You can use this method to construct arbitrarily complex nodes for your APIs. Note that you need to have RABL templates defined
for each of the objects you wish to construct representations for in this manner.
### Inheritance ###
Another common issue of many template builders is unnecessary code redundancy. Typically many representations of an object across multiple endpoints share common attributes or nodes. The nodes for a 'post' object are probably the same or similar in most references throughout the various endpoints.
RABL has the ability to extend other "base" rabl templates and additional attributes:```ruby
# app/views/users/advanced.json.rabl
extends "users/base" # another RABL template in "app/views/users/base.json.rabl"
node :can_drink do |m|
m.age > 21
end
Puoi anche estendere altri template rabl durante la costruzione di nodi figli per ridurre la duplicazione:```ruby
child @address do extends "address/item" end
L'uso di partial e dell'ereditarietà può ridurre significativamente la duplicazione del codice nei tuoi template.
Puoi vedere ulteriori esempi nella [pagina wiki sul riutilizzo dei template](https://github.com/nesquena/rabl/wiki/Reusing-templates).
### Passaggio di variabili locali nei Partial ###
Puoi passare un insieme arbitrario di variabili locali durante il rendering di partial o l'estensione di template.
Ad esempio, se vogliamo mostrare in `posts/:id.json` qualsiasi informazione relativa a un particolare post e ai commenti associati, ma in altri casi vogliamo nascondere quei commenti. Possiamo usare le variabili locali per farlo:```ruby
# app/views/posts/index.json.rabl
collection @posts
extends('posts/show', :locals => { :hide_comments => true })
# or using partial instead of extends
# node(false) { |post| partial('posts/show', :object => :post, :locals => { :hide_comments => true })}
e poi accedere alle variabili locali nel sub-template:```ruby
object @post
attributes :id, :title, :body, :created_at node(:comments) { |post| post.comments } unless locals[:hide_comments]
Questo può essere utile come strumento avanzato quando si estendono o si renderizzano i partials.
### Ambito del Template ###
In RABL, hai accesso a tutto ciò di cui hai bisogno per costruire una risposta API. Ogni template RABL ha pieno accesso alle variabili di istanza del controller
così come a tutti i view helpers e routing urls.```ruby
# app/some/template.rabl
object @post
# Access instance variables
child(@user => :user) { ... }
# or Rails helpers
node(:formatted_body) { |post| simple_format(post.body) }
Non dovrebbero esserci problemi a recuperare i dati appropriati per costruire una risposta.
Nelle API, spesso è necessario costruire nodi di 2° o 3° livello. Supponiamo di avere un modello 'quiz' che ha molte 'domande' e poi ogni domanda ha molte 'risposte'. Possiamo visualizzare questa gerarchia in RABL abbastanza facilmente:```ruby
object @quiz attribute :title child :questions do attribute :caption child :answers do # Use inheritance to reduce duplication extends "answers/item" end end
This will display the quiz object with nested questions and answers as you would expect with a quiz node, and embedded questions and answers.
Note that RABL can be nested arbitrarily deep within child nodes to allow for these representations to be defined.
### Caching ###
RABL ha il supporto integrato per il caching dei template che sfrutta le strategie di fragment caching. Si noti che il caching è attualmente **disponibile solo** per Rails, ma il supporto per altri framework è previsto in una versione futura. L'uso più semplice del caching è:```ruby
# app/views/users/show.json.rabl
object @quiz
cache @quiz # key = rabl/quiz/[cache_key]
attribute :title
La memorizzazione nella cache può accelerare significativamente il rendering dei template RABL in produzione ed è fortemente raccomandata quando possibile. Per uno sguardo più dettagliato alla cache, consulta la guida Caching sul wiki.
Ci sono situazioni in cui un'applicazione richiede che i template RABL vengano renderizzati al di fuori di un contesto di vista tradizionale. Ad esempio, per renderizzare RABL all'interno di un task Rake o per creare payload per code di messaggi. In questo caso, si può usare Rabl.render come mostrato di seguito:```ruby
Rabl.render(object, template, :view_path => 'app/views', :format => :json) #=> "{...json...}"
Puoi utilizzare i metodi di convenienza su `Rabl::Renderer` per renderizzare gli oggetti anche:```ruby
Rabl::Renderer.json(@post, 'posts/show')
Rabl::Renderer.xml(@post, 'posts/show')
Questi metodi consentono di utilizzare RABL per conversioni arbitrarie di un oggetto in un formato desiderato.```ruby Rabl::Renderer.new('posts/show', @post, :view_path => 'app/views', :format => 'hash').render
Puoi anche passare altre variabili di istanza da utilizzare nel tuo template come:```ruby
Rabl::Renderer.new('posts/show', @post, :locals => { :custom_title => "Hello world!" })
Quindi, nel tuo template, puoi usare @custom_title come:```
attribute :content
node(:title) { @custom_title }
### Intestazioni del Tipo di Contenuto ###
Attualmente in RABL, il content-type della risposta non viene impostato automaticamente. Questo perché RABL è pensato
per funzionare con qualsiasi framework basato su Rack ed è il più possibile agnostico rispetto al formato.
Controlla [questo issue](https://github.com/nesquena/rabl/issues/185#issuecomment-4501232) per maggiori
dettagli, e se hai idee o patch, fammi sapere.
Nel frattempo, assicurati di impostare i content-type appropriati se necessario. Questo è di solito abbastanza semplice sia in
Rails che in Padrino. Raccomando un before_filter su quel controller o specificato direttamente in un'azione.
## Risorse ##
Ci sono molte risorse disponibili relative a RABL, tra cui il [RABL Wiki](https://github.com/nesquena/rabl/wiki),
e molti tutorial e guide elencati di seguito.
Puoi dare un'occhiata anche al [RABL Site](http://nesquena.github.com/rabl).
### Utilizzo Avanzato ###
Link a risorse per l'utilizzo avanzato:
* [Gestire la Complessità](https://github.com/nesquena/rabl/wiki/Managing-complexity-with-presenters)
* [Ottimizzazioni di Produzione](https://github.com/nesquena/rabl/wiki/Rabl-In-Production)
* [Integrazione con Grape](https://github.com/nesquena/rabl/wiki/Using-Rabl-with-Grape)
* [Rendering JSON per una struttura ad albero utilizzando RABL](https://github.com/nesquena/rabl/issues/70)
* [Layout (erb, haml e rabl) in RABL](https://github.com/nesquena/rabl/wiki/Using-Layouts)
* [Integrazione con Backbone o Ember.js](https://github.com/nesquena/rabl/wiki/Backbone-Integration)
* [RABL con Rails Engines](https://github.com/nesquena/rabl/wiki/Setup-rabl-with-rails-engines)
Per favore aggiungi i tuoi utilizzi e fammi sapere così possiamo aggiungerli qui! Inoltre, assicurati di dare un'occhiata
al [RABL Wiki](https://github.com/nesquena/rabl/wiki) per altri utilizzi.
### Tutorial ###
I tutorial possono sempre essere utili quando si inizia:
* [Railscasts #322](http://railscasts.com/episodes/322-rabl) - Ryan Bates spiega RABL
* [BackboneRails](http://www.backbonerails.com/) - Ottimi screencast di Brian Mann
* [Creare un'API con RABL e Padrino](http://blog.crowdint.com/2012/10/22/rabl-with-padrino.html)
* http://blog.joshsoftware.com/2011/12/23/designing-rails-api-using-rabl-and-devise/
* http://engineering.gomiso.com/2011/06/27/building-a-platform-api-on-rails/
* http://blog.lawrencenorton.com/better-json-requests-with-rabl
* http://www.rodrigoalvesvieira.com/developing-json-api-rails-rabl/
* http://tech.favoritemedium.com/2011/06/using-rabl-in-rails-json-web-api.html
* http://seesparkbox.com/foundry/better_rails_apis_with_rabl
* http://blog.dcxn.com/2011/06/22/rails-json-templates-through-rabl
* http://teohm.github.com/blog/2011/05/31/using-rabl-in-rails-json-web-api
Fammi sapere se c'è qualche altra risorsa utile non elencata qui.
### Librerie Correlate ###
Ci sono altre librerie che possono complementare o estendere le funzionalità di RABL:
* [versioncake](https://github.com/bwillis/versioncake) - Ottima libreria per versionare facilmente le tue API RABL
* [gon](https://github.com/gazay/gon) - Espone le tue variabili Rails in JS con supporto RABL integrato.
* [rabl-rails](https://github.com/ccocchi/rabl-rails) - Reimplementazione per RABL e Rails
[focalizzata sulla velocità](https://github.com/ccocchi/rabl-benchmark/blob/master/BENCHMARK).
Fammi sapere se c'è qualche altra libreria correlata non elencata qui.
### Risoluzione dei Problemi ###
* [Chiamate ridondanti per una collezione](https://github.com/nesquena/rabl/issues/142#issuecomment-2969107)
* [Test delle Viste RABL](https://github.com/nesquena/rabl/issues/130#issuecomment-4179285)
### Esempi ###
Vedi la directory [examples](https://github.com/nesquena/rabl/tree/master/examples).
## Problemi ##
Controlla la scheda [Issues](https://github.com/nesquena/rabl/issues) per un elenco completo:
* Benchmark rigorosi e ottimizzazioni delle prestazioni
## Autori e Collaboratori ##
Grazie a [Miso](http://gomiso.com) per avermi permesso di creare questo per le nostre applicazioni e rilasciare il progetto!
* [Nathan Esquenazi](https://github.com/nesquena) - Creatore del progetto
* [Arthur Chiu](https://github.com/achiu) - Core Maintainer, Guru del Testing con Riot
* [Tim Lee](https://github.com/timothy1ee) - RABL è stato un grande nome scelto dal CTO di Miso.
* [David Sommers](https://github.com/databyte) - Risoluzione dei template, supporto alla cache e molto altro
* [Rick Thomas](https://github.com/rickthomasjr) - Aggiunte opzioni per extends e test con Sinatra
* [Benjamin Yu](https://github.com/byu) - Aggiunto supporto al formato msgpack
* [Chris Kimpton](https://github.com/kimptoc) - Aiuto con la documentazione e il wiki
* [Marjun](https://github.com/mpagalan) - Aggiunte configurazioni per le opzioni xml
* [Anton Orel](https://github.com/skyeagle) - Aggiunta compatibilità con Rails 3.1
* [Sasha Koss](https://github.com/kossnocorp) - Aggiunto supporto multi_json
* [Matthew Schulkind](https://github.com/mschulkind) - Pulizia della configurazione e dei test
* [Luke van der Hoeven](https://github.com/plukevdh) - Supporto per oggetti non ORM nei template
* [Andrey Voronkov](https://github.com/Antiarchitect) - Aggiunto supporto al formato BSON
* [Alli Witheford](https://github.com/alzeih) - Aggiunto supporto al formato Plist
* [Ryan Bigg](https://github.com/radar) - Migliorato il codice di risoluzione dei template
* [Ivan Vanderbyl](https://github.com/ivanvanderbyl) - Aggiunto renderer per scopi generali
* [Cyril Mougel](https://github.com/shingara) - Aggiunto supporto pluggabile per cache_engine e miglioramenti al renderer
* [Teng Siong Ong](https://github.com/siong1987) - Migliorata l'interfaccia del renderer
* [Brad Dunbar](https://github.com/braddunbar) - Passa l'oggetto corrente nei blocchi
e molti altri contributori elencati nel [CHANGELOG](https://github.com/nesquena/rabl/blob/master/CHANGELOG.md).
Vuoi contribuire con il supporto per un altro formato?
Dai un'occhiata alle patch per [supporto msgpack](https://github.com/nesquena/rabl/pull/69), [supporto plist](https://github.com/nesquena/rabl/pull/153) e
[supporto BSON](https://github.com/nesquena/rabl/pull/163) come riferimento.
Per favore fai un fork e contribuisci, qualsiasi aiuto per migliorare questo progetto è apprezzato!
Questo progetto è un membro del [OSS Manifesto](http://ossmanifesto.org).
## Ispirazioni ##
Ci sono alcune eccellenti librerie che hanno aiutato a ispirare RABL e sono elencate qui sotto:
* [Tequila](https://github.com/inem/tequila)
* [JSON Builder](https://github.com/dewski/json_builder)
* [Argonaut](https://github.com/jbr/argonaut)
Grazie ancora per tutti questi grandi progetti.
## Copyright ##
Copyright © 2011-2012 Nathan Esquenazi. Vedi [MIT-LICENSE](https://github.com/nesquena/rabl/blob/master/MIT-LICENSE) per i dettagli.