scorpio 0.4.2 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/README.md +7 -7
- data/Rakefile +1 -1
- data/lib/scorpio/google_api_document.rb +5 -21
- data/lib/scorpio/openapi.rb +4 -2
- data/lib/scorpio/openapi/document.rb +1 -1
- data/lib/scorpio/resource_base.rb +6 -6
- data/lib/scorpio/version.rb +1 -1
- data/scorpio.gemspec +3 -3
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ebea8c54d7cec0fb3572cffc6f2992882d6fd7a82739abf6656a96d095d523a7
|
4
|
+
data.tar.gz: a76428a2b3c8cfd00f0a3f9f639795bdcb3ac770bd97813bf4a44336158ec753
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f10e3c1ff2bdcfb1d3f5c8459f411508dadcd9a8f0531b1e770a5370011b4946790b6d248baace076fc99f52c0dcafcda0d7e16113ee185ae09baf9515e24f18
|
7
|
+
data.tar.gz: ed13200947e100a9ecb6d9ea38ed57abd1649b16144652ee9ef772a74d253416514fdee186666469009a7abb41f247af809bdc4c29ba66e374d225c9a8bd58da
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -3,13 +3,13 @@
|
|
3
3
|
[![Build Status](https://travis-ci.org/notEthan/scorpio.svg?branch=master)](https://travis-ci.org/notEthan/scorpio)
|
4
4
|
[![Coverage Status](https://coveralls.io/repos/github/notEthan/scorpio/badge.svg)](https://coveralls.io/github/notEthan/scorpio)
|
5
5
|
|
6
|
-
Scorpio is a library that helps you, as a client, consume an HTTP service described by an OpenAPI document. You provide the OpenAPI
|
6
|
+
Scorpio is a library that helps you, as a client, consume an HTTP service described by an OpenAPI document. You provide the OpenAPI description document, a little bit of configuration, and Scorpio will take that and dynamically generate an interface for you to call the service's operations and interact with its resources as an ORM.
|
7
7
|
|
8
8
|
Note: The canonical location of this README is on [RubyDoc](http://rubydoc.info/gems/scorpio/). When viewed on [Github](https://github.com/notEthan/scorpio/), it may be inconsistent with the latest released gem, and Yardoc links will not work.
|
9
9
|
|
10
10
|
## Background
|
11
11
|
|
12
|
-
To start with, you need an OpenAPI (formerly known as Swagger) document describing a service you will be consuming. v2 and v3 are both supported.[^1] This document can be written by hand or sometimes generated from other existing sources. The creation of an OpenAPI document
|
12
|
+
To start with, you need an OpenAPI (formerly known as Swagger) document describing a service you will be consuming. v2 and v3 are both supported.[^1] This document can be written by hand or sometimes generated from other existing sources. The creation of an OpenAPI document describing your service is outside the scope of Scorpio. Here are several resources on OpenAPI:
|
13
13
|
|
14
14
|
- [OpenAPI Specification at Wikipedia](https://en.wikipedia.org/wiki/OpenAPI_Specification)
|
15
15
|
- [OpenAPI Initiative](https://www.openapis.org/) is the official web site for OpenAPI
|
@@ -26,7 +26,7 @@ Once you have the OpenAPI document describing the service you will consume, you
|
|
26
26
|
|
27
27
|
Let's dive into some code, shall we? If you have learned about OpenAPI, you likely learned using the example of the Pet Store service. This README will use the same service. Its documentation is at http://petstore.swagger.io/.
|
28
28
|
|
29
|
-
Using the
|
29
|
+
Using the OpenAPI document, we can start interacting with the pet store with very little code. Here is that code, with explanations of each part in the comments.
|
30
30
|
|
31
31
|
```ruby
|
32
32
|
require 'scorpio'
|
@@ -195,13 +195,13 @@ Its API is described in `test/blog.openapi.yml`, defining the Article resource,
|
|
195
195
|
|
196
196
|
## Scorpio::ResourceBase
|
197
197
|
|
198
|
-
Scorpio::ResourceBase is the main class used in abstracting on OpenAPI document. Scorpio::ResourceBase aims to represent RESTful resources in ruby classes with as little code as possible, given a service with a properly constructed OpenAPI
|
198
|
+
Scorpio::ResourceBase is the main class used in abstracting on OpenAPI document. Scorpio::ResourceBase aims to represent RESTful resources in ruby classes with as little code as possible, given a service with a properly constructed OpenAPI document.
|
199
199
|
|
200
200
|
A class which subclasses Scorpio::ResourceBase directly (such as PetStore::Resource above) should generally represent the whole API - you set the openapi_document and other configuration on this class. As such, it is generally not instantiated. Its subclasses, representing resources with a tag or with schema definitions in the OpenAPI document, are what you mostly instantiate and interact with.
|
201
201
|
|
202
202
|
A model representing a resource needs to be configured, minimally, with:
|
203
203
|
|
204
|
-
- the OpenAPI
|
204
|
+
- the OpenAPI document for the REST API
|
205
205
|
- the schemas that represent instances of the model, if any
|
206
206
|
|
207
207
|
If the resource has HTTP operations associated with it (most, but not all resources will):
|
@@ -210,7 +210,7 @@ If the resource has HTTP operations associated with it (most, but not all resour
|
|
210
210
|
|
211
211
|
When these are set, Scorpio::ResourceBase looks through the API description and dynamically sets up methods for the model:
|
212
212
|
|
213
|
-
- accessors for properties of the model defined as properties of schemas representing the resource in the
|
213
|
+
- accessors for properties of the model defined as properties of schemas representing the resource in the description document
|
214
214
|
- API method calls on the model class and, where appropriate, on the model instance
|
215
215
|
|
216
216
|
## Scorpio::Ur
|
@@ -250,7 +250,7 @@ end
|
|
250
250
|
|
251
251
|
## Other
|
252
252
|
|
253
|
-
The detailed, machine-interpretable description of an API provided by a properly-constructed OpenAPI
|
253
|
+
The detailed, machine-interpretable description of an API provided by a properly-constructed OpenAPI document opens up numerous possibilities to automate aspects of clients and services to an API. These are planned to be implemented in Scorpio:
|
254
254
|
|
255
255
|
- constructing test objects in a manner similar to FactoryBot, allowing you to write tests that depend on a service without having to interact with an actual running instance of that service to run your tests
|
256
256
|
- rack middleware to test that outgoing HTTP responses are conformant to their response schemas
|
data/Rakefile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Scorpio
|
2
2
|
module Google
|
3
|
-
discovery_rest_description_doc = JSI::JSON::Node.
|
3
|
+
discovery_rest_description_doc = JSI::JSON::Node.new_doc(::JSON.parse(Scorpio.root.join('documents/www.googleapis.com/discovery/v1/apis/discovery/v1/rest').read))
|
4
4
|
|
5
5
|
discovery_metaschema = discovery_rest_description_doc['schemas']['JsonSchema']
|
6
6
|
rest_description_schema = JSI.class_for_schema(discovery_metaschema).new(discovery_rest_description_doc['schemas']['RestDescription'])
|
@@ -18,7 +18,7 @@ module Scorpio
|
|
18
18
|
# google does a weird thing where it defines a schema with a $ref property where a json-schema is to be used in the document (method request and response fields), instead of just setting the schema to be the json-schema schema. we'll share a module across those schema classes that really represent schemas. is this confusingly meta enough?
|
19
19
|
module SchemaLike
|
20
20
|
def to_openapi
|
21
|
-
dup_doc = ::
|
21
|
+
dup_doc = JSI::Typelike.as_json(self)
|
22
22
|
# openapi does not want an id field on schemas
|
23
23
|
dup_doc.delete('id')
|
24
24
|
if dup_doc['properties'].is_a?(Hash)
|
@@ -40,12 +40,12 @@ module Scorpio
|
|
40
40
|
|
41
41
|
class RestDescription
|
42
42
|
def to_openapi_document(options = {})
|
43
|
-
Scorpio::OpenAPI::
|
43
|
+
Scorpio::OpenAPI::Document.from_instance(to_openapi_hash(options))
|
44
44
|
end
|
45
45
|
|
46
46
|
def to_openapi_hash(options = {})
|
47
47
|
# we will be modifying the api document (RestDescription). clone self and modify that one.
|
48
|
-
ad = self.class.new(::
|
48
|
+
ad = self.class.new(JSI::Typelike.as_json(instance))
|
49
49
|
ad_methods = []
|
50
50
|
if ad['methods']
|
51
51
|
ad_methods += ad['methods'].map do |mn, m|
|
@@ -200,23 +200,7 @@ module Scorpio
|
|
200
200
|
end.call(openapi)
|
201
201
|
end
|
202
202
|
end
|
203
|
-
|
204
|
-
openapi = JSI::Util.ycomb do |rec|
|
205
|
-
proc do |object|
|
206
|
-
object = object.to_openapi if object.respond_to?(:to_openapi)
|
207
|
-
if object.respond_to?(:to_hash)
|
208
|
-
object.map { |k, v| {rec.call(k) => rec.call(v)} }.inject({}, &:update)
|
209
|
-
elsif object.respond_to?(:to_ary)
|
210
|
-
object.map(&rec)
|
211
|
-
elsif object.is_a?(Symbol)
|
212
|
-
object.to_s
|
213
|
-
elsif [String, TrueClass, FalseClass, NilClass, Numeric].any? { |c| object.is_a?(c) }
|
214
|
-
object
|
215
|
-
else
|
216
|
-
raise(TypeError, "bad (not jsonifiable) object: #{object.pretty_inspect}")
|
217
|
-
end
|
218
|
-
end
|
219
|
-
end.call(openapi)
|
203
|
+
JSI::Typelike.as_json(openapi)
|
220
204
|
end
|
221
205
|
end
|
222
206
|
end
|
data/lib/scorpio/openapi.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
module Scorpio
|
2
2
|
module OpenAPI
|
3
|
-
# an error in the semantics of
|
4
|
-
# two body parameters (in v2, not possible in v3) is a
|
3
|
+
# an error in the semantics of an openapi document. for example, an Operation with
|
4
|
+
# two body parameters (in v2, not possible in v3) is a SemanticError. an Operation
|
5
|
+
# with more than one parameter with the same 'name' and 'in' properties would also be
|
6
|
+
# a SemanticError.
|
5
7
|
#
|
6
8
|
# an instance of a SemanticError may or may not correspond to a validation error of
|
7
9
|
# an OpenAPI document against the OpenAPI schema.
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Scorpio
|
2
2
|
module OpenAPI
|
3
3
|
# A document that defines or describes an API.
|
4
|
-
# An OpenAPI
|
4
|
+
# An OpenAPI description document uses and conforms to the OpenAPI Specification.
|
5
5
|
#
|
6
6
|
# Scorpio::OpenAPI::Document is a module common to V2 and V3 documents.
|
7
7
|
module Document
|
@@ -257,7 +257,7 @@ module Scorpio
|
|
257
257
|
end
|
258
258
|
|
259
259
|
def call_operation(operation, call_params: nil, model_attributes: nil)
|
260
|
-
call_params = JSI.stringify_symbol_keys(call_params) if call_params.
|
260
|
+
call_params = JSI.stringify_symbol_keys(call_params) if call_params.respond_to?(:to_hash)
|
261
261
|
model_attributes = JSI.stringify_symbol_keys(model_attributes || {})
|
262
262
|
|
263
263
|
request = Scorpio::Request.new(operation)
|
@@ -312,7 +312,7 @@ module Scorpio
|
|
312
312
|
# TODO deal with model_attributes / call_params better in nested whatever
|
313
313
|
if call_params.nil?
|
314
314
|
request.body_object = request_body_for_schema(model_attributes, operation.request_schema)
|
315
|
-
elsif call_params.
|
315
|
+
elsif call_params.respond_to?(:to_hash)
|
316
316
|
body = request_body_for_schema(model_attributes.merge(call_params), operation.request_schema)
|
317
317
|
request.body_object = body.merge(call_params) # TODO
|
318
318
|
else
|
@@ -323,7 +323,7 @@ module Scorpio
|
|
323
323
|
if METHODS_WITH_BODIES.any? { |m| m.to_s == operation.http_method.downcase.to_s }
|
324
324
|
request.body_object = other_params
|
325
325
|
else
|
326
|
-
if other_params.
|
326
|
+
if other_params.respond_to?(:to_hash)
|
327
327
|
# TODO pay more attention to 'parameters' api method attribute
|
328
328
|
request.query_params = other_params
|
329
329
|
else
|
@@ -354,12 +354,12 @@ module Scorpio
|
|
354
354
|
elsif object.is_a?(JSI::JSON::Node)
|
355
355
|
request_body_for_schema(object.content, schema)
|
356
356
|
else
|
357
|
-
if object.
|
357
|
+
if object.respond_to?(:to_hash)
|
358
358
|
object.map do |key, value|
|
359
359
|
if schema
|
360
360
|
if schema['type'] == 'object'
|
361
361
|
# TODO code dup with response_object_to_instances
|
362
|
-
if schema['properties'].respond_to?(:to_hash) && schema['properties']
|
362
|
+
if schema['properties'].respond_to?(:to_hash) && schema['properties'].key?(key)
|
363
363
|
subschema = schema['properties'][key]
|
364
364
|
include_pair = true
|
365
365
|
else
|
@@ -397,7 +397,7 @@ module Scorpio
|
|
397
397
|
{}
|
398
398
|
end
|
399
399
|
end.inject({}, &:update)
|
400
|
-
elsif object.
|
400
|
+
elsif object.respond_to?(:to_ary) || object.is_a?(Set)
|
401
401
|
object.map do |el|
|
402
402
|
if schema
|
403
403
|
if schema['type'] == 'array'
|
data/lib/scorpio/version.rb
CHANGED
data/scorpio.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
|
|
7
7
|
spec.name = "scorpio"
|
8
8
|
spec.version = Scorpio::VERSION
|
9
9
|
spec.authors = ["Ethan"]
|
10
|
-
spec.email = ["ethan@unth"]
|
10
|
+
spec.email = ["ethan@unth.net"]
|
11
11
|
|
12
12
|
spec.summary = 'Scorpio REST client'
|
13
13
|
spec.description = 'ORM style REST client'
|
@@ -20,8 +20,8 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
21
|
spec.require_paths = ["lib"]
|
22
22
|
|
23
|
-
spec.add_dependency "jsi", "~> 0.0
|
24
|
-
spec.add_dependency "ur", "~> 0.0.
|
23
|
+
spec.add_dependency "jsi", "~> 0.1.0"
|
24
|
+
spec.add_dependency "ur", "~> 0.0.3"
|
25
25
|
spec.add_dependency "faraday"
|
26
26
|
spec.add_development_dependency "rake", "~> 10.0"
|
27
27
|
spec.add_development_dependency "minitest", "~> 5.0"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scorpio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ethan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jsi
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.0
|
19
|
+
version: 0.1.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.0
|
26
|
+
version: 0.1.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: ur
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.0.
|
33
|
+
version: 0.0.3
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.0.
|
40
|
+
version: 0.0.3
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: faraday
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -250,7 +250,7 @@ dependencies:
|
|
250
250
|
version: '0'
|
251
251
|
description: ORM style REST client
|
252
252
|
email:
|
253
|
-
- ethan@unth
|
253
|
+
- ethan@unth.net
|
254
254
|
executables: []
|
255
255
|
extensions: []
|
256
256
|
extra_rdoc_files: []
|