rails - grape api error calling classes for version-ed api - ruby-on-rails

I'm trying to call version specific classes for versioned api(rails-grape) and get error
NameError (uninitialized constant API::V1::XMLResponses):
09:23:36 web.1 | app/api/v1/base.rb
my directory structure
app/
api/
v1/
xmlresponses/
phonebook.rb
api.rb
v2/
xmlresponses/
api.rb
api.rb
api.rb
require 'v1/base.rb'
require 'v2/base.rb'
module API
class Base < Grape::API
mount API::V1 => '/'
mount API::V2 => '/v2/'
end
end
in v1/base.rb i access classes for this version of api
V1::XMLResponses::Phonebook::getall()
Please, could you tell me why do i get this error?
Thanks for your answer, I've created simple app that demonstrates how it's done https://github.com/Asmmund/grape_versioning

It could be simply something wrong in your module structure.
Maybe a missing require.
I would write something like this:
/foo
v1/
|_ responses/
| |_ time.rb
|
|_ base.rb
v2/
|
|_ base.rb
api.rb
config.ru
The files:
# api.rb`
require 'grape'
require './v1/base.rb'
require './v2/base.rb'
module FooBar
module API
class Base < Grape::API
mount API::V1 => '/'
mount API::V2 => '/v2/'
end
end
end
# v1/base.rb
require_relative './responses/time.rb'
module FooBar
module API
class V1 < Grape::API
get 'foo' do
"foo"
end
get 'time' do
API::Responses::Time.api_time
end
end
end
end
# v1/responses/time.rb
module FooBar
module API
module Responses
class Time
def self.api_time
"API time"
end
end
end
end
end
# v2/base.rb
module FooBar
module API
class V2 < Grape::API
get 'bar' do
"bar"
end
end
end
end
Then in config.ru
# config.ru
require './api.rb'
run FooBar::API::Base
Run with:
thin start
...
curl 0.0.0.0:3000/foo
=> foo
curl 0.0.0.0:3000/v2/bar
=> bar
curl 0.0.0.0:3000/time
=> API time

Related

Grape add new endpoint

I'm using Rails 6 with Grape as API. I'm pretty new in Grape and I'm trying to learn how to add new endpoint using Grape. The idea is to get Index endpoint which is nested in v1/users/index
Here is my structure:
app/
controllers/
api/
root.rb - API::Root
v1/
base.rb - API::V1::Base
users/
base.rb - API::V1::Users::Base
index.rb - API::V1::Users::Index
api/root.rb
module API
class Root < Grape::API
default_format :json
prefix :api
# exception handling
include Rescuers
# helpers
helpers ::API::Helpers::ParamsHelper
# core API modules
mount V1::Base
end
end
api/v1/base.rb:
module API
module V1
class Base < Root
version 'v1', using: :path
content_type :json, 'application/vnd.api+json'
# mount resource modules
mount V1::Users::Base
end
end
end
api/v1/users/base.rb:
module API
module V1
module Users
class Base < Grape::API
version 'v1', using: :path
content_type :json, 'application/vnd.api+json'
# mount resource modules
mount Users::Index
end
end
end
end
api/v1/users/index.rb:
module API
module V1
module Users
class Index < Grape::API
desc 'Test'
get do
head 200
end
end
end
end
end
Here are my routes:
Rails.application.routes.draw do
# API
scope :api do
mount API::Root, at: '/'
end
end
I want to have this index.rb in my routes as GET v1/users/index but when I type rake routes I don't see it. This should not do anything, I want to understand what is the core requirements when it comes to creation endpoint with Grape.

Add methods to a Rails engine model from a Rails plugin

