Module: Flappi::Definition

Includes:
Common
Defined in:
lib/flappi/definition.rb

Overview

DSL for API construction.

This DSL defines methods which can be used to construct API responses, docs, etc. Include it in each API endpoint definition as shown below:

Examples:

include Flappi::Definition

def endpoint
 # Define your endpoint here using {#method}, {#title}, {#description}, {#version}, {#group}, {#path}
 #   #{response_example}, #{param}
 #   #{query}
end

def response
 # Define your response here using #{build}
end

Constant Summary collapse

BOOLEAN =

Use on #field and #param types when a boolean type is wanted, null values will be null

:boolean_type
BOOLEAN_STRICT =

Use on #field and #param types when a boolean type is wanted and falsey values will be false, truthy true

:boolean_strict
SOURCE_PRESENT =
:source_present

Instance Method Summary collapse

Instance Method Details

#api_error(status_code, field_name, field_description) ⇒ Object

Define an API error



360
361
362
363
364
365
366
# File 'lib/flappi/definition.rb', line 360

def api_error(status_code, field_name, field_description)
  endpoint_info[:api_errors] << {
    status_code: status_code,
    response_field_name: field_name,
    response_field_description: field_description
  }
end

#build(options = {}) {|base_object| ... } ⇒ Object

Define how to build the API response. Use this typically with a block that defines how each field of the response is to be generated.

Examples:

fetch a user record

build type: User do
     ...
end

Parameters:

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :type (Class)

    Specifies a (ruby) type, an instance of which will be retrieved by calling the classes (ActiveRecord-style) 'where' method with the controller's parameters and will become the base object the response is generated from.

  • :as (Symbol)

    Specifies the class method to call in place on the `type`

  • :options (Hash)

    Optionally specify an array of options which will be passed to the 'where' method of class 'type'

Yields:

Yield Parameters:

  • base_object (Object)

    the base object we generate the response from. If you don't use explicit value expressions in #field etc, you don't need this.



130
131
132
# File 'lib/flappi/definition.rb', line 130

def build(options = {}, &block)
  @delegate.build options, &block
end

#check_params(mode = false) ⇒ Object

Enable parameter check for strict parameters in Rails



444
445
446
# File 'lib/flappi/definition.rb', line 444

def check_params(mode = false)
  endpoint_info[:check_params] = mode
end

#description(v) ⇒ Object

Define the description

Parameters:

  • v (String)

    The longer description to be shown in documentation.



317
318
319
# File 'lib/flappi/definition.rb', line 317

def description(v)
  endpoint_info[:description] = v
end

#field(name) {|current_source| ... } ⇒ Object #field(name, value) ⇒ Object #field(options = {}) {|current_source| ... } ⇒ Object

Define a single (scalar) field in the result. This will produce a name:value pair in the json response.

