EzDevInfo.com

grape

An opinionated micro-framework for creating REST-like APIs in Ruby. Ruby Grape | An opinionated micro-framework for creating REST-like APIs in Ruby.

Disable automatic download for Groovy grapes

A sample script ss.groovy:

@Grab(group='org.codehaus.groovy.modules.http-builder', 
      module='http-builder', 
      version='0.5.0')
import groovyx.net.http.HTTPBuilder

println('done')

for some reason takes ~25 seconds to load when run with

groovy ss.groovy

and ~5 seconds when run with

groovy -Dgroovy.grape.autoDownload=false ss.groovy

as per this StackOverflow explanation. I tried doing manual initialization with

Grape.enableAutoDownload = false
Grape.grab(group:'org.codehaus.groovy.modules.http-builder', 
           module:'http-builder',
           version:'0.5.0')
import groovyx.net.http.HTTPBuilder
println('done')

but this fails on import with:

/tmp/ss.groovy: 3: unable to resolve class groovyx.net.http.HTTPBuilder
 @ line 3, column 1.
  import groovyx.net.http.HTTPBuilder
  ^

Is there a contained way to either:

  • Make it not download the artifacts automatically (preferred, as it allows for solving other issues, e.g. external site down while an artifact already exists in the local cache)
  • Make it startup faster in any other way

