Rails 4 and grape - undefined method `call' when splitting API file - ruby-on-rails

I've got a vanilla rails 4 application and I'm trying to add a versioned Grape API. The rails server starts up fine, but when I try to access the API URL (http://localhost:3000/v1/user/ping), I get the error:
undefined method `call' for V1:Module
So far, the API I have setup is very simple, but I can't figure out why it is not working
root/app/api/api.rb:
# root/app/api/api.rb
class API < Grape::API
mount V1
end
Within the version folder, I want to have all the classes that the version of the API supports: root/app/api/v1/user.rb:
# root/app/api/v1/user.rb
module V1
class user < Grape::API
get :ping do
{ :ping => params[:pong] || 'pong' }
end
end
end
root/config/routes:
TestApp::Application.routes.draw do
mount API => '/'
end

I split my api up into folders:
v1/resources/users.rb
v1/resources/orders.rb
v1/entities/order.rb
v2/resources/orders.rb
and then in api.rb just mount the individual files ...
mount V1::Resources::Users
mount V1::Resources::Orders
mount V2::Resources::Orders
And then:
version ['v2','v1'], cascade: true
version 'v2', cascade: true

Related

grape-swagger undefined method `[]' for nil:NilClass

I'm using grape to build my restful API, but when I try to integrate it with Swagger via grape-swagger gem, it throws
undefined method `[]' for nil:NilClass
when I visit http://localhost:3000/swagger_doc url
Here is my gem versions:
rails (4.2.4)
grape (0.8.0)
grape-swagger (0.20.0)
And here is my directory structure & files:
api/
api/base.rb
api/graduates.rb
// base.rb
module API
class Base < Grape::API
mount API::Graduates
add_swagger_documentation
end
end
// graduates.rb
module API
class Graduates < Grape::API
resource :graduates do
desc 'wow'
get :all do
Graduate.all
end
end
end
end
In my routes file, I am just mounting the grape api base.
Rails.application.routes.draw do
mount API::Base, at: "/"
end
A detail for debug purposes: when I delete resource block from graduates.rb, swagger_doc url seems fine(but of course, without resources).
For anyone who encounter this issue, here is the answer:
As compatibility table says, grape (0.8.0) and grape-swagger (0.20.0) are not compatible with each other. This is solved when I use grape (0.16.2).

Rails, Grape entity throws: uninitialized constant Grape::Entity

In rails project, I made api folder and I added this code to my application.rb file:
config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb')
config.autoload_paths += Dir[Rails.root.join('app', 'api', '*')]
In my api folder I have created game_server.rb file:
module GameServer
module Entities
class Test < Grape::Entity
expose :id
end
end
class API < Grape::API
version 'v1', using: :path
prefix :api
format :json
get :details do
present Basis.all, with: GameServer::Entities::Test
end
end
end
All code inside GameServer module. When I hit http://localhost:3000/api/v1/details in my browser I het this error:
uninitialized constant Grape::Entity.
I even tried to put my Entities module in other file, still does not work.
WHY?
You are using old version of grape, change your grape version:
gem 'grape', '~> 0.11.0'
You can refer to this repository: https://github.com/philcallister/rails-grape-entity
Just add
gem 'grape'
gem 'grape-entity'
into your Gemfile

Grape::API – Unable to autoload constant Base, expected /app/api/v1/base.rb to define it (LoadError)

