web_function 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 +4 -4
- data/exe/wfn +12 -5
- data/lib/web_function/argument.rb +87 -59
- data/lib/web_function/attribute.rb +83 -59
- data/lib/web_function/client.rb +83 -39
- data/lib/web_function/documented_error.rb +47 -19
- data/lib/web_function/endpoint.rb +190 -172
- data/lib/web_function/flaggable.rb +40 -0
- data/lib/web_function/package.rb +132 -43
- data/lib/web_function/pipeline.rb +35 -6
- data/lib/web_function/promise.rb +68 -0
- 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 +21 -11
- data/test.rb +43 -0
- metadata +5 -1
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module WebFunction
|
|
4
|
-
# # Endpoint
|
|
5
|
-
#
|
|
6
4
|
# Represents an endpoint as described in a Web Function package.
|
|
7
5
|
#
|
|
8
|
-
# An endpoint defines an operation that can be performed via a Web Function API.
|
|
9
|
-
#
|
|
10
|
-
#
|
|
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:
|
|
11
10
|
#
|
|
12
|
-
# Endpoints are described as objects in each package under the `"endpoints"` key.
|
|
13
|
-
# For more information, see:
|
|
14
11
|
# - [Web Function package docs](https://webfunction.org/package)
|
|
15
12
|
# - [Web Function endpoint docs](https://webfunction.org/endpoint)
|
|
16
13
|
#
|
|
17
|
-
# This class provides methods for accessing endpoint metadata (name, docs, arguments, attributes, errors)
|
|
18
|
-
#
|
|
14
|
+
# This class provides methods for accessing endpoint metadata (name, docs, arguments, attributes, errors) and
|
|
15
|
+
# supports invocation via HTTP.
|
|
19
16
|
#
|
|
20
17
|
# Typical tasks include:
|
|
18
|
+
#
|
|
21
19
|
# - Querying endpoint name or documentation
|
|
22
20
|
# - Enumerating the arguments or attributes definitions
|
|
23
21
|
# - Invoking the endpoint through HTTP using required inputs
|
|
@@ -25,209 +23,229 @@ module WebFunction
|
|
|
25
23
|
# See: https://webfunction.org/endpoint for more details on endpoint structure and contract.
|
|
26
24
|
#
|
|
27
25
|
class Endpoint
|
|
28
|
-
|
|
29
|
-
|
|
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] }
|
|
30
38
|
end
|
|
31
39
|
|
|
32
40
|
class << self
|
|
33
|
-
#
|
|
41
|
+
# Invokes an endpoint through HTTP using the given URL, bearer authentication, version, and arguments.
|
|
34
42
|
#
|
|
35
|
-
#
|
|
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
|
|
36
47
|
#
|
|
37
|
-
# @return [
|
|
48
|
+
# @return [Object] The response returned by the endpoint
|
|
38
49
|
#
|
|
39
|
-
def
|
|
40
|
-
|
|
41
|
-
response = Excon.post(url,
|
|
42
|
-
headers: headers,
|
|
43
|
-
body: body,
|
|
44
|
-
)
|
|
45
|
-
[response.status, response.body]
|
|
46
|
-
end
|
|
50
|
+
def invoke(url, bearer_auth: nil, version: nil, args: {})
|
|
51
|
+
Request.execute(url, bearer_auth: bearer_auth, version: version, args: args)
|
|
47
52
|
end
|
|
48
53
|
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
# Sets the HTTP client used to invoke the endpoint.
|
|
52
|
-
#
|
|
53
|
-
# To provide a custom HTTP client instead of the default (which uses Excon),
|
|
54
|
-
# set this to any object responding to #call or a Proc/lambda.
|
|
55
|
-
#
|
|
56
|
-
# The contract is:
|
|
57
|
-
# client.call(url, headers, body)
|
|
54
|
+
# Creates a new Endpoint from a hash.
|
|
58
55
|
#
|
|
59
|
-
#
|
|
60
|
-
# - headers:[Hash<String,String>] HTTP headers, e.g. { "Content-Type" => "application/json" }
|
|
61
|
-
# - body: [String] The JSON body to post.
|
|
56
|
+
# @param endpoint [Hash] The endpoint hash
|
|
62
57
|
#
|
|
63
|
-
#
|
|
64
|
-
# - status: [Integer] HTTP status code (e.g. 200, 400, 500)
|
|
65
|
-
# - body: [String] Raw response body as a string
|
|
58
|
+
# @return [Endpoint] A new Endpoint instance
|
|
66
59
|
#
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
# [http_response.status, http_response.body]
|
|
71
|
-
# }
|
|
72
|
-
#
|
|
73
|
-
# @param http_client [Proc,#call] The new HTTP client to use.
|
|
74
|
-
#
|
|
75
|
-
attr_writer :http_client
|
|
76
|
-
|
|
77
|
-
def step(url, bearer_auth: nil, args: {})
|
|
78
|
-
headers = {
|
|
79
|
-
"Content-Type": "application/json",
|
|
80
|
-
"Accept": "application/json",
|
|
81
|
-
"User-Agent": "webfunction/#{WebFunction::VERSION}",
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if args.nil?
|
|
85
|
-
args = {}
|
|
60
|
+
def from_hash(endpoint)
|
|
61
|
+
unless endpoint.is_a?(Hash)
|
|
62
|
+
return
|
|
86
63
|
end
|
|
87
64
|
|
|
88
|
-
|
|
89
|
-
|
|
65
|
+
unless endpoint["name"]
|
|
66
|
+
return
|
|
90
67
|
end
|
|
91
68
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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
|
+
)
|
|
97
80
|
end
|
|
98
81
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
if bearer_auth
|
|
111
|
-
headers["Authorization"] = "Bearer #{bearer_auth}"
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
status, body = http_client.call(url, headers, JSON.generate(args))
|
|
115
|
-
|
|
116
|
-
unless [200, 400].include?(status)
|
|
117
|
-
raise WebFunction::UnexpectedStatusCodeError.new("Unexpected status code (#{status})",
|
|
118
|
-
details: {
|
|
119
|
-
status_code: status,
|
|
120
|
-
raw_body: body,
|
|
121
|
-
},
|
|
122
|
-
)
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
begin
|
|
126
|
-
result = JSON.parse(body)
|
|
127
|
-
rescue JSON::ParserError => e
|
|
128
|
-
raise WebFunction::JsonParseError.new(e.message,
|
|
129
|
-
details: {
|
|
130
|
-
status_code: status,
|
|
131
|
-
raw_body: body,
|
|
132
|
-
original_exception: e,
|
|
133
|
-
},
|
|
134
|
-
)
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
if status == 400
|
|
138
|
-
code = "BAD_REQUEST"
|
|
139
|
-
message = "Bad request"
|
|
140
|
-
details = { body: result }
|
|
141
|
-
|
|
142
|
-
if result.is_a?(Array) && result.length == 3 && result[0].is_a?(String) && result[1].is_a?(String)
|
|
143
|
-
code = result[0]
|
|
144
|
-
message = result[1]
|
|
145
|
-
details = result[2]
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
raise WebFunction::BadRequestError.new(message, code: code, details: details)
|
|
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)
|
|
149
91
|
end
|
|
150
|
-
|
|
151
|
-
result
|
|
152
92
|
end
|
|
153
93
|
end
|
|
154
94
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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"
|
|
156
|
+
end
|
|
158
157
|
|
|
159
|
-
|
|
160
|
-
[*@endpoint["returns"]].map { |type| type.to_s }
|
|
158
|
+
client.call(name, args)
|
|
161
159
|
end
|
|
162
160
|
|
|
163
|
-
|
|
164
|
-
|
|
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
|
|
165
168
|
end
|
|
166
169
|
|
|
167
|
-
|
|
168
|
-
|
|
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]
|
|
169
178
|
end
|
|
170
179
|
|
|
171
|
-
|
|
172
|
-
|
|
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
|
|
173
186
|
end
|
|
174
187
|
|
|
175
|
-
|
|
176
|
-
|
|
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]
|
|
177
196
|
end
|
|
178
197
|
|
|
198
|
+
# The arguments required by the endpoint. The array is empty when the endpoint requires no arguments.
|
|
199
|
+
#
|
|
200
|
+
# @return [Array<Argument>]
|
|
201
|
+
#
|
|
179
202
|
def arguments
|
|
180
|
-
|
|
181
|
-
return []
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
@endpoint["arguments"].map do |argument|
|
|
185
|
-
unless argument.is_a?(Hash)
|
|
186
|
-
next
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
unless argument["name"]
|
|
190
|
-
next
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
Argument.new(argument)
|
|
194
|
-
end
|
|
203
|
+
@arguments.values
|
|
195
204
|
end
|
|
196
205
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
unless attribute["name"]
|
|
208
|
-
next
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
Attribute.new(attribute)
|
|
212
|
-
end
|
|
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]
|
|
213
214
|
end
|
|
214
215
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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
|
|
219
223
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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")
|
|
231
|
+
end
|
|
224
232
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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
|
|
228
240
|
|
|
229
|
-
|
|
230
|
-
|
|
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")
|
|
231
249
|
end
|
|
232
250
|
end
|
|
233
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,67 +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
|
-
|
|
20
|
-
|
|
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
|
|
21
60
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
|
26
67
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
68
|
+
# The name of the package.
|
|
69
|
+
#
|
|
70
|
+
# @return [String, nil]
|
|
71
|
+
#
|
|
72
|
+
attr_reader :name
|
|
30
73
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
|
35
81
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
82
|
+
# Top-level documentation for the package. It must be formatted as markdown.
|
|
83
|
+
#
|
|
84
|
+
# @return [String]
|
|
85
|
+
#
|
|
86
|
+
attr_reader :docs
|
|
40
87
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
|
44
95
|
|
|
45
|
-
|
|
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
|
|
46
104
|
end
|
|
105
|
+
|
|
106
|
+
Pipeline.new(pipeline_url)
|
|
47
107
|
end
|
|
48
108
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
109
|
+
# The endpoints declared by this package.
|
|
110
|
+
#
|
|
111
|
+
# @return [Array<Endpoint>]
|
|
112
|
+
#
|
|
113
|
+
def endpoints
|
|
114
|
+
@endpoints.values
|
|
115
|
+
end
|
|
53
116
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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("_", "-")]
|
|
126
|
+
end
|
|
58
127
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
+
#
|
|
133
|
+
def errors
|
|
134
|
+
@errors.values
|
|
135
|
+
end
|
|
62
136
|
|
|
63
|
-
|
|
64
|
-
|
|
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
|
|
146
|
+
|
|
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")
|
|
65
154
|
end
|
|
66
155
|
end
|
|
67
156
|
end
|