Grape::Entity
repository·master·Indexed 20 days ago
https://github.com/ruby-grape/grape-entityA presentation layer for Ruby APIs that allows developers to define structured, reusable, and conditional data representations (entities) for their models. It provides a DSL to control field exposure, handle nested structures, apply custom formatting via `format_with`, and manage conditional visibility using `:if` and `:unless` options. Commonly used with the Grape framework to transform data models into consistent API responses.
What's inside grape-entity
- Grape::Entity is an API-focused facade designed to sit on top of an object model. It provides a way to define how your data models should be represented when sent through an API, allowing for controlled exposure of fields, conditional logic, and nested structures. It is commonly used with the Grape framework.
Access the options hash and attribute path
masterDuring runtime exposure or conditional checking, you can access metadata via the
optionshash::version: The API version (api.version).:collection: Boolean indicating if the object is an array.:env: The runtime environment (includesoptions[:env]['grape.request.params']).:attr_path: An array representing the path to the current attribute (e.g.,[:user, :address, :city]). This is useful for tracking which attribute is being processed in nested structures.
Upgrade to Grape Entity >= 0.10.2
masterOfficial support forFetchableObjecthas been removed in version 0.10.2 and later.Test API responses with Entities
masterWhen usinggrape-entity, you can test API requests and responses using your standard testing framework. For specialized testing tools, you can use Grape Entity Matchers.Upgrade to Grape Entity >= 0.5.1
masterInGrape::Entity::Exposure::NestingExposure::NestedExposures.delete_if, the method now always returns the exposures, regardless of whether a deletion occurred. Previously, it returnednilif no items were deleted.Upgrade to Grape Entity >= 0.6.0
masterTheGrape::Entity#inspectmethod has changed. It no longer serializes the entity presenter with its options and delegator. Instead, it serializes the exposed entity itself using#serializable_hash.Install grape-entity
masterTo add
grape-entityto your Ruby application, add the gem to yourGemfileand runbundle.Alternatively, you can install the gem directly via the command line.
# In your Gemfile gem 'grape-entity'$ bundle # OR $ gem install grape-entityUpgrade to Grape Entity >= 0.8.2
masterWhen upgrading to version 0.8.2 or higher, note the following:
Ruby Support: Official support for Ruby < 2.5 has been removed. Ruby 2.5 is only in testing mode and is not officially supported.
Ruby 3.0 Compatibility: Due to changes in block handling in Ruby 3.0, the following pattern is deprecated:
expose :that_method_without_args, &:method_without_args
Recommended Pattern: For simple value setting, use the
as:option instead:expose :method_without_args, as: :that_method_without_args# Deprecated pattern (in Ruby 3.0+) expose :that_method_without_args, &:method_without_args # Preferred pattern expose :method_without_args, as: :that_method_without_argsUpgrade to Grape Entity >= 1.1.0
masterWhen upgrading to version 1.1.0 or higher, note the following changes:
Dependency Change: The
multi_jsongem is no longer a runtime dependency. If your application relies on a configuredMultiJsonadapter, you must explicitly addmulti_jsonto yourGemfile.Error Handling for Missing Methods: The behavior of
expose :x, &:missing_methodhas changed. It no longer raises anArgumentErrorduring the definition phase. Instead, unknown methods will now raise a nativeNoMethodErrorat call time.
Action Required: If you have rescue clauses around entity rendering intended to catch typos in method names (e.g.,
rescue ArgumentError), update them torescue NoMethodError.# Old pattern (may no longer catch typos) begin present user, with: UserEntity rescue ArgumentError # ... end # New pattern for version >= 1.1.0 begin present user, with: UserEntity rescue NoMethodError # ... endDefine data representations with Grape::Entity
masterAn
Entityis a lightweight structure used to represent application data in a consistent, abstracted way for your API. You define an entity by subclassingGrape::Entityand using theexposemethod to declare which attributes should be included in the API response.Entities can provide documentation for fields, transform values using blocks or procs, and conditionally expose attributes based on runtime options or object state.
module API module Entities class User < Grape::Entity expose :first_name, :last_name, :screen_name, :location expose :field, documentation: { type: "string", desc: "describe the field" } expose :latest_status, using: API::Status, as: :status, unless: { collection: true } expose :email, if: { type: :full } expose :new_attribute, if: { version: 'v2' } expose(:name) { |model, options| [model.first_name, model.last_name].join(' ') } end end endUse an Entity in a Grape API
masterOnce an entity is defined, use the
presentmethod within your Grape API to transform your data models into the entity's representation. You can pass runtime options (liketype: :full) to trigger conditional exposures defined in the entity.module API class Users < Grape::API version 'v2' desc 'User index', { params: API::Entities::User.documentation } get '/users' do @users = User.all type = current_user.admin? ? :full : :default present @users, with: API::Entities::User, type: type end end endDefine API responses using Grape::Entity
masterTo define an entity, create a class that inherits from
Grape::Entity. You use theexposemethod to specify which attributes of the underlying object should be included in the API response. You can also apply formatting, conditional logic, and nesting within the definition.module API module Entities class Status < Grape::Entity format_with(:iso_timestamp) { |dt| dt.iso8601 } expose :user_name expose :text, documentation: { type: "String", desc: "Status update text." } expose :ip, if: { type: :full } expose :user_type, :user_id, if: lambda { |status, options| status.user.public? } expose :location, merge: true expose :contact_info do expose :phone expose :address, merge: true, using: API::Entities::Address end expose :digest do |status, options| Digest::MD5.hexdigest status.txt end expose :replies, using: API::Entities::Status, as: :responses expose :last_reply, using: API::Entities::Status do |status, options| status.replies.last end with_options(format_with: :iso_timestamp) do expose :created_at expose :updated_at end end end end module API module Entities class StatusDetailed < API::Entities::Status expose :internal_id end end end