By contained I mean that all additional instructions should be either within script or, if no such one exists, an acceptable default (e.g. don't check the cached artifacts for updates - I would still, however, like to have automatic downloads globally) to be put in some of groovy config files (e.g. ~/.groovy/grapeConfig.xml or similar).


Source: (StackOverflow)

Grape get username:password from BasicAuth

I'm starting to build a really small API and I need to authenticate some endpoints, not all of them. I want to be able to select which endpoint to force authentication with an authenticate! method to be called in the body of the 'route'.

For example:

resource :groups do
    desc 'List all groups.'
    get do
      authenticate!
      { groups: "list of groups v1"}
    end
end

I have this working. I used a helper where I manually get the base64 encoded data from the header using: request.env["HTTP_AUTHORIZATION"]. I decode that data and check against the database if the user and secret belongs to a registered user. This is working fine, but I want to use Grape's helper to avoid all the base64 decoding etc etc:

http_basic do |username, password|
end

My idea is inside that method always return true, assign username and password to @username and @password and have a helper that grabs those variables and check against the db. All that works fine, the problem is that for routes that doesn't require authentication as the 'Authorization' header is empty the popup asking for password appears, and I want to avoid that. Is there a way to use the helper to do what I want to do??

BTW: I'm using grape mounted on rails-api

Thanks!


Source: (StackOverflow)

Advertisements

Stubbing Grape helper

I have Rails app with Grape API.

The interface is done with Backbone and Grape API provides it all data.

All it returns is user-specific stuff, so i need reference to currently logged in user.

Simplified version looks like this:

API initialization:

module MyAPI
  class API < Grape::API
    format :json

    helpers MyAPI::APIHelpers

    mount MyAPI::Endpoints::Notes
  end
end

Endpoint:

module MyAPI
  module Endpoints
    class Notes < Grape::API
      before do
        authenticate!
      end

      # (...) Api methods
    end
  end
end

API helper:

module MyAPI::APIHelpers
  # @return [User]
  def current_user
    env['warden'].user
  end

  def authenticate!
    unless current_user
      error!('401 Unauthorized', 401)
    end
  end
end

So, as you can see, i get the current user from Warden and it works fine. But the problem is with testing.

describe MyAPI::Endpoints::Notes do
  describe 'GET /notes' do
    it 'it renders all notes when no keyword is given' do
      Note.expects(:all).returns(@notes)
      get '/notes'
      it_presents(@notes)
    end
  end
end

How can I stub helpers's method *current_user* with some specific user?

I tried:

  • setting env/request, but it doesn't exist before calling get method.
  • stubbing MyAPI::APIHelpers#current_user method with Mocha
  • stubbing MyAPI::Endpoints::Notes.any_instance.stub with Mocha

Edit: At the moment, it's stubbed this way:

spec:

  # (...)
  before :all do
    load 'patches/api_helpers'
    @user = STUBBED_USER
  end
  # (...)

spec/patches/api_helpers.rb:

STUBBED_USER = FactoryGirl.create(:user)
module MyAPI::APIHelpers
  def current_user
    STUBBED_USER
  end
end

But it's definitely not the answer :).


Source: (StackOverflow)

Groovy grapes freeze after downloading artifacts

After updating my ubuntu system I have problem to run groovy grapes scripts. All dependecies are download but process is still running in about 100 %

I have ubuntu :

lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 12.10
Release:    12.10
Codename:   quantal

groovy version:

Groovy Version: 1.8.6 JVM: 1.7.0_25 Vendor: Oracle Corporation OS: Linux

My simple script look like:

@Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.6')
@GrabExclude('asm:*')

import groovyx.net.http.*
import groovy.util.CliBuilder
import groovy.xml.XmlUtil

import java.util.regex.Matcher;
import java.util.regex.Pattern;


class MyGroovyScript {

static main(args) {
    println "?????"
} 

}

and output is:

groovy -Dgroovy.grape.report.downloads=true my-groovy-script.groovy
Resolving dependency: org.codehaus.groovy.modules.http-builder#http-builder;0.6 {default=[default]}
Preparing to download artifact org.codehaus.groovy.modules.http-builder#http-builder;0.6!http-builder.jar
Preparing to download artifact org.apache.httpcomponents#httpclient;4.2.1!httpclient.jar
Preparing to download artifact net.sf.json-lib#json-lib;2.3!json-lib.jar
Preparing to download artifact org.codehaus.groovy#groovy;1.8.8!groovy.jar
Preparing to download artifact net.sourceforge.nekohtml#nekohtml;1.9.16!nekohtml.jar
Preparing to download artifact xml-resolver#xml-resolver;1.2!xml-resolver.jar
Preparing to download artifact org.apache.httpcomponents#httpcore;4.2.1!httpcore.jar
Preparing to download artifact commons-logging#commons-logging;1.1.1!commons-logging.jar
Preparing to download artifact commons-codec#commons-codec;1.6!commons-codec.jar
Preparing to download artifact commons-beanutils#commons-beanutils;1.8.0!commons-beanutils.jar
Preparing to download artifact commons-collections#commons-collections;3.2.1!commons-collections.jar
Preparing to download artifact commons-lang#commons-lang;2.4!commons-lang.jar
Preparing to download artifact net.sf.ezmorph#ezmorph;1.0.6!ezmorph.jar
Preparing to download artifact antlr#antlr;2.7.7!antlr.jar
Preparing to download artifact xerces#xercesImpl;2.9.1!xercesImpl.jar
Preparing to download artifact xml-apis#xml-apis;1.3.04!xml-apis.jar
Downloaded 9854 Kbytes in 134ms:
  [SUCCESSFUL ] org.codehaus.groovy.modules.http-builder#http-builder;0.6!http-builder.jar (5ms)
  [SUCCESSFUL ] org.apache.httpcomponents#httpclient;4.2.1!httpclient.jar (7ms)
  [SUCCESSFUL ] org.apache.httpcomponents#httpcore;4.2.1!httpcore.jar (2ms)
  [SUCCESSFUL ] commons-logging#commons-logging;1.1.1!commons-logging.jar (1ms)
  [SUCCESSFUL ] commons-codec#commons-codec;1.6!commons-codec.jar (2ms)
  [SUCCESSFUL ] net.sf.json-lib#json-lib;2.3!json-lib.jar (2ms)
  [SUCCESSFUL ] commons-beanutils#commons-beanutils;1.8.0!commons-beanutils.jar (3ms)
  [SUCCESSFUL ] commons-collections#commons-collections;3.2.1!commons-collections.jar (5ms)
  [SUCCESSFUL ] commons-lang#commons-lang;2.4!commons-lang.jar (2ms)
  [SUCCESSFUL ] net.sf.ezmorph#ezmorph;1.0.6!ezmorph.jar (24ms)
  [SUCCESSFUL ] org.codehaus.groovy#groovy;1.8.8!groovy.jar (34ms)
  [SUCCESSFUL ] antlr#antlr;2.7.7!antlr.jar (5ms)
  [SUCCESSFUL ] net.sourceforge.nekohtml#nekohtml;1.9.16!nekohtml.jar (2ms)
  [SUCCESSFUL ] xerces#xercesImpl;2.9.1!xercesImpl.jar (14ms)
  [SUCCESSFUL ] xml-apis#xml-apis;1.3.04!xml-apis.jar (3ms)
  [SUCCESSFUL ] xml-resolver#xml-resolver;1.2!xml-resolver.jar (2ms)

Source: (StackOverflow)

Rack apps mounted in different subdomains

I'm building a Grape API alongside Sinatra. So far I've been mounting them in separate routes like this:

run Rack::URLMap.new("/" => Frontend::Server.new,
                     "/api" => API::Server.new)

Where the "/api" is served by a Grape app and "/" by a Sinatra app. But I wanted to use subdomains to separate those concerns instead of the actual "sub-URL". Any clues on how to do this?

Thanks in advance for the help.


Source: (StackOverflow)

Can I avoid using Grape to load modules in Groovy?

I am writing my first automation script in groovy and I've hit a roadblock. While making use of the AntBuilder class to run sshexec() I run into the following error:

: Problem: failed to create task or type sshexec
Cause: the class org.apache.tools.ant.taskdefs.optional.ssh.SSHExec was not found.
    This looks like one of Ant's optional components.
Action: Check that the appropriate optional JAR exists in
    -ANT_HOME\lib
    -the IDE Ant configuration dialogs

Do not panic, this is a common problem.
The commonest cause is a missing JAR.

This is not a bug; it is a configuration problem

So far the best solution I've found for this is to use

Grape.grab(group : "com.jcraft", module : "jsch", classLoader : this.class.classLoader.rootLoader)
Grape.grab(group:"ant", module:"ant-jsch", classLoader:this.class.classLoader.rootLoader)

in order to load the required modules. However, I would like to eliminate the lag time of Grape downloading the jars from the remote Maven repository.

Is there a way to download and save modules for future use, perhaps in the JAVA_PATH or something to that effect?


Source: (StackOverflow)

Resolve all ActiveRecord Associations using Grape::Entity (SQL Join)

Question

I've been messing with ruby, grape, grape-entity, and activerecord. Everything is going swimmingly however I can't see to get the desired result from grape-entity when using the using keyword for a expose item.

My goal is to basically resolve all my activerecord associations, and then return the resulting JSON. This way I have a complete object for presentation for my configurations API method.

If you need more information, please ask i'll happily provide anything and everything.

Notes: I am using rackup as my server, i'm not using rails at all.

Classes

console_game.rb

class ConsoleGame < ActiveRecord::Base
  self.table_name = 'console_game'
  self.primary_key = :id

  has_many :configurations, :class_name => 'Configuration'

  class Entity < Grape::Entity
    expose :id
    expose :value, :as => :console_game
  end
end

cloud_user.rb

class CloudUser < ActiveRecord::Base
    self.primary_key = :username

    has_many :configurations, :class_name => 'Configuration'
    has_many :favorites, :class_name => 'Favorite', :foreign_key => :username

    class Entity < Grape::Entity
      expose :username, :email, :first_name, :last_name
    end
end

device.rb

class Device < ActiveRecord::Base
    self.table_name = 'device'
    self.primary_key = :id

    has_many :configurations, :class_name => 'Configuration'

    class Entity < Grape::Entity
      expose :id
      expose :name, :as => :device
    end
end

console_system.rb

class ConsoleSystem < ActiveRecord::Base
    self.table_name = 'console_system'
    self.primary_key = :id

    has_many :configurations, :class_name => 'Configuration'

    class Entity < Grape::Entity
      expose :id
      expose :value, :as => :console_system
    end
end

configuration.rb

class Configuration < ActiveRecord::Base
  self.table_name = 'configuration'
  self.primary_key = :id

  belongs_to :console_system, :class_name => 'ConsoleSystem', primary_key: :id, foreign_key: :system_id
  belongs_to :cloud_user, :class_name => 'CloudUser', primary_key: :username, foreign_key: :creator
  belongs_to :device, :class_name => 'Device', primary_key: :id, foreign_key: :device_id
  belongs_to :console_game, :class_name => 'ConsoleGame', primary_key: :id, foreign_key: :console_game_id

  scope :by_system,->(system){
    system_ids = ConsoleSystem.where(value: system).pluck(:id)
    where(system_id: system_ids)
  }

  scope :by_user,->(user){
    user_ids = CloudUser.where(username: user).pluck(:username)
    where(creator: user_ids)
  }

  scope :by_device,->(device){
    device_ids = Device.where(name: device).pluck(:id)
    where(device_id: device_ids)
  }

  scope :by_game,->(game){
    game_ids = ConsoleGame.where(value: game).pluck(:id)
    where(console_game_id: game_ids)
  }

  class Entity < Grape::Entity
    expose :id
    expose :value
    expose :device_id, :as => :device, using: Device::Entity
    expose :system_id, :as => :console_system, using: ConsoleSystem::Entity
    expose :console_game_id, :as => :console_game, using: ConsoleGame::Entity
    expose :creator, :as => :creator, using: CloudUser::Entity
    expose :created_date
    expose :positive_votes
    expose :negative_votes
  end
end

Grape API

resource :configuration do
  desc "Returns all configurations."
  get do
    configs = Configuration.includes(:device, :console_system, :cloud_user, :console_game)
    present :data, configs, :with => Configuration::Entity
    present :status, "Success"
  end
end

Error

NoMethodError at /configuration undefined method `id' for 4:Fixnum

Ruby /Library/Ruby/Gems/2.0.0/gems/grape-entity-0.4.2/lib/grape_entity/entity.rb: in delegate_attribute, line 465 Web GET localhost/configuration

Removing :using to get it to "work"

configuration.rb

class Entity < Grape::Entity
    expose :id
    expose :value
    expose :device_id, :as => :device#, using: Device::Entity
    expose :system_id, :as => :console_system#, using: ConsoleSystem::Entity
    expose :console_game_id, :as => :console_game#, using: ConsoleGame::Entity
    expose :creator, :as => :creator#, using: CloudUser::Entity
    expose :created_date
    expose :positive_votes
    expose :negative_votes
end

JSON Result

{
    data: [
        {
            id: 1,
            value: "configuration data 1 example",
            device: 4,
            console_system: 1,
            console_game: 1,
            creator: "manster",
            created_date: null,
            positive_votes: 0,
            negative_votes: 0
        },
        {
            id: 2,
            value: "configuration data 2 example",
            device: 4,
            console_system: null,
            console_game: 2,
            creator: "Zombieguy",
            created_date: null,
            positive_votes: 0,
            negative_votes: 0
        },
        {
            id: 3,
            value: "configuration data 3 example",
            device: 4,
            console_system: null,
            console_game: 3,
            creator: "Justin13692",
            created_date: null,
            positive_votes: 0,
            negative_votes: 0
        }
    ],
    status: "Success"
}

Desired Result

{
    data: [
        {
            id: 1,
            value: "configuration data 1 example",
            device: {
                id: 4,
                device: "XIM Edge"
            },
            console_system: {
                id: 1,
                console_system: "Xbox 360"
            }
            console_game: {
                id: 1,
                console_game: "Gears of War 3"
            },
            creator: {
                username: "manster",
                email: null,
                first_name: null,
                last_name: null
            },
            created_date: null,
            positive_votes: 0,
            negative_votes: 0
        },
        {
            id: 2,
            value: "configuration data 2 example",
            device: {
                id: 4,
                device: "XIM Edge"
            },
            console_system: null,
            console_game: {
                id: 2,
                console_game: "Battlefield 3"
            },
            creator: {
                username: "Zombieguy",
                email: null,
                first_name: null,
                last_name: null
            },
            created_date: null,
            positive_votes: 0,
            negative_votes: 0
        },
        {
            id: 3,
            value: "configuration data 3 example",
            device: {
                id: 4,
                device: "XIM Edge"
            },
            console_system: null,
            console_game: {
                id: 3,
                console_game: "Call of Duty: Modern Warfare 3"
            },
            creator: {
                username: "Justin13692",
                email: null,
                first_name: null,
                last_name: null
            },
            created_date: null,
            positive_votes: 0,
            negative_votes: 0
        }
    ],
    status: "Success"
}

Source: (StackOverflow)

Grape: Rescue from invalid JSON

First:

I'm using grape for building my API (Rails 4). When someone is sending an invalid JSON body (e.g. forgot the last }), the following error is raised:

ActionDispatch::ParamsParser::ParseError (795: unexpected token at '{"foobar": 1234

')

I tried it with grapes rescue_from :all option, but this doesn't work. Inside the stacktrace, I don't see the grape gem involved. It seems that this error is thrown from actionpack:

  .gems/gems/actionpack-4.1.4/lib/action_dispatch/middleware/params_parser.rb:53:in `rescue in parse_formatted_parameters'
  .gems/gems/actionpack-4.1.4/lib/action_dispatch/middleware/params_parser.rb:32:in `parse_formatted_parameters'
  .gems/gems/actionpack-4.1.4/lib/action_dispatch/middleware/params_parser.rb:23:in `call'

But what would be the best way to catch those errors, return a 400: Bad Request errors, and include the unexpected token at '{"foobar": 1234 message inside the json response?

Second:

I tried to test this with RSpec, but didn't have any luck on sending a raw request with an invalid JSON. I tried it with

post "/my_route", '{some invalid json'

but this doesn't throw the error from above. I thought since Rails 4, the second parameter, passed as a string, is treated like the raw body?


Source: (StackOverflow)

How to grab a dependency and make it work with IntelliJ project?

I am trying to start a GroovyFX project within IntelliJ 12. However, I have not been able to get IntelliJ to compile and run the following simple script (for reproducing the problem in the simplest manner possible):

@Grab(group='org.codehaus.groovyfx', module='groovyfx', version='0.3.1')
import groovyx.javafx.GroovyFX
println GroovyFX.class.name

I used IntelliJ's support for Grape's Grab to add groovyfx as a dependency of my module (the jar is shown under "External Libraries" and the editor does not complain that the class is missing after that!) but still, when I run the script, it throws an error:

Groovyc: unable to resolve class groovyx.javafx.GroovyFX

I was able to get this script working in the GroovyConsole without much problem and as expected....

I tried grabbing another randomly chosen dependency (turned out to be a Spring library) and it worked straight out:

@Grab(group='org.springframework', module='spring', version='2.5.6')
import org.springframework.jdbc.core.JdbcTemplate
println JdbcTemplate.class.name

I can see no good reason why the Spring library should work, but not the GroovyFX library!!!!

I even double checked that the GroovyFx library had been actually downloaded, and it is there where it should be (under {user.home}/.groovy/grapes/{group}/{module}/jars/)

What can cause this weird and extremely frustrating problem??


Source: (StackOverflow)

Request to Grape API for rails block other requests

For my rails app I set up an API with gem Grape. I add a test post method that the code sleeps 10 seconds and returns {'status'=>'success'}. Everything works except that the API call seems to block all other requests sent to the server. Any other request will not be executed until this sleep 10 seconds api finishes. Any GET request from front end interface will be delayed. And if I simulate two api calls, it takes the second call 20 seconds (10 seconds for waiting the first one finishes) to finish. Please give advise on this.

The api.rb file looks like this:

module ProjectName
  module MyErrorFormatter
    def self.call message, backtrace, options, env
      { "status" => "Fail", "error_message" => message }.to_json
    end
  end

  class API < Grape::API

    format :json
    default_format :json
    prefix 'api'
    cascade false
    error_formatter :json, MyErrorFormatter
    helpers APIHelpers

    before do 
      authenticate!
    end

    post do
      if params[:action].present?
        p_url = format_url(params)
        redirect "/api/#{params[:action]}?key=#{params[:key]}#{p_url}"
      end
    end

    post 'test' do
      sleep(10)
      {'status'=>'success'}
    end
  end
end

I am using Rails 4.2.0


Source: (StackOverflow)

Grape error handling strategy?

I am using Grape and Rails to create a REST API. I have the basic architecture in place and I am looking for places to 'clean' things up. One of those places is the error handling/processing.

I am currently rescuing errors in the root.rb (GRAPE::API base class) file for the whole API. I format them and then send the error back via rack_response. Everything works find but the root.rb file is getting a bit bloated with all the errors being rescued and some of them have special parsing that needs to be done. I was wondering if anyone has developed a good strategy for error handling so that it can be moved out into it's own module and leave the root.rb (GRAPE::API base class) fairly lean.

I would really like to create a error processing module and define methods for each type of error, for example...

module API
 module ErrorHandler
   def record_not_found
     rack_response API::Utils::ApiErrors.new({type: e.class.name, message: 'Record not found'}).to_json, 404
   end
 end
end

Then in the root.rb file do something like this

module API
  class Root < Grape::API
    prefix 'api'
    format :json

    helpers API::ErrorHandler

    rescue_from ActiveRecord::RecordNotFound, with: :record_not_found # Use the helper method as the handler for this error
  end
end

Has anyone done something like this? I have been trying various flavors of the above strategy but I can't seem to get anything work.


Source: (StackOverflow)

grape-entity represent not working

I am using grape gem for API and grape-entity to generate responses.

Simple show/get request is responding fine like returning only data from ActiveRecord Object. Fine

When i try to include data from has_many relation it return all the data related to that object. Fine

But when I represent data like

post = Post.first
data = V1::Entities::PostEntities.represent(post, only: [:id, { comments: [:id, :body] }])
data.as_json

It should return something like this as per documentation:

{
  id: 1,
  comments: [{
    id: 1,
    body: 'example'
  }]
}

But it returns:

{
  id: 1,
  comments: [{
    id: 1,
    user_id: 1,
    body: 'example',
    created_at: 'some_timestamp',
    updated_at: 'also_some_timestamp',
    is_deleted: 0,
  }]
}

My PostEntities contains:

module V1
  module Entities
    class PostEntities < Grape::Entity
      expose :id
      expose :comments, with: V1::Entities::CommentEntities
    end
  end
end

My CommentEntities contains:

module V1
  module Entities
    class CommentEntities < Grape::Entity
      expose :id
      expose :user_id
      expose :body
      expose :created_at
      expose :updated_at
      expose :is_deleted
    end
  end
end

there is something wrong with represent method. i am not getting what the issue is?


Source: (StackOverflow)

how to get the remote ip (requester) on grape-api rails application

I have a working rails application with grape-gem working as an end point for some APIs in the application. I need to get the remote ip for the requester and return it back in the response. I could do that on regular controllers using

request.remote_ip

however, in grape calls, the 'request' is not a defined variable.

how can I get access to the remote ip on grape?


Source: (StackOverflow)

Groovy 1.8 @Grab fails unless I manually call grape resolve

When running a script that is using grape system to @Grab a dependency in the ibiblio repo, it fails till I manually call grape resolve from the command line. After that, it's in the local cache and the script runs fine.

Is there some other annotation that I need to use to get it to work the first time from the script? It feels kludgy to tell users to first "grape resolve" and then @Grab works.

This is the script, grabbing the jedis jar for redis:

#!/usr/bin/env groovy
@Grab('redis.clients:jedis:2.0.0')

import redis.clients.jedis.*

Jedis redis = new Jedis("localhost")

Which fails with this exception if I have a clean ~/.groovy/grapes cache:

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
General error during conversion: Error grabbing Grapes -- [unresolved dependency: redis.clients#jedis;2.0.0: ibiblio: unable to get resource for redis/clients#jedis;2.0.0: res=/redis/clients/jedis/2.0.0/jedis-2.0.0.pom: java.net.MalformedURLException: no protocol:  /redis/clients/jedis/2.0.0/jedis-2.0.0.pom]

It only runs once I execute grape resolve manually from the command line:

grape -V resolve redis.clients jedis 2.0.0

(part of the output shows it's downloading from ibiblio):

...
ibiblio: found md file for redis.clients#jedis;2.0.0
    => http://repo1.maven.org/maven2/redis/clients/jedis/2.0.0/jedis-2.0.0.pom (2.0.0)
downloading http://repo1.maven.org/maven2/redis/clients/jedis/2.0.0/jedis-2.0.0.pom ...
    ibiblio: downloading http://repo1.maven.org/maven2/redis/clients/jedis/2.0.0/jedis-2.0.0.pom
    ibiblio: downloading http://repo1.maven.org/maven2/redis/clients/jedis/2.0.0/jedis-2.0.0.pom.sha1
sha1 OK for http://repo1.maven.org/maven2/redis/clients/jedis/2.0.0/jedis-2.0.0.pom
    [SUCCESSFUL ] redis.clients#jedis;2.0.0!jedis.pom(pom.original) (1184ms)
...

After it's in the local cache, the script works fine with @Grab.

I have not manually added a ~/.groovy/grapeConfig.xml file so it's using the default one that comes with groovy. I'm using groovy 1.8:

groovy -v
Groovy Version: 1.8.0 JVM: 1.6.0_24

I tried adding this manually above the grab:

@GrabResolver(name='ibiblio', m2Compatible='true', root='http://repo1.maven.org/maven2/')

but that didn't help. Am I missing something?


Source: (StackOverflow)

Ruby Grape JSON-over-HTTP API, custom JSON representation

I have a small prototype subclass of Grape::API as a rack service, and am using Grape::Entity to present my application's internal objects.

I like the Grape::Entity DSL, but am having trouble finding out how I should go beyond the default JSON representation, which is too lightweight for our purposes. I have been asked to produce output in "jsend or similar" format: http://labs.omniti.com/labs/jsend

I am not at all sure what nature of change is most in keeping with the Grape framework (I'd like a path-of-least-resistance here). Should I create a custom Grape formatter (I have no idea how to do this), new rack middleware (I have done this in order to log API ins/outs via SysLog - but formatting seems bad as I'd need to parse the body back from JSON to add container level), or change away from Grape::Entity to e.g. RABL?

Example code ("app.rb")

require "grape"
require "grape-entity"

class Thing
  def initialize llama_name
    @llama_name = llama_name
  end
  attr_reader :llama_name
end

class ThingPresenter < Grape::Entity
  expose :llama_name
end

class MainService < Grape::API
  prefix      'api'
  version     'v2'
  format      :json
  rescue_from :all

  resource :thing do
    get do
      thing = Thing.new 'Henry'
      present thing, :with => ThingPresenter
    end
  end
end

Rackup file ("config.ru")

require File.join(File.dirname(__FILE__), "app")
run MainService

I start it up:

rackup -p 8090

And call it:

curl http://127.0.0.1:8090/api/v2/thing
{"llama_name":"Henry"}

What I'd like to see:

curl http://127.0.0.1:8090/api/v2/thing
{"status":"success","data":{"llama_name":"Henry"}}

Obviously I could just do something like

  resource :thing do
    get do
      thing = Thing.new 'Henry'
      { :status => "success", :data => present( thing, :with => ThingPresenter ) }
    end
  end

in every route - but that doesn't seem very DRY. I'm looking for something cleaner, and less open to cut&paste errors when this API becomes larger and maintained by the whole team


Weirdly, when I tried { :status => "success", :data => present( thing, :with => ThingPresenter ) } using grape 0.3.2, I could not get it to work. The API returned just the value from present - there is more going on here than I initially thought.


Source: (StackOverflow)