I'm writing a Rails plugin to extend a Rails engine. Namely MyPlugin has MyEngine as a dependency.
On my Rails engine I have a MyEngine::Foo model.
I'd like to add new methods to this model so I created a file in my plugin app/models/my_engine/foo.rb which has the following code:
module MyEngine
class Foo
def sayhi
puts "hi"
end
end
end
If I enter the Rails console on the plugin dummy application I can find MyEngine::Foo, but runnning MyEngine::Foo.new.sayhi returns
NoMethodError: undefined method `sayhi'
Why MyPlugin cannot see the updates to MyEngine::Foo model? Where am I wrong?
Ok, found out. To make MyPlugin aware and able to modify MyEngine models the engine must be required on the plugin engine.rb like so:
require "MyEngine"
module MyPlugin
class Engine < ::Rails::Engine
isolate_namespace MyPlugin
# You can also inherit the ApplicationController from MyEngine
config.parent_controller = 'MyEngine::ApplicationController'
end
end
In order to extend MyEngine::Foo model I then had to create a file lib/my_engine/foo_extension.rb:
require 'active_support/concern'
module FooExtension
extend ActiveSupport::Concern
def sayhi
puts "Hi!"
end
class_methods do
def sayhello
puts "Hello!"
end
end
end
::MyEngine::Foo(:include, FooExtension)
And require it in config/initializers/my_engine_extensions.rb
require 'my_engine/foo_extension'
Now from MyPlugin I can:
MyEngine::Foo.new.sayhi
=> "Hi!"
MyEngine::Foo.sayhello
=> "Hello!"
See ActiveSupport Concern documentation for more details.

how to namespace in rails engine

I trying create a rails engine
Content default
lib/abc_xyz.rb
require 'abc_xyz/engine'
module AbcXyz
end
abc_xyz/engine.rb
module AbcXyz
class Engine < ::Rails::Engine
isolate_namespace AbcXyz
end
end
But, i want nested it in a namespace, as below:
lib/abc_xyz.rb
require 'abc/xyz/engine'
module Abc
module Xyz
end
end
abc/xyz/engine.rb
module Abc
module Xyz
class Engine < ::Rails::Engine
isolate_namespace Abc
end
end
end
but, rake abc:install:migrations not working for me
. How to do it?

Rails Grape, DRY Helpers call for shared params

Objective: Use grape Shared Params from a helper module, without having to add the syntax helpers Helper::Module on every mounted API.
Example code that works:
# /app/api/v1/helpers.rb
module V1
module Helpers
extend Grape::API::Helpers
params :requires_authentication_params do
requires :user_email, type: String
requires :authentication_token, type: String
end
end
end
# /app/api/api.rb
class API < Grape::API
format :json
version 'v1', using: :path
mount V1::A
mount V1::B
end
# /app/api/v1/a.rb
module V1
class A < Grape::API
helpers V1::Helpers
desc 'SampleA'
params do
use :requires_authentication_params
end
get 'sample_a/url' do
#...
end
end
end
# /app/api/v1/B.rb
module V1
class B < Grape::API
helpers V1::Helpers
desc 'SampleB'
params do
use :requires_authentication_params
end
get 'sample_b/url' do
#...
end
end
end
The problem arise when I try to move the helpers V1::Helpers call from A and B to the API class that mounts them, throwing the exception:
block (2 levels) in use': Params :requires_authentication_params not found! (RuntimeError)
As an interesting note, the module does get included, because if I add any instance method to the class V1::Helpers I can use them inside A and B.
So the question, What would be the best solution to DRY this and follow best practices?
What if you include V1::Helpers on API and then make A and B inherit from API? E.g:
# /app/api/api.rb
class API < Grape::API
include V1::Helpers
format :json
version 'v1', using: :path
mount V1::A
mount V1::B
end
class A < API
# ...
end
class B < API
# ...
end

Rails Grape api versioning module structure

I'm trying to implement api versioning, almost the same as I've done here . but i don't seem to get module/folder structure right in rails app, because I get error messages like V1 is not a module /app/api/v1/xml_responses/device.rb:3:in '<module:API>'
Directory structure
/app
/api
- api.rb
/v1
-base.rb
/xml_responces
- device.rb
api.rb
require 'v1/base.rb'
module API
class Base < Grape::API
mount API::V1 => '/v1/'
end
end
v1/base.rb
module API
module V1
class ApiV1 < Grape::API
require 'builder'
helpers DeviceMethods
prefix 'api'
version 'v1', using: :header
end
end
end
V1/xml_responses/device.rb
module API
module V1
module XMLResponses::Device
def self.do_something
#do_something
end
end
end
end
Routes.rb
mount API::Base => '/'
I can't figure out what i'm doing wrong! could you please help me?
I was having similar problems, but then stumbled on this great post that helped me get things to work, and had more complete information than I found elsewhere. See http://funonrails.com/2014/03/building-restful-api-using-grape-in-rails/
Looking at your code, this looks funny:
module XMLResponses::Device
def self.do_something
Do you mean to do something like this?
module API
module V1
module XMLResponses
class Device < Grape::API
resource :device do
get do { Device.all } # Or whatever
end
end
end
end
end
Make sure that you have this line in application.rb
config.paths.add "app/api", glob: "**/*.rb"
config.autoload_paths += Dir["#{Rails.root}/app/api/*"]
As suggested at grape wiki here.

Resources