Overloads:

  • #field(name) {|current_source| ... } ⇒ Object

    Define a field sourcing data from the enclosing source object. If no block is given, the field value will be extracted from source_object, otherwise it will be the block return.

    Parameters:

    • name (String)

      the name of the field

    Yields:

    • A block that will be called to return the field value

    Yield Parameters:

    • current_source (Object)

      the current source object

  • #field(name, value) ⇒ Object

    Define a field with an explicitly specified value.

    Parameters:

    • name (String)

      the name of the field

    • value (Object)

      the value to output

  • #field(options = {}) {|current_source| ... } ⇒ Object

    Define a field with named options

    Options Hash (options):

    • :name (String)

      the name of the field

    • :value (Object)

      if given, the value to output

    • :source (Object)

      the name of a hash or method in the current source to get the data from, instead of :name

    • :when (Boolean)

      if false, omit this object, if SOURCE_PRESENT, omit unless a data source is present

    • :version (Hash)

      specify a versioning rule as a hash (see #version for spec for the rule). If present, this field will only we shown if the rule is met.

    • :doc_name (String)

      where a field has a dynamic name (computed value) then use this value, enclosed in underscores, as the name of the field.

    • :type (String)

      a type to coerce the value to: :Integer, :BigDecimal, :Float

    Yields:

    • A block that will be called to return the field value

    Yield Parameters:

    • current_source (Object)

      the current source object



236
237
238
# File 'lib/flappi/definition.rb', line 236

def field(*args_or_name, &block)
  @delegate.field(*args_or_name, block)
end

#group(v) ⇒ Object

Define the API group this endpoint is in - used to break documentation into sections

Parameters:

  • v (String)

    The group name.



335
336
337
# File 'lib/flappi/definition.rb', line 335

def group(v)
  endpoint_info[:group] = v
end

#hash_key(value, options = {}) ⇒ Object #hash_key(options = {}) ⇒ Object

Define the hash key to be used in generating a hash from #objects

Overloads:

  • #hash_key(value, options = {}) ⇒ Object

    Define the hash key as having a specified value

    Parameters:

    • value (Object)

      the value for the hash key

    Options Hash (options):

    • :when (Boolean)

      if false, omit this object, if SOURCE_PRESENT, omit unless a data source is present

  • #hash_key(options = {}) ⇒ Object

    Define the hash key with named options

    Options Hash (options):

    • :value (Object)

      if given, the value to output

    • :when (Boolean)

      if false, omit this object, if SOURCE_PRESENT, omit unless a data source is present



252
253
254
# File 'lib/flappi/definition.rb', line 252

def hash_key(*args, &block)
  @delegate.hash_key(*args, block)
end

#http_method(v) ⇒ Object

Define the HTTP method - note however that Rails and the controller is responsible for routing

Parameters:

  • v (String)

    GET, POST, PUT, DELETE



305
306
307
# File 'lib/flappi/definition.rb', line 305

def http_method(v)
  endpoint_info[:http_method] = v
end

Specify a link to be provided in the response Links defined at the top level will be output at the end of the response Links defined at object level will be output at the end of the object

Overloads:

  • #link(: self) ⇒ Object

    Parameters:

    • key (String)

      (:self, to generate the link that produces this result)

  • #link(key, path) ⇒ Object

    Parameters:

    • key (String)

      :self to generate the link that produces this result or an endpoint name

    • path (String)

      the (parameterised) path to generate the link from

  • #link(options = {}) ⇒ Object

    Parameters:

    • options (Hash) (defaults to: {})

      parameters passed to create the link

    Options Hash (options):

    • :key (String)

      :self to generate the link that produces this result or an endpoint name

    • :path (String) — default: String

      the (parameterised) path to generate the link from



297
298
299
# File 'lib/flappi/definition.rb', line 297

def link(*link_params)
  @delegate.link(*link_params) if @delegate.respond_to? :link
end

#major_versionObject

The major version for documentation and example purposes



476
477
478
# File 'lib/flappi/definition.rb', line 476

def major_version
  @delegate.requested_version&.major
end

#object(name) {|current_source| ... } ⇒ Object #object(name, value) {|current_source| ... } ⇒ Object #object(options) {|current_source| ... } ⇒ Object

Define an object (which will be rendered within json as name:hash). Use this with a block that defines the fields of the object hash. For a named object, if no source data exists (is nil) then no object will be rendered. (Set value: true if the block can render with no input)

Overloads:

  • #object(name) {|current_source| ... } ⇒ Object

    Defines a named object using the enclosing source object.

    Parameters:

    • name (String)

      the name of the object

    Yields:

    • A block that will be called to generate the response fields using nested #field, #object and #objects elements.

    Yield Parameters:

    • current_source (Object)

      the current source object from the enclosing context

  • #object(name, value) {|current_source| ... } ⇒ Object

    Define an object using a specified value.

    Parameters:

    • name (String)

      the name of the object

    • value (Object)

      the object to extract fields from

    Yields:

    • A block that will be called to generate the response fields using nested #field, #object and #objects elements.

    Yield Parameters:

    • current_source (Object)

      the current source object (passed as value)

  • #object(options) {|current_source| ... } ⇒ Object

    Define an object (which will be rendered within json as name:hash or inlined into the parent hash).

    Options Hash (options):

    • :name (String)

      the name of the object

    • :value (Object)

      the object to extract fields from

    • :source (Object)

      the name of a hash or method in the current source to get the data from, instead of :name

    • :inline_always (Boolean)

      rather than creating this object's hash, inline its fields into the parent

    • :when (Boolean)

      if false, omit this object, if SOURCE_PRESENT, omit unless a data source is present

    • :version (Hash)

      specify a versioning rule as a hash (see #version for spec for the rule). If present, this object will only we shown if the rule is met.

    • :dynamic_key (String)

      Rather than a fixed name, specify a key that is valid at request time.

    Yields:

    • A block that will be called to generate the response fields using nested #field, #object and #objects elements.

    Yield Parameters:

    • current_source (Object)

      the current source object (passed as value)



163
164
165
# File 'lib/flappi/definition.rb', line 163

def object(*args_or_name, &block)
  @delegate.object(*args_or_name, block)
end

#objects(name, options = {}) {|current_source| ... } ⇒ Object #objects(name, value, options = {}) {|current_source| ... } ⇒ Object #objects(options) {|current_source| ... } ⇒ Object

Define multiple objects which will be rendered into json as an array of object hashes. Use this with a block that defines the fields of each object hash. The array is generated by iterating over the source object (if an Array) or with one field (if scalar).

Overloads:

  • #objects(name, options = {}) {|current_source| ... } ⇒ Object

    Defines a named array object using the enclosing source object. Will generate name: array in json.

    Parameters:

    • name (String)

      the name of the array field

    Options Hash (options):

    • :compact (Boolean)

      remove nil entries from the result array

    Yields:

    • A block that will be called to generate the response fields using nested #field, #object and #objects elements. The block will be called for each array value in sequence.

    Yield Parameters:

    • current_source (Object)

      the current source object iterated from the enclosing context

  • #objects(name, value, options = {}) {|current_source| ... } ⇒ Object

    Defines a named array object using a specified (array or scalar) value. Will generate name: array in json.

    Parameters:

    • name (String)

      the name of the array field

    • value (Object)

      either an array, in which case each value will become a result entry, or a scalar which will produce a single result.

    Options Hash (options):

    • :compact (Boolean)

      remove nil entries from the result array

    • :when (Boolean)

      if false, omit this object, if SOURCE_PRESENT, omit unless a data source is present

    • :version (Hash)

      specify a versioning rule as a hash (see #version for spec for the rule). If present, this object will only we shown if the rule is met.

    • :hashed (Boolean)
      • produce a hash rather than a collection. The hash key is defined with #hash_key

    Yields:

    • A block that will be called to generate the response fields using nested #field, #object and #objects elements. The block will be called for each array value in sequence.

    Yield Parameters:

    • current_source (Object)

      the current source object iterated from the enclosing context

  • #objects(options) {|current_source| ... } ⇒ Object

    Define an object (which will be rendered within json as name:hash or inlined into the parent hash).

    Options Hash (options):

    • :name (String)

      the name of the array field

    • :value (Object)

      either an array, in which case each value will become a result entry, or a scalar which will produce a single result.

    • :source (Object)

      the name of a hash or method in the current source to get the data array from, instead of :name

    • :compact (Boolean)

      remove nil entries from the result array

    • :when (Boolean)

      if false, omit this object, if SOURCE_PRESENT, omit unless a data source is present

    • :version (Hash)

      specify a versioning rule as a hash (see #version for spec for the rule). If present, this object will only we shown if the rule is met.

    • :hashed (Boolean)
      • produce a hash rather than a collection. The hash key is defined with #hash_key

    Yields:

    • A block that will be called to generate the response fields using nested #field, #object and #objects elements.

    Yield Parameters:

    • current_source (Object)

      the current source object iterated from the enclosing context



202
203
204
# File 'lib/flappi/definition.rb', line 202

def objects(*args_or_name, &block)
  @delegate.objects(*args_or_name, block)
end

#param(name, options = {}) {|param| ... } ⇒ ParamProcessor #param(options = {}) {|param| ... } ⇒ ParamProcessor

Define an input parameter (inline or query string) This is used to document and validate the parameters.

Chain processor &block to this to define a parameter processor

and/or validator &block for define a parameter validator

Overloads:

  • #param(name, options = {}) {|param| ... } ⇒ ParamProcessor

    Define a named parameter

    Parameters:

    • name (String)

      the name of the parameter

    Options Hash (options):

    • :name (String)

      the name of the parameter

    • :type (Symbol)

      the parameter type, defaults to String, allowed types are `Boolean`, `BigDecimal`, `Float`, `Integer`, `Date`, `String`, `Array`. For `Array`, the input params can be defined using comma separated or [] syntax

    • :default (Object)

      a default value when the parameter is not supplied or is empty

    • :default_doc (String)

      text to document the default with instead of a computed default

    • :doc (String)

      the parameter description

    • :hidden (Boolean)

      if true don't document

    • :optional (Boolean)

      true for an optional parameter

    Yields:

    • A block that will be called to validate the parameter

    Yield Parameters:

    • param (Object)

      the actual parameter value to validate

    Yield Returns:

    • (String)

      nil if the parameter is valid, else a failure message

    Returns:

    • (ParamProcessor)

      chain this with processor or validator

  • #param(options = {}) {|param| ... } ⇒ ParamProcessor

    Define a parameter

    Options Hash (options):

    • :name (String)

      the name of the parameter, which can be in a path

    • :type (Symbol)

      the parameter type, defaults to String, allowed types are `Boolean`, `BigDecimal`, `Float`, `Integer`, `Date`, `String`, `Array`. For `Array`, the input params can be defined using comma separated or [] syntax

    • :default (Object)

      a default value when the parameter is not supplied or is empty

    • :default_doc (String)

      text to document the default with instead of a computed default

    • :doc (String)

      the parameter description

    • :hidden (Boolean)

      if true don't document

    • :optional (Boolean)

      true for an optional parameter

    • :fail (Integer)

      code Code to return when fail is true

    Yields:

    • A block that will be called to validate the parameter

    Yield Parameters:

    • param (Object)

      the actual parameter value to validate

    Yield Returns:

    • (String)

      nil if the parameter is valid, else a failure message

    Returns:

    • (ParamProcessor)

      chain this with processor or validator



420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
# File 'lib/flappi/definition.rb', line 420

def param(*args_or_name, &block)
  def_args = extract_definition_args(args_or_name)
  require_arg def_args, :name

  return unless version_wanted(def_args)

  param_def = { name: def_args[:name],
                type: name_for_type(def_args[:type]),
                default_doc: def_args[:default_doc],
                description: def_args[:doc],
                hidden: def_args[:hidden],
                optional: def_args.key?(:optional) ? def_args[:optional] : true,
                validation_block: block,
                fail_code: def_args[:fail_code] }

  # options that take nil
  param_def[:default] = def_args[:default] if def_args.key?(:default)

  endpoint_info[:params] << param_def

  ParamProcessor.new(param_def)
end

#path(v) ⇒ Object

Define the path to this endpoint under the API root. This is for documentation only.

Parameters:

  • v (String)

    The path, with parameters.



342
343
344
# File 'lib/flappi/definition.rb', line 342

def path(v)
  endpoint_info[:path] = v
end

#query {|controller_params| ... } ⇒ Object

Define a query to be used to retrieve the source object for the response.

Yields:

  • A block that will be called to perform the query and return the source object

Yield Parameters:

  • controller_params (Array)

    the parameters as passed to the controller

Yield Returns:

  • an object to construct the response from



459
460
461
# File 'lib/flappi/definition.rb', line 459

def query(&block)
  @delegate.query(block)
end

#reference(name, options = {}) {|current_source| ... } ⇒ Object #reference(name, value, options = {}) ⇒ Object

Creates a sideloaded reference to an object created by the block. The object must include an ID field

Overloads:

  • #reference(name, options = {}) {|current_source| ... } ⇒ Object

    Define a reference sourcing data from the enclosing source object. If no block is given, the reference object will be extracted from source_object, otherwise it will be the block return.

    Parameters:

    • name (String)

      the name of the field

    Options Hash (options):

    • :type (String)

      creates a polymorphic reference for a named type, requires 'for'

    • :for (Object)

      for a polymorphic relation, provide the type that is being requested/generated. (This will usually be from model data or request)

    • :generate_from_type (Boolean)

      generate (inline) a name_type field with the type value

    • :link_id (Boolean)

      generate a link id name_id in the source location. Defaults to true

    Yields:

    • A block that will be called to return the referenced object

    Yield Parameters:

    • current_source (Object)

      the current source object

    Yield Returns:

    • the referenced object

  • #reference(name, value, options = {}) ⇒ Object

    Define a reference sourcing data from the enclosing source object. If no block is given, the reference object will be extracted from source_object, otherwise it will be the block return.

    Parameters:

    • name (String)

      the name of the field

    • value (Object)

      the referenced object

    Options Hash (options):

    • :type (String)

      creates a polymorphic reference for a named type, requires 'for'

    • :for (Object)

      for a polymorphic relation, provide the type that is being requested/generated. (This will usually be from model data or request)

    • :generate_from_type (Boolean)

      generate (inline) a name_type field with the type value

    • :link_id (Boolean)

      generate a link id name_id in the source location. Defaults to true



280
281
282
# File 'lib/flappi/definition.rb', line 280

def reference(*args_or_name, &block)
  @delegate.reference(*args_or_name, block)
end

#request_example(*v) ⇒ Object

Define an example request path (no scheme or host) that will be included in documentation. If not specified, the #path is used.

Parameters:

  • v (String)

    The request example URL



355
356
357
# File 'lib/flappi/definition.rb', line 355

def request_example(*v)
  set_example('request', v)
end

#response_example(*v) ⇒ Object

Define an example response that will be included in documentation.

Parameters:

  • v (String)

    The response example.



348
349
350
# File 'lib/flappi/definition.rb', line 348

def response_example(*v)
  set_example('response', v)
end

#return_error(status_code, error_info) ⇒ Object

From inside a query, return an error

Parameters:

  • status_code (Integer)

    an HTTP status code to return

  • error_info (Object)

    a message String or an error hash to return



471
472
473
# File 'lib/flappi/definition.rb', line 471

def return_error(status_code, error_info)
  @delegate.return_error(status_code, error_info) if @delegate.respond_to?(:return_error)
end

#return_no_contentObject

From inside a query, return 204 NO CONTENT



464
465
466
# File 'lib/flappi/definition.rb', line 464

def return_no_content
  @delegate.return_no_content if @delegate.respond_to?(:return_no_content)
end

#strict(mode = false) ⇒ Object

Enable/disable strict mode, unknown parameters will cause an error Default is to disable this



450
451
452
# File 'lib/flappi/definition.rb', line 450

def strict(mode = false)
  endpoint_info[:strict_mode] = mode
end

#title(v) ⇒ Object

Define the title

Parameters:

  • v (String)

    The title to be shown in documentation.



311
312
313
# File 'lib/flappi/definition.rb', line 311

def title(v)
  endpoint_info[:title] = v
end

#version(version_rule) ⇒ Object

Define the version this endpoint works with.

This assumes that a version plan (which defines semantic versioning and version flavours) is configured into Flappi.

Parameters:

  • version_rule (Hash)

    a customizable set of options

Options Hash (version_rule):

  • :equals (String)

    A version which must be matched for the endpoint to be supported. The version can be wildcarded with '*'.

  • :matches (String)

    Synonym for equals



327
328
329
330
331
# File 'lib/flappi/definition.rb', line 327

def version(version_rule)
  raise "No version plan is defined - cannot use 'version'" unless version_plan

  @version_rule = version_rule
end