web_function 0.4.1 → 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 +4 -4
- data/exe/wfn +42 -0
- data/lib/web_function/argument.rb +120 -14
- data/lib/web_function/attribute.rb +110 -15
- data/lib/web_function/client.rb +91 -27
- data/lib/web_function/documented_error.rb +60 -8
- data/lib/web_function/endpoint.rb +214 -74
- data/lib/web_function/flaggable.rb +40 -0
- data/lib/web_function/package.rb +135 -20
- data/lib/web_function/pipeline.rb +35 -6
- data/lib/web_function/promise.rb +69 -1
- data/lib/web_function/request.rb +171 -0
- data/lib/web_function/utils.rb +44 -0
- data/lib/web_function/version.rb +1 -1
- data/lib/web_function.rb +23 -3
- data/test.rb +43 -0
- metadata +6 -2
|
@@ -1,111 +1,251 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module WebFunction
|
|
4
|
+
# Represents an endpoint as described in a Web Function package.
|
|
5
|
+
#
|
|
6
|
+
# An endpoint defines an operation that can be performed via a Web Function API. Endpoints declare their name,
|
|
7
|
+
# documentation, arguments (inputs), attributes (outputs), and the possible errors that may occur when invoking them.
|
|
8
|
+
#
|
|
9
|
+
# Endpoints are described as objects in each package under the `"endpoints"` key. For more information, see:
|
|
10
|
+
#
|
|
11
|
+
# - [Web Function package docs](https://webfunction.org/package)
|
|
12
|
+
# - [Web Function endpoint docs](https://webfunction.org/endpoint)
|
|
13
|
+
#
|
|
14
|
+
# This class provides methods for accessing endpoint metadata (name, docs, arguments, attributes, errors) and
|
|
15
|
+
# supports invocation via HTTP.
|
|
16
|
+
#
|
|
17
|
+
# Typical tasks include:
|
|
18
|
+
#
|
|
19
|
+
# - Querying endpoint name or documentation
|
|
20
|
+
# - Enumerating the arguments or attributes definitions
|
|
21
|
+
# - Invoking the endpoint through HTTP using required inputs
|
|
22
|
+
#
|
|
23
|
+
# See: https://webfunction.org/endpoint for more details on endpoint structure and contract.
|
|
24
|
+
#
|
|
4
25
|
class Endpoint
|
|
5
|
-
|
|
6
|
-
|
|
26
|
+
include Flaggable
|
|
27
|
+
|
|
28
|
+
def initialize(name:, returns: [], hints: [], flags: [], group: nil, docs: nil, arguments: [], attributes: [], errors: [])
|
|
29
|
+
@name = name
|
|
30
|
+
@returns = returns
|
|
31
|
+
@hints = hints
|
|
32
|
+
@flags = flags
|
|
33
|
+
@group = group
|
|
34
|
+
@docs = docs
|
|
35
|
+
@arguments = arguments.to_h { |a| [a.name, a] }
|
|
36
|
+
@attributes = attributes.to_h { |a| [a.name, a] }
|
|
37
|
+
@errors = errors.to_h { |e| [e.code, e] }
|
|
7
38
|
end
|
|
8
39
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
40
|
+
class << self
|
|
41
|
+
# Invokes an endpoint through HTTP using the given URL, bearer authentication, version, and arguments.
|
|
42
|
+
#
|
|
43
|
+
# @param url [String] The URL of the endpoint to invoke
|
|
44
|
+
# @param bearer_auth [String] The bearer authentication token
|
|
45
|
+
# @param version [String] The API version to use
|
|
46
|
+
# @param args [Hash] The arguments to send to the endpoint
|
|
47
|
+
#
|
|
48
|
+
# @return [Object] The response returned by the endpoint
|
|
49
|
+
#
|
|
50
|
+
def invoke(url, bearer_auth: nil, version: nil, args: {})
|
|
51
|
+
Request.execute(url, bearer_auth: bearer_auth, version: version, args: args)
|
|
18
52
|
end
|
|
19
53
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
54
|
+
# Creates a new Endpoint from a hash.
|
|
55
|
+
#
|
|
56
|
+
# @param endpoint [Hash] The endpoint hash
|
|
57
|
+
#
|
|
58
|
+
# @return [Endpoint] A new Endpoint instance
|
|
59
|
+
#
|
|
60
|
+
def from_hash(endpoint)
|
|
61
|
+
unless endpoint.is_a?(Hash)
|
|
62
|
+
return
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
unless endpoint["name"]
|
|
66
|
+
return
|
|
67
|
+
end
|
|
23
68
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
69
|
+
new(
|
|
70
|
+
name: endpoint["name"],
|
|
71
|
+
returns: Utils.normalize_array_of_strings(endpoint["returns"]),
|
|
72
|
+
hints: Utils.normalize_array_of_strings(endpoint["hints"]),
|
|
73
|
+
flags: Utils.normalize_array_of_strings(endpoint["flags"]),
|
|
74
|
+
group: endpoint["group"],
|
|
75
|
+
docs: endpoint["docs"].to_s,
|
|
76
|
+
arguments: Argument.from_array(endpoint["arguments"]),
|
|
77
|
+
attributes: Attribute.from_array(endpoint["attributes"]),
|
|
78
|
+
errors: DocumentedError.from_array(endpoint["errors"]),
|
|
79
|
+
)
|
|
30
80
|
end
|
|
31
81
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
when Array
|
|
42
|
-
if result.length == 3 && result[0].is_a?(String) && result[1].is_a?(String)
|
|
43
|
-
code = result[0]
|
|
44
|
-
message = result[1]
|
|
45
|
-
details = result[2]
|
|
46
|
-
|
|
47
|
-
raise WebFunction::Error.new(message, code: code, details: details)
|
|
48
|
-
else
|
|
49
|
-
raise WebFunction::Error.new("Bad request", details: result)
|
|
50
|
-
end
|
|
51
|
-
when String
|
|
52
|
-
raise WebFunction::Error.new(result)
|
|
53
|
-
else
|
|
54
|
-
raise WebFunction::Error.new("Bad request", details: result)
|
|
82
|
+
# Creates a new Endpoint from an array of hashes. Uses {Endpoint#from_hash} under the hood.
|
|
83
|
+
#
|
|
84
|
+
# @param endpoints [Array<Hash>] The endpoint array of hashes
|
|
85
|
+
#
|
|
86
|
+
# @return [Array<Endpoint>] A new array of Endpoint instances
|
|
87
|
+
#
|
|
88
|
+
def from_array(endpoints)
|
|
89
|
+
Utils.normalize_array endpoints do |endpoint|
|
|
90
|
+
from_hash(endpoint)
|
|
55
91
|
end
|
|
56
92
|
end
|
|
93
|
+
end
|
|
57
94
|
|
|
58
|
-
|
|
59
|
-
|
|
95
|
+
# The {Client} used to invoke this endpoint. It is assigned when the endpoint is loaded from a package and is
|
|
96
|
+
# required by {#call}.
|
|
97
|
+
#
|
|
98
|
+
# @return [Client, nil]
|
|
99
|
+
#
|
|
100
|
+
attr_accessor :client
|
|
101
|
+
|
|
102
|
+
# The suffix for the endpoint URL, appended to the package's base URL to form the full endpoint URL. Endpoint names
|
|
103
|
+
# are unique within a package; overloading (two endpoints sharing the same name) is not permitted.
|
|
104
|
+
#
|
|
105
|
+
# @return [String]
|
|
106
|
+
#
|
|
107
|
+
attr_reader :name
|
|
108
|
+
|
|
109
|
+
# The JSON type(s) returned by the endpoint. A non-empty array whose entries are each one of:
|
|
110
|
+
#
|
|
111
|
+
# - object
|
|
112
|
+
# - array
|
|
113
|
+
# - string
|
|
114
|
+
# - number
|
|
115
|
+
# - boolean
|
|
116
|
+
# - null
|
|
117
|
+
#
|
|
118
|
+
# @return [Array<String>]
|
|
119
|
+
#
|
|
120
|
+
attr_reader :returns
|
|
121
|
+
|
|
122
|
+
# Hints for the endpoint's return value. Each hint's base JSON type matches one of the endpoint's {#returns} types,
|
|
123
|
+
# and at most one hint is supplied per base JSON type. See the [hints section][1] on the Web Function website for
|
|
124
|
+
# the complete list of allowed hints.
|
|
125
|
+
#
|
|
126
|
+
# @return [Array<String>]
|
|
127
|
+
#
|
|
128
|
+
# [1]: https://webfunction.org/package#hints
|
|
129
|
+
#
|
|
130
|
+
attr_reader :hints
|
|
131
|
+
|
|
132
|
+
# A name used to categorize or group similar endpoints together. This should be used by documentation tools to
|
|
133
|
+
# organize related endpoints.
|
|
134
|
+
#
|
|
135
|
+
# @return [String, nil]
|
|
136
|
+
#
|
|
137
|
+
attr_reader :group
|
|
138
|
+
|
|
139
|
+
# Documentation for the endpoint. It must be formatted as markdown.
|
|
140
|
+
#
|
|
141
|
+
# @return [String]
|
|
142
|
+
#
|
|
143
|
+
attr_reader :docs
|
|
144
|
+
|
|
145
|
+
# Invokes the endpoint through its assigned {#client}, passing the given arguments.
|
|
146
|
+
#
|
|
147
|
+
# @param args [Hash] The arguments to send to the endpoint.
|
|
148
|
+
#
|
|
149
|
+
# @raise [RuntimeError] If no client has been assigned to the endpoint.
|
|
150
|
+
#
|
|
151
|
+
# @return [Object] The decoded response returned by the endpoint.
|
|
152
|
+
#
|
|
153
|
+
def call(args = {})
|
|
154
|
+
unless client
|
|
155
|
+
raise "Client must be set to invoke an endpoint"
|
|
60
156
|
end
|
|
61
157
|
|
|
62
|
-
|
|
63
|
-
rescue JSON::ParserError => e
|
|
64
|
-
raise WebFunction::Error.new("Response cannot be parsed", details: {})
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def name
|
|
68
|
-
@endpoint["name"]
|
|
158
|
+
client.call(name, args)
|
|
69
159
|
end
|
|
70
160
|
|
|
71
|
-
|
|
72
|
-
|
|
161
|
+
# The list of errors specific to this endpoint. Clients SHOULD only refer to this list if the endpoint uses the
|
|
162
|
+
# `error_triple` flag. See the error specification for more information.
|
|
163
|
+
#
|
|
164
|
+
# @return [Array<DocumentedError>]
|
|
165
|
+
#
|
|
166
|
+
def errors
|
|
167
|
+
@errors.values
|
|
73
168
|
end
|
|
74
169
|
|
|
75
|
-
|
|
76
|
-
|
|
170
|
+
# Looks up a single endpoint error by its machine-readable code.
|
|
171
|
+
#
|
|
172
|
+
# @param code [String, Symbol] The error code to look up.
|
|
173
|
+
#
|
|
174
|
+
# @return [DocumentedError, nil] The matching error, or `nil` if none is found.
|
|
175
|
+
#
|
|
176
|
+
def error(code)
|
|
177
|
+
@errors[code.to_s]
|
|
77
178
|
end
|
|
78
179
|
|
|
79
|
-
|
|
80
|
-
|
|
180
|
+
# The attributes of the object returned by the endpoint. Relevant when the endpoint returns an `object`.
|
|
181
|
+
#
|
|
182
|
+
# @return [Array<Attribute>]
|
|
183
|
+
#
|
|
184
|
+
def attributes
|
|
185
|
+
@attributes.values
|
|
81
186
|
end
|
|
82
187
|
|
|
83
|
-
|
|
84
|
-
|
|
188
|
+
# Looks up a single returned attribute by name.
|
|
189
|
+
#
|
|
190
|
+
# @param name [String, Symbol] The name of the attribute to look up.
|
|
191
|
+
#
|
|
192
|
+
# @return [Attribute, nil] The matching attribute, or `nil` if none is found.
|
|
193
|
+
#
|
|
194
|
+
def attribute(name)
|
|
195
|
+
@attributes[name.to_s]
|
|
85
196
|
end
|
|
86
197
|
|
|
198
|
+
# The arguments required by the endpoint. The array is empty when the endpoint requires no arguments.
|
|
199
|
+
#
|
|
200
|
+
# @return [Array<Argument>]
|
|
201
|
+
#
|
|
87
202
|
def arguments
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
end
|
|
203
|
+
@arguments.values
|
|
204
|
+
end
|
|
91
205
|
|
|
92
|
-
|
|
206
|
+
# Looks up a single argument by name.
|
|
207
|
+
#
|
|
208
|
+
# @param name [String, Symbol] The name of the argument to look up.
|
|
209
|
+
#
|
|
210
|
+
# @return [Argument, nil] The matching argument, or `nil` if none is found.
|
|
211
|
+
#
|
|
212
|
+
def argument(name)
|
|
213
|
+
@arguments[name.to_s]
|
|
93
214
|
end
|
|
94
215
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
216
|
+
# Whether the endpoint requires authentication via a bearer token, i.e. whether it declares the `bearer_auth` flag.
|
|
217
|
+
#
|
|
218
|
+
# @return [Boolean]
|
|
219
|
+
#
|
|
220
|
+
def bearer_auth?
|
|
221
|
+
flag?("bearer_auth")
|
|
222
|
+
end
|
|
99
223
|
|
|
100
|
-
|
|
224
|
+
# Whether the endpoint returns a bearer token in its response, i.e. whether it declares the `capture_bearer` flag.
|
|
225
|
+
# See the authentication specification for more information.
|
|
226
|
+
#
|
|
227
|
+
# @return [Boolean]
|
|
228
|
+
#
|
|
229
|
+
def capture_bearer?
|
|
230
|
+
flag?("capture_bearer")
|
|
101
231
|
end
|
|
102
232
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
233
|
+
# Whether the endpoint supports pagination, i.e. whether it declares the `paginated` flag.
|
|
234
|
+
#
|
|
235
|
+
# @return [Boolean]
|
|
236
|
+
#
|
|
237
|
+
def paginated?
|
|
238
|
+
flag?("paginated")
|
|
239
|
+
end
|
|
107
240
|
|
|
108
|
-
|
|
241
|
+
# Whether the endpoint is intended for internal use and is not part of the public API, i.e. whether it declares the
|
|
242
|
+
# `private` flag. Documentation tooling SHOULD omit endpoints with this flag from generated or
|
|
243
|
+
# published documentation.
|
|
244
|
+
#
|
|
245
|
+
# @return [Boolean]
|
|
246
|
+
#
|
|
247
|
+
def private?
|
|
248
|
+
flag?("private")
|
|
109
249
|
end
|
|
110
250
|
end
|
|
111
251
|
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WebFunction
|
|
4
|
+
# A module that provides a flaggable interface. Flags are used to define the behavior of an object.
|
|
5
|
+
#
|
|
6
|
+
# @example
|
|
7
|
+
# class Endpoint
|
|
8
|
+
# include Flaggable
|
|
9
|
+
#
|
|
10
|
+
# def initialize(name:, flags: [])
|
|
11
|
+
# @name = name
|
|
12
|
+
# @flags = flags
|
|
13
|
+
# end
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# endpoint = Endpoint.new(name: "get_user", flags: ["private"])
|
|
17
|
+
# endpoint.flag?("private") # => true
|
|
18
|
+
# endpoint.flag?("public") # => false
|
|
19
|
+
#
|
|
20
|
+
module Flaggable
|
|
21
|
+
# List of flags. See the [available flags section][2] on the Web Function
|
|
22
|
+
# website for a complete list of flags available.
|
|
23
|
+
#
|
|
24
|
+
# @return [Array<String>]
|
|
25
|
+
#
|
|
26
|
+
# [2]: https://webfunction.org/package#available-flags
|
|
27
|
+
#
|
|
28
|
+
attr_reader :flags
|
|
29
|
+
|
|
30
|
+
# Whether the endpoint declares the given flag.
|
|
31
|
+
#
|
|
32
|
+
# @param flag [String] The flag to check for.
|
|
33
|
+
#
|
|
34
|
+
# @return [Boolean]
|
|
35
|
+
#
|
|
36
|
+
def flag?(flag)
|
|
37
|
+
@flags.include?(flag)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
data/lib/web_function/package.rb
CHANGED
|
@@ -1,41 +1,156 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module WebFunction
|
|
4
|
+
# Organize, document, and validate endpoints. A package facilitates {Endpoint} discovery and integration by providing
|
|
5
|
+
# standardized metadata about them.
|
|
6
|
+
#
|
|
7
|
+
# A package bundles a base URL together with the endpoints it exposes, as well as optional metadata such as a name,
|
|
8
|
+
# version information, top-level documentation, and a list of common errors.
|
|
9
|
+
#
|
|
10
|
+
# See the [package specification][0] on the Web Function website for the full description of every recognized key and
|
|
11
|
+
# its constraints.
|
|
12
|
+
#
|
|
13
|
+
# [0]: https://webfunction.org/package
|
|
14
|
+
#
|
|
4
15
|
class Package
|
|
5
|
-
|
|
6
|
-
@package = package
|
|
7
|
-
end
|
|
16
|
+
include Flaggable
|
|
8
17
|
|
|
9
|
-
def base_url
|
|
10
|
-
|
|
18
|
+
def initialize(base_url:, pipeline_url: nil, name: nil, version: nil, docs: nil, flags: [], versions: [],
|
|
19
|
+
endpoints: [], errors: [])
|
|
20
|
+
@base_url = base_url
|
|
21
|
+
@pipeline_url = pipeline_url
|
|
22
|
+
@name = name
|
|
23
|
+
@version = version
|
|
24
|
+
@docs = docs.to_s
|
|
25
|
+
@flags = flags
|
|
26
|
+
@versions = versions
|
|
27
|
+
@endpoints = endpoints.to_h { |e| [e.name, e] }
|
|
28
|
+
@errors = errors.to_h { |e| [e.code, e] }
|
|
11
29
|
end
|
|
12
30
|
|
|
13
|
-
|
|
14
|
-
|
|
31
|
+
class << self
|
|
32
|
+
# Instantiate a new Package from a hash.
|
|
33
|
+
#
|
|
34
|
+
# @param package [Hash] The package hash
|
|
35
|
+
#
|
|
36
|
+
# @return [Package] A new Package instance
|
|
37
|
+
#
|
|
38
|
+
def from_hash(package)
|
|
39
|
+
new(
|
|
40
|
+
base_url: package["base_url"],
|
|
41
|
+
pipeline_url: package["pipeline_url"],
|
|
42
|
+
name: package["name"],
|
|
43
|
+
version: package["version"],
|
|
44
|
+
docs: package["docs"],
|
|
45
|
+
flags: Utils.normalize_array_of_strings(package["flags"]),
|
|
46
|
+
versions: Utils.normalize_array_of_strings(package["versions"]),
|
|
47
|
+
endpoints: Endpoint.from_array(package["endpoints"]),
|
|
48
|
+
errors: DocumentedError.from_array(package["errors"]),
|
|
49
|
+
)
|
|
50
|
+
end
|
|
15
51
|
end
|
|
16
52
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
53
|
+
# The base URL for the package. Endpoint URLs are formed by joining this base URL with each endpoint's name.
|
|
54
|
+
#
|
|
55
|
+
# This is required for the package to be valid and MUST use the HTTP or HTTPS scheme.
|
|
56
|
+
#
|
|
57
|
+
# @return [String]
|
|
58
|
+
#
|
|
59
|
+
attr_reader :base_url
|
|
60
|
+
|
|
61
|
+
# A function pipelining URL used to batch several endpoint invocations into a single request. See the pipelining
|
|
62
|
+
# specification for more information.
|
|
63
|
+
#
|
|
64
|
+
# @return [String, nil]
|
|
65
|
+
#
|
|
66
|
+
attr_reader :pipeline_url
|
|
67
|
+
|
|
68
|
+
# The name of the package.
|
|
69
|
+
#
|
|
70
|
+
# @return [String, nil]
|
|
71
|
+
#
|
|
72
|
+
attr_reader :name
|
|
73
|
+
|
|
74
|
+
# The version that this package describes. An opaque string.
|
|
75
|
+
#
|
|
76
|
+
# This MUST be present when the `versioned` flag is set. See the versioning specification for more information.
|
|
77
|
+
#
|
|
78
|
+
# @return [String, nil]
|
|
79
|
+
#
|
|
80
|
+
attr_reader :version
|
|
81
|
+
|
|
82
|
+
# Top-level documentation for the package. It must be formatted as markdown.
|
|
83
|
+
#
|
|
84
|
+
# @return [String]
|
|
85
|
+
#
|
|
86
|
+
attr_reader :docs
|
|
87
|
+
|
|
88
|
+
# The versions that are available. Each entry is an opaque string.
|
|
89
|
+
#
|
|
90
|
+
# This MUST be present when the `versioned` flag is set. See the versioning specification for more information.
|
|
91
|
+
#
|
|
92
|
+
# @return [Array<String>]
|
|
93
|
+
#
|
|
94
|
+
attr_reader :versions
|
|
20
95
|
|
|
21
|
-
|
|
22
|
-
|
|
96
|
+
# The {Pipeline} for this package, built from {#pipeline_url}, or `nil` when the package does not declare a
|
|
97
|
+
# pipeline URL.
|
|
98
|
+
#
|
|
99
|
+
# @return [Pipeline, nil]
|
|
100
|
+
#
|
|
101
|
+
def pipeline
|
|
102
|
+
unless pipeline_url
|
|
103
|
+
return
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
Pipeline.new(pipeline_url)
|
|
23
107
|
end
|
|
24
108
|
|
|
109
|
+
# The endpoints declared by this package.
|
|
110
|
+
#
|
|
111
|
+
# @return [Array<Endpoint>]
|
|
112
|
+
#
|
|
25
113
|
def endpoints
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
end
|
|
114
|
+
@endpoints.values
|
|
115
|
+
end
|
|
29
116
|
|
|
30
|
-
|
|
117
|
+
# Looks up a single endpoint by name. Underscores in the given name are converted to hyphens so that Ruby-style
|
|
118
|
+
# names (e.g. `:find_user_by`) match the hyphenated endpoint names used in packages (e.g. `find-user-by`).
|
|
119
|
+
#
|
|
120
|
+
# @param name [String, Symbol] The name of the endpoint to look up.
|
|
121
|
+
#
|
|
122
|
+
# @return [Endpoint, nil] The matching endpoint, or `nil` if none is found.
|
|
123
|
+
#
|
|
124
|
+
def endpoint(name)
|
|
125
|
+
@endpoints[name.to_s.gsub("_", "-")]
|
|
31
126
|
end
|
|
32
127
|
|
|
128
|
+
# The list of common errors that can be returned by any endpoint in this package. Only refer to this list if an
|
|
129
|
+
# endpoint uses the `error_triple` flag. See the error specification for more information.
|
|
130
|
+
#
|
|
131
|
+
# @return [Array<DocumentedError>]
|
|
132
|
+
#
|
|
33
133
|
def errors
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
134
|
+
@errors.values
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Looks up a single common error by its machine-readable code.
|
|
138
|
+
#
|
|
139
|
+
# @param code [String, Symbol] The error code to look up.
|
|
140
|
+
#
|
|
141
|
+
# @return [DocumentedError, nil] The matching error, or `nil` if none is found.
|
|
142
|
+
#
|
|
143
|
+
def error(code)
|
|
144
|
+
@errors[code.to_s]
|
|
145
|
+
end
|
|
37
146
|
|
|
38
|
-
|
|
147
|
+
# Whether the package is versioned, i.e. whether it declares the `versioned` flag. A versioned package is selected
|
|
148
|
+
# using the `Api-Version` header.
|
|
149
|
+
#
|
|
150
|
+
# @return [Boolean]
|
|
151
|
+
#
|
|
152
|
+
def versioned?
|
|
153
|
+
flag?("versioned")
|
|
39
154
|
end
|
|
40
155
|
end
|
|
41
156
|
end
|
|
@@ -1,4 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module WebFunction
|
|
4
|
+
# A pipeline is a sequence of steps that are executed in order.
|
|
5
|
+
#
|
|
6
|
+
# @example
|
|
7
|
+
# pipeline = WebFunction::Pipeline.new("https://pipe.example/exec")
|
|
8
|
+
# pipeline.add_step({ url: "https://a", headers: {}, body: {} })
|
|
9
|
+
# pipeline.add_step({ url: "https://b", headers: {}, body: {} })
|
|
10
|
+
# pipeline.execute(returns: :all) # => [{ "a" => 1 }, { "b" => 2 }]
|
|
11
|
+
#
|
|
2
12
|
class Pipeline
|
|
3
13
|
def initialize(url)
|
|
4
14
|
@url = url
|
|
@@ -6,6 +16,12 @@ module WebFunction
|
|
|
6
16
|
@promises = []
|
|
7
17
|
end
|
|
8
18
|
|
|
19
|
+
# Adds a step to the pipeline.
|
|
20
|
+
#
|
|
21
|
+
# @param step [Hash] The step to add
|
|
22
|
+
#
|
|
23
|
+
# @return [Promise] A new Promise instance
|
|
24
|
+
#
|
|
9
25
|
def add_step(step)
|
|
10
26
|
n = @promises.count
|
|
11
27
|
promise = Promise.new(self, "$[#{n}]")
|
|
@@ -16,13 +32,20 @@ module WebFunction
|
|
|
16
32
|
promise
|
|
17
33
|
end
|
|
18
34
|
|
|
35
|
+
# Executes the pipeline.
|
|
36
|
+
#
|
|
37
|
+
# @param returns [String, Symbol] The return type or a JSONPath expression to return a specific value.
|
|
38
|
+
#
|
|
39
|
+
# @return [Object] The response returned by the pipeline.
|
|
40
|
+
#
|
|
19
41
|
def execute(returns: :all)
|
|
20
42
|
case returns
|
|
21
43
|
when :all
|
|
22
|
-
responses =
|
|
44
|
+
responses = Request.execute(@url, args: {
|
|
23
45
|
steps: @steps,
|
|
24
46
|
returns: "$",
|
|
25
|
-
}
|
|
47
|
+
},
|
|
48
|
+
)
|
|
26
49
|
|
|
27
50
|
responses.each_with_index do |response, index|
|
|
28
51
|
@promises[index].value = response
|
|
@@ -32,10 +55,11 @@ module WebFunction
|
|
|
32
55
|
|
|
33
56
|
responses
|
|
34
57
|
when :last
|
|
35
|
-
response =
|
|
58
|
+
response = Request.execute(@url, args: {
|
|
36
59
|
steps: @steps,
|
|
37
60
|
returns: "$[-1:]",
|
|
38
|
-
}
|
|
61
|
+
},
|
|
62
|
+
)
|
|
39
63
|
|
|
40
64
|
@promises.last.value = response
|
|
41
65
|
|
|
@@ -43,10 +67,11 @@ module WebFunction
|
|
|
43
67
|
|
|
44
68
|
response
|
|
45
69
|
else
|
|
46
|
-
response =
|
|
70
|
+
response = Request.execute(@url, args: {
|
|
47
71
|
steps: @steps,
|
|
48
72
|
returns: returns,
|
|
49
|
-
}
|
|
73
|
+
},
|
|
74
|
+
)
|
|
50
75
|
|
|
51
76
|
reset!
|
|
52
77
|
|
|
@@ -54,6 +79,10 @@ module WebFunction
|
|
|
54
79
|
end
|
|
55
80
|
end
|
|
56
81
|
|
|
82
|
+
# Resets the pipeline.
|
|
83
|
+
#
|
|
84
|
+
# @return [void]
|
|
85
|
+
#
|
|
57
86
|
def reset!
|
|
58
87
|
@steps = []
|
|
59
88
|
@promises = []
|