grape icon indicating copy to clipboard operation
grape copied to clipboard

Provide a generic interface for requires: complex type.

Open dblock opened this issue 11 years ago • 17 comments

http://pastebin.com/QQV0NJ5K

  # Entity
  module API
  module Entities
    class Article < Grape::Entity
      expose :title, documentation: { type: 'string', desc: 'Title' }
      expose :body, documentation: { type: 'string', desc: 'Body' }
    end
  end
end

  # API
  desc "Create an article"
  params do
    requires :article, type: API::Entities::Article, documentation: { example: "aklsdfj" }
  end
  post '/articles' do
    puts params
    article = Article.create(params(:title, :body))
    represent(article, env)
  end

Currently:

# curl -X POST -H "Content-Type:application/json" 0:9292/v1/articles -d '{"title":"hello","body":"world"}'  
# {"error":"article is missing"}
# curl -X POST -H "Content-Type:application/json" 0:9292/v1/articles -d '{"article":{"title":"hello","body":"world"}}'
# {"error":"article is invalid"}

dblock avatar Nov 28 '14 13:11 dblock

:+1:

antonzhyliuk avatar May 28 '15 18:05 antonzhyliuk

+1

dim avatar Jun 17 '15 16:06 dim

Acording to the documentation , it is supported (in a way, I guess).

0x5d avatar Jun 26 '15 14:06 0x5d

Hi, what's status of this issue? I wrote something like

    params do
      requires :user, type: Entities::User
    end

But when I pass a user json as parameter, it throws {"error":"user is invalid"}

It the result expected or I made some mistake?

birbird avatar Jul 18 '15 14:07 birbird

I believe https://github.com/intridea/grape/pull/1039 has implemented this, @rnubel would you confirm and I'll close this issue? Is this any different from #993?

dblock avatar Jul 18 '15 15:07 dblock

@birbird this is on HEAD FYI, not in any released version of Grape yet.

dblock avatar Jul 18 '15 15:07 dblock

Maybe we need to do something built-in for Grape entities though ...

dblock avatar Jul 18 '15 15:07 dblock

@dblock Thanks a lot for you help.

Actually, before I asked, I have tried exactly the same code with https://github.com/intridea/grape#custom-types, which is also the sample code in #1039. But got the {"error":"color is invalid"} sadly.

All the things can be explained with your reminder.

A little suggestion, if this feature has not been released, it should not be in the document.

birbird avatar Jul 18 '15 16:07 birbird

But even with custom-types, Grape Entity still could not be processd. custom-types require the input type is String, this is not the case for Entity.

birbird avatar Jul 18 '15 17:07 birbird

Yeah, like @birbird noted, #1039 added support for custom primitive types (i.e., something that can be parsed from a single string parameter) whereas this story requires support for complex types. And actually, grape does have support for that already, but only when done through Virtus. It would certainly be possible to also support coercion into Grape::Entitys, but that's not existing functionality.

rnubel avatar Jul 18 '15 18:07 rnubel

Is it possible to express required/optional parameters in entities ?

With a required: parameters ? Does it fail if the title in not passed in the following example ? Or is it just documentation ?

module API
  module Entities
    class Article < Grape::Entity
      expose :title, documentation: { type: 'string', desc: 'Title', required: true }
      expose :body, documentation: { type: 'string', desc: 'Body', required: false }
    end
  end
end

