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.
Related
I using Grape to create API and I have issue : How I can mounting V1 inside V2
/api/v1/users.rb
module API
module V1
class Users < Grape::API
resource :users do
desc "Timeline" do
end
get :time_line do
{status: true, version: 'v1'}
end
desc "Timeline" do
end
get :profile do
{status: true, profile: {email: "julian#vinova.sg"}, version: 'v1'}
end
end
end
end
end
/api/v1/base.rb
module API
module V1
class Base < Grape::API
prefix 'api'
format :json
version 'v1', using: :path
mount API::V1::Users
add_swagger_documentation \
api_version: 'v1'
end
end
end
/api/v2/users.rb
module API
module V2
class Users < Grape::API
resource :users do
desc "Timeline" do
end
params do
use :pagination
end
get :time_line do
{status: true, version: 'v2'}
end
end
end
end
end
/api/v2/base.rb
module API
module V2
class Base < Grape::API
prefix 'api'
format :json
version 'v2', using: :path
mount API::V2::Users
add_swagger_documentation \
api_version: 'v2'
end
end
end
/api/base.rb
module API
class Base < Grape::API
mount ::API::V1::Base
mount ::API::V2::Base
end
end
I want :profile(/api/v2/users/profile) to also be implemented in V2 without having to repeat the code. Now, any suggestions to do that ?
Thanks
I am using grape redtful-api. I am Unable to inherit common_params in Grape. I defined common
_params in class API1 and called it in API2 throws the error. How can I change the code to make this work?
module Example
class API1 < Grape::API
version 'v1'
format :json
prefix :api
resource :exc1 do
common_params = proc do
requires :param1
requires :param2
end
params(&common_params)
get :params_by_pair do
p1 = params[:param1]
p2 = params[:param2]
response = "https://www.example1.com/#{p1}_#{p2}"
end
end
end
end
module Example
class API2 < API1
version 'v1', using: :header, vendor: 'twitter'
format :json
prefix :api
resource :exc2 do
params(&common_params)
get :params_by_pair do
p1 = params[:param1]
p2 = params[:param2]
response = "https://www.example2.com/#{p1}_#{p2}"
end
end
end
end
The issue doesn't have much to do with Grape but rather the way variables' scope works in Ruby. common_params is just a local, it won't survive the end of the scope. You could make it work by using a class instance variable or similar but let's not go there. The way you're supposed to share helpers across different grapes is through a dedicated module.
module Example
module SharedHelpers
extend Grape::API::Helpers
params :common_params do
requires :param1
requires :param2
end
end
end
And now in the different grapes you need to "include" the module and use the helper.
module Example
class API1 < Grape::API
helpers SharedHelpers # !!!
version 'v1'
format :json
prefix :api
resource :exc1 do
params do
use :common_params # !!!
end
get :params_by_pair do
...
end
end
end
end
To use the helpers in the API2 grape, use the same technique.
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
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.
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