Виноград: обязательные параметры с виноградной сущностью
Я пишу API-сервер с Grape, и я решил использовать Grape-Entity, потому что он имеет возможность автоматически генерировать документацию для Swagger. Но теперь у меня есть проблема, когда я устанавливаю параметр как требуется. Потому что виноград не подтверждает, что этот параметр присутствует. Похоже, виноград игнорирует required: true
из параметров объекта.
app.rb
module Smart
module Version1
class App < BaseApi
resource :app do
# POST /app
desc 'Creates a new app' do
detail 'It is used to re gister a new app on the server and get the app_id'
params Entities::OSEntity.documentation
success Entities::AppEntity
failure [[401, 'Unauthorized', Entities::ErrorEntity]]
named 'My named route'
end
post do
app = ::App.create params
present app, with: Entities::AppEntity
end
end
end
end
end
os_entity.rb
module Smart
module Entities
class OSEntity < Grape::Entity
expose :os, documentation: { type: String, desc: 'Operative system name', values: App::OS_LIST, required: true }
end
end
end
app_entity.rb
module Smart
module Entities
class AppEntity < OSEntity
expose :id, documentation: { type: 'integer', desc: 'Id of the created app', required: true }
expose :customer_id, documentation: { type: 'integer', desc: 'Id of the customer', required: true }
end
end
end
Теперь все остальное работает отлично, но я не знаю, как использовать сущности в СУХОЙ форме, и я делаю это, утверждая требование параметра.
2 ответа
После некоторой работы я смог сделать виноградную работу, поскольку я думаю, что это должно работать. Потому что я не хочу повторять код как для проверки, так и для документации. Вы просто должны добавить это к инициализаторам (если вы, конечно, в рельсах). Я также смог поддержать вложенные ассоциации. Как видите, код API выглядит так просто, а чванство выглядит идеально. Вот API и все необходимые объекты:
приложение / API / умный / лица / characteristics_params_entity.rb
module Smart
module Entities
class CharacteristicsParamsEntity < Grape::Entity
root :characteristics, :characteristic
expose :id, documentation: { type: Integer, desc: 'Id of the characteristic' }
end
end
end
приложение / API / умный / лица / characterisitcs_entity.rb
module Smart
module Entities
class CharacteristicsEntity < CharacteristicsParamsEntity
expose :id, documentation: { type: Integer, desc: 'Id of the characteristic' }
expose :name, documentation: { type: String, desc: 'Name of the characteristic' }
expose :description, documentation: { type: String, desc: 'Description of the characteristic' }
expose :characteristic_type, documentation: { type: String, desc: 'Type of the characteristic' }
expose :updated_at, documentation: { type: Date, desc: 'Last updated time of the characteristic' }
end
end
end
приложение / API / умный / лица / apps_params_entity.rb
module Smart
module Entities
class AppsParamsEntity < Grape::Entity
expose :os, documentation: { type: String, desc: 'Operative system name', values: App::OS_LIST, required: true }
expose :characteristic_ids, using: CharacteristicsParamsEntity, documentation: { type: CharacteristicsParamsEntity, desc: 'List of characteristic_id that the customer has', is_array: true }
end
end
end
приложение / API / умный / лица / apps_entity.rb
module Smart
module Entities
class AppsEntity < AppsParamsEntity
unexpose :characteristic_ids
expose :id, documentation: { type: 'integer', desc: 'Id of the created app', required: true }
expose :customer_id, documentation: { type: 'integer', desc: 'Id of the customer', required: true }
expose :characteristics, using: CharacteristicsEntity, documentation: { is_array: true, desc: 'List of characteristics that the customer has' }
end
end
end
приложение / API / умный / version1 / apps.rb
module Smart
module Version1
class Apps < Version1::BaseAPI
resource :apps do
# POST /apps
desc 'Creates a new app' do
detail 'It is used to register a new app on the server and get the app_id'
params Entities::AppsParamsEntity.documentation
success Entities::AppsEntity
failure [[400, 'Bad Request', Entities::ErrorEntity]]
named 'create app'
end
post do
app = ::App.create! params
present app, with: Entities::AppsEntity
end
end
end
end
end
И это код, который делает волшебство, чтобы заставить это работать:
конфиг / Инициализаторы / grape_extensions.rb
class Evaluator
def initialize(instance)
@instance = instance
end
def params parameters
evaluator = self
@instance.normal_params do
evaluator.list_parameters(parameters, self)
end
end
def method_missing(name, *args, &block)
end
def list_parameters(parameters, grape)
evaluator = self
parameters.each do |name, description|
description_filtered = description.reject { |k| [:required, :is_array].include?(k) }
if description.present? && description[:required]
if description[:type] < Grape::Entity
grape.requires name, description_filtered.merge(type: Array) do
evaluator.list_parameters description[:type].documentation, self
end
else
grape.requires name, description_filtered
end
else
if description[:type] < Grape::Entity
grape.optional name, description_filtered.merge(type: Array) do
evaluator.list_parameters description[:type].documentation, self
end
else
grape.optional name, description_filtered
end
end
end
end
end
module GrapeExtension
def desc name, options = {}, &block
Evaluator.new(self).instance_eval &block if block
super name, options do
def params *args
end
instance_eval &block if block
end
end
end
class Grape::API
class << self
prepend GrapeExtension
end
end
Это результат примера:
Я люблю комбинацию виноград / виноград-чванство / объект-виноград для создания API. Я обычно использую объекты винограда для построения результата, а вовсе не для документирования / проверки API. В соответствии с документацией (для grape-entity) это должно работать, но я предполагаю просто построить документацию.
Согласно виноградной документации по валидации и приведению параметров, требуется block
для обеспечения любой проверки / принуждения.
[РЕДАКТИРОВАТЬ: смешивая параметры]
Вы можете определить параметры в desc
используя объект, но для проверки вы должны предоставить params
блок, на том же уровне, что и desc
блок, например:
# POST /app
desc 'Creates a new app' do
detail 'It is used to re gister a new app on the server and get the app_id'
params Entities::OSEntity.documentation
success Entities::AppEntity
failure [[401, 'Unauthorized', Entities::ErrorEntity]]
named 'My named route'
end
params do
requires :name, String
optional :description, String
end
post do
app = ::App.create params
present app, with: Entities::AppEntity
end
Они оба называются params
но расположен совсем по-другому и с другой функцией.
Я не уверен, что desc
Блок имеет какое-либо использование, кроме документации (и как извлечь эту документацию для меня немного загадка).
Драгоценный камень не использует его, мой типичный desc
выглядит так:
desc "list of batches", {
:notes => <<-NOTE
Show a list of all available batches.
## Request properties
* _Safe:_ Yes
* _Idempotent:_ Yes
* _Can be retried:_ Yes
NOTE
}
params do
optional :page, desc: 'paginated per 25'
end
get do
present Batch.page(params[:page]), with: API::Entities::Batch
end
где :notes
отображаются с использованием уценки. Как это выглядит в Swagger-UI