Can we express complex validations as with "normal" params ? ( https://github.com/intridea/grape/blob/v0.12.0/README.md#parameter-validation-and-coercion)

guizmaii avatar Jul 27 '15 11:07 guizmaii

I'm also wondering the exact same thing as @guizmaii. I have a Grape Entity with some required attributes but if I only use the desc block with params set to my Entity's documentation there isn't any validation being done on the params when i make requests to the API for those resources. The only way I can get validation of the params is to also use the separate params block like below...

This will validate the params:

desc 'Create a User.', {
    detail: 'Used to create a new User.',
    named: 'Create User',
    success: Entities::User,
    failure: [
        [400, 'Bad request', Entities::Error],
        [422, 'Bad parameter entry', Entities::Error]
    ],
    notes: <<-NOTE
      Creates a new User

      ## Request properties

      * _Safe:_ Yes
      * _Idempotent:_ No
      * _Can be retried:_ Yes
    NOTE
}
params do
  requires :email, type: String, desc: 'Email address.'
  requires :password, type: String, desc: 'Password.'
  requires :password_confirmation, type: String, desc: 'Password Confirmation.'
  optional :first_name, type: String, desc: 'Users first name.'
  optional :last_name, type: String, desc: 'Users last name.'
  optional :phone, type: Integer, desc: 'Users phone number.'
  optional :address, type: String, desc: 'Users address.'
  optional :address_two, type: String, desc: 'Users address line two.'
  optional :city, type: String, desc: 'Users city.'
  optional :state, type: String, desc: 'Users state.'
  optional :zip, type: Integer, desc: 'Users zip code.'
end
post do
  # stuff ...
end

This will not validate params:

desc 'Create a User.', {
    detail: 'Used to create a new User.',
    named: 'Create User',
    params: Entities::CreateUserParams.documentation,
    success: Entities::User,
    failure: [
        [400, 'Bad request', Entities::Error],
        [422, 'Bad parameter entry', Entities::Error]
    ],
    notes: <<-NOTE
      Creates a new User

      ## Request properties

      * _Safe:_ Yes
      * _Idempotent:_ No
      * _Can be retried:_ Yes
    NOTE
}
post do
  # stuff ...
end

# here is what CreateUserParams looks like...
module API
  module V1
    module Entities
      require 'grape-entity'
      class User < Grape::Entity
        expose :id, documentation: { type: Integer, desc: 'User unique identifier.' }
        expose :first_name, documentation: { type: String, desc: 'User first name.' }
        expose :last_name, documentation: { type: String, desc: 'User last name.' }
        expose :email, documentation: { type: String, desc: 'User unique email address.' }
        expose :username, documentation: { type: String, desc: 'User unique username.' }
        expose :errors, documentation: { type: Hash, desc: 'A hash containing any validation errors that may have occurred.' }
        expose :phone, documentation: { type: Integer, desc: 'User phone number.' }
        expose :address, documentation: { type: String, desc: 'User address line 1.' }
        expose :address_two, documentation: { type: String, desc: 'User address line 2.' }
        expose :city, documentation: { type: String, desc: 'User city.' }
        expose :state, documentation: { type: String, desc: 'User state.' }
        expose :zip, documentation: { type: Integer, desc: 'User zip code.' }
        expose :created_at, documentation: { type: DateTime, desc: 'The date the user was created.' }
        expose :updated_at, documentation: { type: DateTime, desc: 'The date the user was last updated.' }
      end

      class CreateUserParams < User
        unexpose :id
        unexpose :email

        expose :email, documentation: { type: String, desc: 'User unique email address.', required: true }
        expose :password, documentation: { type: String, desc: 'Password.', required: true }
        expose :password_confirmation, documentation: { type: String, desc: 'Password Confirmation.', required: true }
      end

      class UpdateUserParams < User
        unexpose :id

        expose :id, documentation: { type: Integer, desc: 'User unique identifier.', required: true }
        expose :password, documentation: { type: String, desc: 'Password.' }
        expose :password_confirmation, documentation: { type: String, desc: 'Password Confirmation.' }
      end
    end
  end
end

atljeremy avatar Aug 19 '15 13:08 atljeremy

Same request as per @guizmaii and @atljeremy above. Did either of you manage to get some sort of simple/elegant workaround?

dpad avatar Mar 04 '16 05:03 dpad

@dpad Unfortunately no. I'm having to use the explicit params do block to define required and optional params separately from my Grape::Entity's. I'm really hoping that this gets updated so that I don't have to keep maintaining two separate sets of params documentation.

atljeremy avatar Mar 04 '16 12:03 atljeremy

+1

emanoelxavier2 avatar Jun 07 '18 02:06 emanoelxavier2

I was wondering if there's a solution to this?

nanderss avatar Nov 03 '18 13:11 nanderss

+1

maxgurewitz avatar Aug 11 '20 01:08 maxgurewitz