I need some help to get Grape::API up and running with Rails 4.
I get a Unable to autoload constant Base even though a puts tells me that the class is loaded.
What am I doing wrong?
app/api/api.rb
class API < Grape::API
prefix 'api'
format :json
default_format :json
mount V1::Base # Everything loads perfectly until I add this line.
end
app/api/v1/base.rb
module V1
class Base < API
puts "=== DEBUG - in Base"
version 'v1', using: :path, vendor: 'orwapp', cascade: false
mount Users
end
end
$ rspec spec/api
12:58:29 - INFO - Run all
12:58:29 - INFO - Running all specs
=== DEBUG - in Base
/dependencies.rb:481:in `load_missing_constant':
Unable to autoload constant Base,
expected /Users/martins/Work/myapp/app/api/v1/base.rb to define it (LoadError)
from /Users/martins/Work/myapp/app/api/api.rb:9:in `<class:API>'
from /Users/martins/Work/myapp/app/api/api.rb:3:in `<top (required)>'
spec/api/users_spec.rb
describe 'GET /api/v1/users/:id', focus: true do
let(:user) { Fabricate :user }
it 'returns that specific user' do
get "/api/v1/users/#{ user.id }", {}, https_and_authorization
response.status.should eq 200
parse_response_for(:user)['email'].should eq user.email
end
end
The versions I'm using
$ ack grape Gemfile.lock
remote: git://github.com/intridea/grape.git
grape (0.9.1)
grape-entity (0.4.4)
grape-swagger (0.8.0)
grape
grape-entity
Try having Base inherit from Grape::API instead of API:
module V1
class Base < Grape::API
...
By having it inherit from API you're creating a circular dependency: The interpreter can't know the definition of V1::Base until it knows the definition of API, but for that it would first need to know the definition of V1::Base, and so on.
Changing to mount ::V1::Base fixed it.

Why am I getting "Unable to autoload constant" with Rails and grape?

I want to do an API for an Android app. When searching, I found {grape}. I'm following this tutorial, but I have a problem launching the Rails server:
=> Booting WEBrick
=> Rails 4.0.2 application starting in development on http://0.0.0.0:80
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
Exiting
C:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activesupport-4.0.2/lib/act
ive_support/dependencies.rb:464:in `load_missing_constant': Unable to autoload c
onstant Usuarios, expected C:/Sites/appCerca/app/api/v1/usuarios.rb to define it
(LoadError)
My directory:
app
..api
....api.rb
....v1
......root.rb
......usuarios.rb
and the files:
#application.rb
module AppCerca
class Application < Rails::Application
config.paths.add "app/api", glob: "**/*.rb"
config.autoload_paths += Dir["#{Rails.root}/app/api/*"]
end
end
#routes.rb
AppCerca::Application.routes.draw do
mount API::Root => '/'
[...]
#app/api/root.rb
module API
class Root < Grape::API
prefix 'api'
mount API::V1::Root
end
end
# app/api/v1/root.rb
module API
module V1
class Root < Grape::API
mount API::V1::Usuarios
end
end
end
# app/api/v1/usuarios.rb
module API
module V1
class Usuarios < Grape::API
version 'v1'
format :json
resource :usuarios do
desc "Return list of authors"
get do
Usuario.all
end
end
end
end
end
Why am I getting this error? I am using Ruby 1.9.3p484 and Rails-4.0.2.
Try either
Moving your API code's files from app/api to app/api/api, or
Moving your API classes outside the API module (i.e. deleting all the module API lines and their corresponding end statements).
From Grape's documentation:
Place API files into app/api. Rails expects a subdirectory that matches the name of the Ruby module and a file name that matches the name of the class. In our example, the file name location and directory for Twitter::API should be app/api/twitter/api.rb.
Thus the correct location for your API::Root class would actually be app/api/api/root.rb.
With this change your code starts and works fine for me on Rails 4.0.2.

Rails Engine add middleware to host app only

I am developing a gem which is also a Rails::Engine
I would like the engine to add a custom middleware to the host application and I have done that with the following code
module MyModule
class Engine < ::Rails::Engine
isolate_namespace MyModule
initializer "my_gem.middleware" do |app|
app.config.app_middleware.use "MyModule::MyMiddleware"
end
end
end
However this also adds the middleware to those routes defined in the routes.rb file of the Engine. How can I avoid this? I only want the middleware to be added to the host app.
For example, consider the following routes defined in the host application
Rails.application.routes.draw do
mount MyModule::Engine => "/engine"
root :to => Proc.new { |env| [200, {'Content-Type' => 'text/html'}, ["Hello World"]] }
end
Everything under /engine should NOT go through MyMiddleware
I am probably going down the wrong path to achieve this and may be I should look at some other solution?
I don't see how you can do that without putting it in the engine. The initializer is run on boot. You could create an URL matcher in your middleware to skip whatever it does if url is /engine. Note that I had to use app.config.middleware.use, not app.config.app_middleware.use

Resources