Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add scenario to test coercion of grape entity #2036

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/grape/validations/types/build_coercer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require_relative 'array_coercer'
require_relative 'set_coercer'
require_relative 'primitive_coercer'
require_relative 'grape_entity_coercer'

module Grape
module Validations
Expand Down Expand Up @@ -64,6 +65,8 @@ def self.create_coercer_instance(type, method, strict)
ArrayCoercer.new type, strict
elsif type.is_a?(Set)
SetCoercer.new type, strict
elsif type.superclass == Grape::Entity
GrapeEntityCoercer.new type
else
PrimitiveCoercer.new type, strict
end
Expand Down
43 changes: 43 additions & 0 deletions lib/grape/validations/types/grape_entity_coercer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# frozen_string_literal: true

module Grape
module Validations
module Types
# Handles coercion and type checking for parameters that are subclasses
# of Grape::Entity.
class GrapeEntityCoercer
def initialize(type)
@type = type
end

def call(val)
return if val.nil?

if val.is_a?(Array)
val.each do |i|
return InvalidValue.new unless coerced?(i)
end
else
return InvalidValue.new unless coerced?(val)
end
end

private

attr_reader :type

def coerced?(val)
val.each_key do |k|
return false unless exposure_keys.include?(k.to_sym)
end

true
end

def exposure_keys
type.root_exposures.map(&:key)
end
end
end
end
end
60 changes: 60 additions & 0 deletions spec/grape/validations/validators/coerce_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require 'spec_helper'
require 'grape_entity'

describe Grape::Validations::CoerceValidator do
subject do
Expand Down Expand Up @@ -984,5 +985,64 @@ def self.parsed?(value)
10.times { get '/' }
end
end

context 'grape entity' do
class Name < Grape::Entity
expose :first_name, documentation: { required: true, type: 'String', desc: 'first name' }
expose :surname, as: 'lastName', documentation: { required: true, type: 'String', desc: 'last name' }
end

class Person < Grape::Entity
expose :email, documentation: { required: true, type: 'String', desc: 'email address' }
expose :name, using: Name, documentation: { required: true, type: 'Name', desc: 'full name' }
end

class Question < Grape::Entity
expose :order, documentation: { required: true, type: 'Integer', desc: 'order of question' }
expose :text, documentation: { required: true, type: 'String', desc: 'text of question' }
end

it 'handles a subclass of Grape::Entity' do
subject.params do
requires :name, type: Name
end
subject.get '/' do
'simple grape entity works'
end

get '/', name: { first_name: 'John', 'lastName' => 'Smith' }

expect(last_response.status).to eq(200)
expect(last_response.body).to eq('simple grape entity works')
end

it 'handles a subclass of Grape::Entity which exposes another Grape::Entity' do
subject.params do
requires :person, type: Person
end
subject.get '/' do
'complex grape entity works'
end

get '/', person: { email: 'john@example.com', name: { first_name: 'John', 'lastName' => 'Smith' } }

expect(last_response.status).to eq(200)
expect(last_response.body).to eq('complex grape entity works')
end

it 'handles an array of elements of a subclass of Grape::Entity' do
subject.params do
requires :question, type: Question
end
subject.get '/' do
'an array of grape entities works'
end

get '/', question: [{ order: 1, text: 'Why?' }, { order: 2, text: 'How?' }]

expect(last_response.status).to eq(200)
expect(last_response.body).to eq('an array of grape entities works')
end
end
end
end