Created
June 28, 2018 16:08
-
-
Save JoshCheek/f43fc90eec99db4d767de0cd3fade4f9 to your computer and use it in GitHub Desktop.
Complex JSON API Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# SETUP DB | |
require 'active_record' | |
ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:' | |
# SCHEMA | |
ActiveRecord::Schema.define do | |
self.verbose = false | |
create_table :users do |t| | |
t.string :name | |
t.timestamps | |
end | |
create_table :posts do |t| | |
t.string :body | |
t.integer :author_id | |
t.timestamps | |
end | |
create_table :comments do |t| | |
t.string :body | |
t.integer :author_id | |
t.integer :post_id | |
t.timestamps | |
end | |
end | |
# MODELS | |
class User < ActiveRecord::Base | |
has_many :posts, foreign_key: :author | |
has_many :comments, foreign_key: :author | |
end | |
class Post < ActiveRecord::Base | |
belongs_to :author, class_name: 'User' | |
has_many :comments | |
end | |
class Comment < ActiveRecord::Base | |
belongs_to :post | |
belongs_to :author, class_name: 'User' | |
end | |
# DATA | |
josh = User.create! name: 'Josh' | |
yumin = User.create! name: 'Yumin' | |
gomez = User.create! name: 'Gomez' | |
Post.create! author: gomez, body: 'first' do |post| | |
post.comments.build author: josh, body: "first" | |
end | |
Post.create! author: josh, body: 'yo ho ho' do |post| | |
post.comments.build author: yumin, body: "yo yo ma" | |
post.comments.build author: gomez, body: "yo mama" | |
end | |
Post.create! author: josh, body: 'and a bottle of rum' | |
# JSON API RESOURCES | |
require 'jsonapi/serializable' | |
class SerializablePost < JSONAPI::Serializable::Resource | |
type 'post' | |
attributes :body | |
attribute(:date) { @object.created_at } | |
belongs_to :author | |
has_many :comments do | |
data { @object.comments } | |
link(:all) { @url_helpers.comment_posts_url(@object.id) } | |
meta { { count: @object.comments.count } } | |
end | |
link(:self) { @url_helpers.post_url(@object.id) } | |
meta { { featured: true } } | |
end | |
class SerializableComment < JSONAPI::Serializable::Resource | |
type 'comment' | |
attributes :body | |
attribute(:date) { @object.created_at } | |
belongs_to :author | |
belongs_to :post | |
link(:self) { @url_helpers.comment_url(@object.id) } | |
end | |
class SerializableUser < JSONAPI::Serializable::Resource | |
type 'user' | |
attributes :name | |
attribute(:joined) { @object.created_at } | |
has_many :posts | |
has_many :comments | |
link(:self) { @url_helpers.user_url(@object.id) } | |
end | |
# THEIR HELPERS | |
class MyUrlHelper | |
def post_url(id) "/posts/#{id}" end | |
def user_posts_url(id) "/posts?user=#{id}" end | |
def comment_posts_url(id) "/comments?post_id=#{id}" end | |
def comment_url(id) "/comments/#{id}" end | |
def user_url(id) "/users/#{id}" end | |
end | |
# RENDER A POST TO JSON (feels weird that it returns an array in included) | |
renderer = JSONAPI::Serializable::Renderer.new | |
renderer.render( | |
Post.first, | |
class: { User: SerializableUser, Comment: SerializableComment, Post: SerializablePost }, | |
expose: { url_helpers: MyUrlHelper.new }, | |
include: [:author, comments: [:author]], | |
fields: { users: [:name, :email] }, | |
) | |
# => {:data=> | |
# {:id=>"1", | |
# :type=>:post, | |
# :attributes=>{:body=>"first", :date=>2018-06-28 16:07:23 UTC}, | |
# :relationships=> | |
# {:author=>{:data=>{:type=>:user, :id=>"3"}}, | |
# :comments=> | |
# {:links=>{:all=>"/comments?post_id=1"}, | |
# :data=>[{:type=>:comment, :id=>"1"}], | |
# :meta=>{:count=>1}}}, | |
# :links=>{:self=>"/posts/1"}, | |
# :meta=>{:featured=>true}}, | |
# :included=> | |
# [{:id=>"3", | |
# :type=>:user, | |
# :attributes=>{:name=>"Gomez", :joined=>2018-06-28 16:07:23 UTC}, | |
# :relationships=> | |
# {:posts=>{:meta=>{:included=>false}}, | |
# :comments=>{:meta=>{:included=>false}}}, | |
# :links=>{:self=>"/users/3"}}, | |
# {:id=>"1", | |
# :type=>:comment, | |
# :attributes=>{:body=>"first", :date=>2018-06-28 16:07:23 UTC}, | |
# :relationships=> | |
# {:author=>{:data=>{:type=>:user, :id=>"1"}}, | |
# :post=>{:meta=>{:included=>false}}}, | |
# :links=>{:self=>"/comments/1"}}, | |
# {:id=>"1", | |
# :type=>:user, | |
# :attributes=>{:name=>"Josh", :joined=>2018-06-28 16:07:23 UTC}, | |
# :relationships=> | |
# {:posts=>{:meta=>{:included=>false}}, | |
# :comments=>{:meta=>{:included=>false}}}, | |
# :links=>{:self=>"/users/1"}}]} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment