api-blueprint 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 92b97a2c669c6b891dca65a5d31a2bfa703951bd
4
- data.tar.gz: 90dd0b51277c9d8e8279ada2be73e1255c61b75e
3
+ metadata.gz: bc247d9616a2e34feda3dd467150f03d384628c0
4
+ data.tar.gz: 68106129bf5eccc56440c0d15ae49f40034c7b20
5
5
  SHA512:
6
- metadata.gz: 9d36fd33e0683abc566069d8b2698d9317f12fa65e76f0bce55e313bfa43ceb5c1a9191d282cd01359221bd4b012dd6abcccf8b8f4813a10e3a648f184ca72e3
7
- data.tar.gz: 242e8eda32ad332e4ebf46e538dcb6173bcbaf8d293ab888ff7aa5a3f7e26fba00a411b295d5577de5b62223209e874c5044ca8d714f1cafaf73d628c943ec12
6
+ metadata.gz: cc963e572698777cded8128676784cbd2625c6b55f34931a274f7697d93bd57bf50e4ae91590a018841560472898aaf35400a00885e1e0929bfce59a0329c3ca
7
+ data.tar.gz: 05333cf34ddc87d344cfb5bd90bf8d37e94282b53a6d98114b8a67a04d99450e37dc2470a31aea443ba94b9c57e5eb2bcab17bec3d6beb2eaf6a7c75a00afe53
data/README.md CHANGED
@@ -61,6 +61,51 @@ The result of using `api.run` on a blueprint is as you'd expect, nice model inst
61
61
  </ul>
62
62
  ```
63
63
 
64
+ ## Collections
65
+
66
+ Sometimes you might want a model which requires multiple api calls and collects the results onto different attributes. You can use an `ApiBlueprint::Model.collection` for this.
67
+
68
+ ```ruby
69
+ class Vehicles < ApiBlueprint::Model
70
+ attribute :car, Types.Constructor(Car)
71
+ attribute :bus, Types.Constructor(Bus)
72
+
73
+ def self.fetch_all(color)
74
+ collection \
75
+ car: Car.all(color),
76
+ bus: Bus.all(color)
77
+ end
78
+ end
79
+
80
+ # Example use
81
+ red_vehicles = api.run Vehicles.fetch_all("red")
82
+ red_vehicles.cars # [<Car>, <Car>, ...]
83
+ red_vehicles.busses # [<Bus>, <Bus>, ...]
84
+ ```
85
+
86
+ ## Request registry
87
+
88
+ If you use the same api request in multiple controllers, it can be cumbersome to remember to set the cache options and pass all required params to api calls. ApiBlueprint includes a registry, which can be used as a container to store blueprints along with cache options and make it quicker and simpler to re-use in controllers.
89
+
90
+ You can add to the registry when initialing the api runner, or later.
91
+
92
+ ```ruby
93
+ # Add `astronauts_in_space` to the registry when initializing the runner:
94
+ api = ApiBlueprint::Runner.new registry: {
95
+ astronauts_in_space: { blueprint: -> { AstronautsInSpace.fetch }, cache: { ttl: 10.minutes } }
96
+ }
97
+
98
+ # Add `vehicles` to the existing registry:
99
+ api.register :vehicles, -> { Vehicles.fetch_all }, ttl: 60.minutes
100
+ ```
101
+
102
+ Once a blueprint is registered in the registry, you can invoke it via the key name on the runner:
103
+
104
+ ```ruby
105
+ api.astronauts_in_space # the same as running api.run AstronautsInSpace.fetch, ttl: 10.minutes
106
+ api.vehicles # the same as running api.run Vehicles.fetch_all, ttl: 60.minutes
107
+ ```
108
+
64
109
  ## Model Configuration
65
110
 
66
111
  Using a `configure` block on models, you can define a default url (host), a [parser](#configparser), a [builder](#configbuilder) and can define a list of [replacements](#configreplacements):
@@ -126,10 +171,10 @@ Certain response statuses will also cause ApiBlueprint to behave in different wa
126
171
 
127
172
  | HTTP Status range | Behavior |
128
173
  | ----------------- | -------- |
129
- | 200 - 399 | Objects are built normally, no errors raised |
174
+ | 200 - 400 | Objects are built normally, no errors raised |
130
175
  | 401 | raises `ApiBlueprint::UnauthenticatedError` |
131
176
  | 404 | raises `ApiBlueprint::NotFoundError` |
132
- | 400 - 499 | raises `ApiBlueprint::ClientError` |
177
+ | 402 - 499 | raises `ApiBlueprint::ClientError` |
133
178
  | 500 - 599 | raises `ApiBlueprint::ServerError` |
134
179
 
135
180
  ## Access to response headers and status codes
data/lib/api-blueprint.rb CHANGED
@@ -7,6 +7,7 @@ require 'active_model'
7
7
  require 'active_support/core_ext/hash'
8
8
  require 'addressable'
9
9
 
10
+ require 'api-blueprint/struct'
10
11
  require 'api-blueprint/response_middleware'
11
12
  require 'api-blueprint/cache'
12
13
  require 'api-blueprint/types'
@@ -19,10 +20,19 @@ require 'api-blueprint/runner'
19
20
  require 'api-blueprint/collection'
20
21
 
21
22
  module ApiBlueprint
23
+ class ResponseError < StandardError
24
+ attr_reader :status, :headers, :body
25
+ def initialize(env)
26
+ @status = env.status
27
+ @headers = env.response_headers.symbolize_keys
28
+ @body = env.body
29
+ end
30
+ end
31
+
22
32
  class DefinitionError < StandardError; end
23
33
  class BuilderError < StandardError; end
24
- class ServerError < StandardError; end
25
- class UnauthenticatedError < StandardError; end
26
- class ClientError < StandardError; end
27
- class NotFoundError < StandardError; end
34
+ class ServerError < ResponseError; end
35
+ class UnauthenticatedError < ResponseError; end
36
+ class ClientError < ResponseError; end
37
+ class NotFoundError < ResponseError; end
28
38
  end
@@ -1,14 +1,12 @@
1
1
  module ApiBlueprint
2
- class Blueprint < Dry::Struct
3
- constructor_type :schema
4
-
2
+ class Blueprint < ApiBlueprint::Struct
5
3
  attribute :http_method, Types::Symbol.default(:get).enum(*Faraday::Connection::METHODS)
6
4
  attribute :url, Types::String
7
5
  attribute :headers, Types::Hash.default(Hash.new)
8
6
  attribute :params, Types::Hash.default(Hash.new)
9
7
  attribute :body, Types::Hash.default(Hash.new)
10
8
  attribute :creates, Types::Any
11
- attribute :parser, Types.Instance(ApiBlueprint::Parser).default(ApiBlueprint::Parser.new)
9
+ attribute :parser, Types.Instance(ApiBlueprint::Parser).optional.default(ApiBlueprint::Parser.new)
12
10
  attribute :replacements, Types::Hash.default(Hash.new)
13
11
  attribute :after_build, Types::Instance(Proc).optional
14
12
  attribute :builder, Types.Instance(ApiBlueprint::Builder).default(ApiBlueprint::Builder.new)
@@ -1,12 +1,11 @@
1
1
  module ApiBlueprint
2
- class Builder < Dry::Struct
3
- constructor_type :schema
2
+ class Builder < ApiBlueprint::Struct
4
3
 
5
4
  attribute :body, Types::Hash.default(Hash.new)
6
5
  attribute :headers, Types::Hash.default(Hash.new)
7
- attribute :status, Types::Int.optional
6
+ attribute :status, Types::Integer.optional
8
7
  attribute :replacements, Types::Hash.default(Hash.new)
9
- attribute :creates, Types::Any
8
+ attribute :creates, Types::Any.optional
10
9
 
11
10
  attr_writer :body
12
11
 
@@ -1,5 +1,5 @@
1
1
  module ApiBlueprint
2
- class Model < Dry::Struct
2
+ class Model < ApiBlueprint::Struct
3
3
  extend Dry::Configurable
4
4
  include ActiveModel::Conversion
5
5
  include ActiveModel::Validations
@@ -7,15 +7,13 @@ module ApiBlueprint
7
7
  extend ActiveModel::Naming
8
8
  extend ActiveModel::Callbacks
9
9
 
10
- constructor_type :schema
11
-
12
10
  setting :host, ""
13
11
  setting :parser, Parser.new
14
12
  setting :builder, Builder.new
15
13
  setting :replacements, {}
16
14
 
17
15
  attribute :response_headers, Types::Hash.optional
18
- attribute :response_status, Types::Int.optional
16
+ attribute :response_status, Types::Integer.optional
19
17
 
20
18
  def self.blueprint(http_method, url, options = {}, &block)
21
19
  blueprint_opts = {
@@ -4,19 +4,15 @@ module ApiBlueprint
4
4
  def on_complete(env)
5
5
  case env[:status]
6
6
  when 401
7
- raise ApiBlueprint::UnauthenticatedError, response_values(env)
7
+ raise ApiBlueprint::UnauthenticatedError.new(env)
8
8
  when 404
9
- raise ApiBlueprint::NotFoundError, response_values(env)
9
+ raise ApiBlueprint::NotFoundError.new(env)
10
10
  when 402..499
11
- raise ApiBlueprint::ClientError, response_values(env)
11
+ raise ApiBlueprint::ClientError.new(env)
12
12
  when 500...599
13
- raise ApiBlueprint::ServerError, response_values(env)
13
+ raise ApiBlueprint::ServerError.new(env)
14
14
  end
15
15
  end
16
16
 
17
- def response_values(env)
18
- { status: env.status, headers: env.response_headers, body: env.body }
19
- end
20
-
21
17
  end
22
18
  end
@@ -4,6 +4,7 @@ module ApiBlueprint
4
4
 
5
5
  option :headers, default: proc { {} }
6
6
  option :cache, default: proc { Cache.new key: "global" }
7
+ option :registry, default: proc { {} }
7
8
 
8
9
  def run(item, cache_options = {})
9
10
  if item.is_a?(Blueprint)
@@ -19,6 +20,18 @@ module ApiBlueprint
19
20
  { headers: headers, cache: cache }
20
21
  end
21
22
 
23
+ def register(name, blueprint, cache_options = {})
24
+ registry[name] = { blueprint: blueprint, cache: cache_options }
25
+ end
26
+
27
+ def method_missing(name, *args, &block)
28
+ if stored_method = registry[name].presence
29
+ run stored_method[:blueprint].call(*args), stored_method[:cache]
30
+ else
31
+ raise NoMethodError, "#{name} is not defined in the ApiBlueprint::Runner registry"
32
+ end
33
+ end
34
+
22
35
  private
23
36
 
24
37
  def run_blueprint(blueprint, cache_options)
@@ -0,0 +1,9 @@
1
+ module ApiBlueprint
2
+ class Struct < Dry::Struct
3
+ transform_keys &:to_sym
4
+
5
+ transform_types do |type|
6
+ type.default? ? type : type.meta(omittable: true)
7
+ end
8
+ end
9
+ end
@@ -1,3 +1,3 @@
1
1
  module ApiBlueprint
2
- VERSION = '0.5.0'
2
+ VERSION = '0.6.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api-blueprint
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Damien Timewell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-26 00:00:00.000000000 Z
11
+ date: 2018-05-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-types
@@ -212,6 +212,7 @@ files:
212
212
  - lib/api-blueprint/parser.rb
213
213
  - lib/api-blueprint/response_middleware.rb
214
214
  - lib/api-blueprint/runner.rb
215
+ - lib/api-blueprint/struct.rb
215
216
  - lib/api-blueprint/types.rb
216
217
  - lib/api-blueprint/url.rb
217
218
  - lib/api-blueprint/version.rb