Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API proof of concept: forums#show #665

Open
wants to merge 33 commits into
base: rails4
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
780197a
API proof of concept: forums#show
eostrom Jul 2, 2015
2df1654
Fixed bug when no API version is specified.
eostrom Jul 7, 2015
f0520c1
Include topics in /forum/:id API.
eostrom Jul 7, 2015
6080de5
JSON API compliance: relationships go inside data.
eostrom Jul 8, 2015
676b2f6
Added posts count and views count.
eostrom Jul 8, 2015
1d8d680
topics#show API: include last post.
eostrom Jul 9, 2015
7e8ad68
Allow topics to be created without first posts.
eostrom Jul 12, 2015
c5a78c3
Give API routes priority.
eostrom Jul 12, 2015
88ca5e7
Create Topic happy path.
eostrom Jul 12, 2015
aa614d9
Create Topic error handling.
eostrom Jul 12, 2015
87019aa
Lock Jbuilder against incompatible upgrades.
eostrom Jul 13, 2015
3b2ebb7
API: Added topics#show.
eostrom Jul 14, 2015
30d7dce
API: Include posts in topics#show.
eostrom Jul 15, 2015
a60d5d5
Removed accidentally duplicated specs.
eostrom Jul 15, 2015
3c867db
API: added posts#show.
eostrom Jul 15, 2015
95c9abf
API: include forum ID in post JSON.
eostrom Jul 17, 2015
dc751a3
API: Added posts#update.
eostrom Jul 17, 2015
054991a
Spec refactor: started abstracting API behavior.
eostrom Jul 17, 2015
bafbee5
Spec refactor: matchers for JSON API references.
eostrom Jul 19, 2015
b2684a8
API: Inherit from ForumsController.
eostrom Jul 19, 2015
5efb90f
API: Extracted JsonApiController module.
eostrom Jul 19, 2015
fe776c5
API: Added forum relationship to posts and topics.
eostrom Jul 20, 2015
b97d486
API: send user relationships, not ID attributes.
eostrom Jul 20, 2015
45b8ef9
API: Render included posts with a partial.
eostrom Jul 20, 2015
da075e8
Add topic slugs to JSON output.
eostrom Aug 18, 2015
70e0ffe
API: Don't list unmoderated topics.
eostrom Aug 25, 2015
92db379
Merged from rails4 into api branch.
eostrom Sep 8, 2015
0543130
Added created_at field to topics list.
eostrom Sep 16, 2015
21fa728
API: Added topic author ID to forums/show response.
eostrom Sep 17, 2015
6617ae2
API: Include latest post author in topic list.
eostrom Sep 17, 2015
fbb1e72
API: Reduced code duplication in topic views.
eostrom Sep 17, 2015
5991286
API: Hide unapproved posts from non-moderators.
eostrom Sep 17, 2015
b354f5b
Set last_post_at for topics with no posts.
eostrom Sep 29, 2015
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ gemspec
gem 'pry-rails'
gem 'pry-nav'
gem 'select2-rails', '~> 3.5.4'
gem 'jbuilder'

platforms :jruby do
gem "activerecord-jdbc-adapter", :require => false
Expand Down
13 changes: 13 additions & 0 deletions app/controllers/forem/api/v1/forums_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
require_dependency "forem/application_controller"

module Forem
module Api
module V1
class ForumsController < ApplicationController
load_and_authorize_resource :class => 'Forem::Forum', :only => :show

before_action { request.format = :json }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that this kind of request format setting could be done at the routes level but I can't find a solution that works. I tried coming up with my own and googling for one. Nothing that I tried works.

Instead, putting respond_to :json at the top of the controller works, but this requires the use of the responders gem (which is alright imo). I think this is a better method than forcing the request format this way.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

respond_to doesn't seem to address the problem I was trying to solve. The problem is that I'm using a custom MIME type (application/vnd.forem+json), as recommended in any number of blog posts, but because of that, Rails looks for a view named show.application/vnd.forem+json.jbuilder. I just wanted to call it show.json.jbuilder.

I tried Mime::Type.register 'application/vnd.forem+json', :json, which works, but I get a warning about initializing Mime::JSON twice. There doesn't seem to be a way to say "Just treat this MIME type as JSON, too." (register_alias doesn't do it.)

It looks like a solution is to register the MIME type as :forem and then rename the views to show.forem.jbuilder. But it seems like there should be a way to use .json.

end
end
end
end
24 changes: 24 additions & 0 deletions app/views/forem/api/v1/forums/show.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
json.data do
json.type "forums"
json.(@forum, :id)
json.attributes do
json.(@forum, :title, :slug)
end
end

json.relationships do
json.topics do
json.data @forum.topics do |topic|
json.type 'topics'
json.(topic, :id)
end
end
end

json.included @forum.topics do |topic|
json.type 'topics'
json.(topic, :id)
json.attributes do
json.(topic, :subject)
end
end
10 changes: 10 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require 'forem/api/version_routing_constraint'

Forem::Engine.routes.draw do
root :to => "forums#index"

Expand Down Expand Up @@ -48,4 +50,12 @@
end
end
end

namespace :api do
constraints Forem::API::VersionRoutingConstraint.new(1) do
scope module: :v1 do
resources :forums
end
end
end
end
1 change: 1 addition & 0 deletions forem.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ Gem::Specification.new do |s|
s.add_dependency 'select2-rails', '~> 3.5.4'
s.add_dependency 'friendly_id', '~> 5.0.0'
s.add_dependency 'cancancan', '~> 1.7'
s.add_dependency 'jbuilder'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would personally lock the jbuilder version here, just in case of a major version bump that changes things in a breaking way.

end
45 changes: 45 additions & 0 deletions lib/forem/api/version_routing_constraint.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
module Forem
module API
class VersionRoutingConstraint
def initialize(version)
@version = version
end

def matches?(request)
requested_this_version?(request) ||
# All real clients should specify an API version in their
# request headers, but for ease of debugging (via curl, browsers,
# etc.), the latest API version responds to requests that don't
# specify.
(no_requested_version?(request) && latest_version?)
end

private

def requested_this_version?(request)
requested_version(request) == @version
end

def no_requested_version?(request)
!requested_version(request)
end

def requested_version(request)
accept = request.headers['Accept']
accept &&
accept[/application\/vnd\.forem\+json; version=([0-9]+)/] &&
Integer($1)
end

# True if no later API version exists.
def latest_version?
"::Forem::Api::V#{@version + 1}".constantize
# if the above succeeds, this is not the latest version
false
rescue NameError
# no version beyond this one exists
true
end
end
end
end
49 changes: 49 additions & 0 deletions spec/requests/api/forums_api_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
require 'spec_helper'

describe 'Forums API', type: :request do
let(:forum) { create(:forum) }
let!(:topic) { create(:topic, forum: forum) }

def api(method, action, params = {})
send method, action, params,
Accept: 'application/vnd.forem+json; version=1'
end

describe '#show' do
before { api :get, api_forum_path(forum) }

let(:json) { JSON.parse(response.body).with_indifferent_access }
let(:data) { json[:data] }

it 'succeeds' do
expect(response).to be_success
end

it 'represents the forum' do
expect(data[:type]).to eq 'forums'
expect(data[:id]).to eq forum.id
expect(data[:attributes][:title]).to eq forum.title
expect(data[:attributes][:slug]).to eq forum.slug
end

let(:related_topics) { json[:relationships][:topics] }
let(:included_objects) { json[:included] }

it 'describes topic relationships' do
expect(related_topics[:data].length).to eq 1
related_topic = related_topics[:data].first

expect(related_topic[:type]).to eq 'topics'
expect(related_topic[:id]).to eq topic.id
end

it 'includes topic data' do
expect(included_objects.length).to eq 1
included_topic = included_objects.first

expect(included_topic[:type]).to eq 'topics'
expect(included_topic[:id]).to eq topic.id
expect(included_topic[:attributes][:subject]).to eq topic.subject
end
end
end