Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .yardopts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@
--markup=markdown
--markup-provider=redcarpet
--no-private
--hide-void-return
lib/**/*.rb
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# v0.7.0

- OpenAPI v3.1 (OpenAPI::V3_1)
- rename OpenAPI::V3 to OpenAPI::V3_0
- OpenAPI::Reference resolves $ref across documents
- Scorpio::Google::RestDescription is an API description document on its own; rm conversion to OpenAPI
- JSI ~> v0.9

# v0.6.4

- JSI ~> v0.8.1
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ Note: The canonical location of this README is on [RubyDoc](https://rubydoc.info

### OpenAPI specification and OpenAPI documents

To start with, you need an OpenAPI document (an OAD) describing a service you will be consuming. OpenAPI Specification v3.0 and v2 (formerly known as Swagger) are supported. An OAD can be written by hand or sometimes generated from other existing sources. The creation of an OpenAPI document describing a given service is outside the scope of Scorpio. Here are several resources on OpenAPI:
To start with, you need an OpenAPI document (an OAD) describing a service you will be consuming. OpenAPI Specification v3.1, v3.0, and v2 (formerly known as Swagger) are supported. An OAD can be written by hand or sometimes generated from other existing sources. The creation of an OpenAPI document describing a given service is outside the scope of Scorpio. Here are several resources on OpenAPI:

- [Learn about OpenAPI](https://learn.openapis.org/)
- [OpenAPI Specification at Wikipedia](https://en.wikipedia.org/wiki/OpenAPI_Specification)
- OpenAPI [Specification v2.0](https://spec.openapis.org/oas/v2.0.html) and [Specification v3.0](https://spec.openapis.org/oas/v3.0.html)
- OpenAPI Specifications [v3.1](https://spec.openapis.org/oas/v3.1.html), [v3.0](https://spec.openapis.org/oas/v3.0.html), [v2.0](https://spec.openapis.org/oas/v2.0.html)
- [OpenAPI Specification development on GitHub](https://github.com/OAI/OpenAPI-Specification)

### JSON Schema, JSI
Expand Down Expand Up @@ -128,7 +128,7 @@ You do not have to define resource classes as above to use Scorpio to interact w

This representation uses [JSI](https://github.com/notEthan/jsi) with the JSON schema describing OpenAPI documents (for the relevant version of the OpenAPI specification). Scorpio's API client functionality is implemented using these schemas, and the result is that the instantiated OpenAPI document is itself the client to the service it describes.

To consume the Pet Store service, we start by instantiating the OpenAPI document. {Scorpio::OpenAPI::Document.from_instance} returns a JSI instance described by the appropriate V2 or V3 OpenAPI document schema.
To consume the Pet Store service, we start by instantiating the OpenAPI document. {Scorpio::OpenAPI::Document.from_instance} returns a JSI instance described by the appropriate OpenAPI document schema.

```ruby
require 'scorpio'
Expand Down Expand Up @@ -220,7 +220,7 @@ pet_store_oad.operations['getPetById'].run(petId: 0)

For another example of an API that a client interacts with using Scorpio::ResourceBase, Scorpio's tests implement the Blog service. This is defined in test/blog.rb. The service uses ActiveRecord models and Sinatra to make a simple RESTful service.

Its API is described in `test/blog.openapi.yml`, defining the Article resource, several operations, and schemas. The client is set up in `test/blog_scorpio_models.rb`. The base class BlogModel defines the base_url and the api description, as well as some other optional setup done for testing. Its operations are tested in `test/scorpio_test.rb`.
Its API is described in `test/blog.openapi<version>.yml`, defining the Article resource, several operations, and schemas. The client is set up in `test/blog_scorpio_models.rb`. The base class BlogModel defines the base_url and the api description, as well as some other optional setup done for testing. Its operations are tested in `test/scorpio_test.rb`.

## Scorpio::ResourceBase

Expand Down Expand Up @@ -249,7 +249,7 @@ If you need a more complete representation of the HTTP request and/or response,
```ruby
inventory_op = Scorpio::OpenAPI::Document.from_instance(JSON.parse(Faraday.get('https://petstore.swagger.io/v2/swagger.json').body, freeze: true)).paths['/store/inventory']['get']
inventory_ur = inventory_op.run_ur
# => #{<Scorpio::Ur fragment="#"> ...}
# => #{<JSI (Ur + Scorpio::Ur)> "bound" => "outbound", "request" => ...}
```

### Scorpio ResourceBase pickle adapter
Expand Down
10 changes: 4 additions & 6 deletions lib/scorpio.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def self.root
module Scorpio
# generally put in code paths that are not expected to be valid control flow paths.
# rather a NotImplementedCorrectlyError. but that's too long.
# @private
class Bug < NotImplementedError
end

Expand All @@ -31,12 +32,9 @@ class HTTPError < Error
# @param status [Integer] if specified, sets the HTTP status the class represents
# @return [Integer] the HTTP status the class represents
def self.status(status = nil)
if status
@status = status
Scorpio.error_classes_by_status[status] = self
else
@status
end
return @status if !status
Scorpio.error_classes_by_status[status] = self
@status = status
end
attr_accessor :ur, :response_object
end
Expand Down
2 changes: 2 additions & 0 deletions lib/scorpio/google_api_document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ module Google
)

# naming these is not strictly necessary, but is nice to have.


DirectoryList = DISCOVERY_REST_DESCRIPTION.schemas['DirectoryList'].jsi_schema_module
JsonSchema = DISCOVERY_REST_DESCRIPTION.schemas['JsonSchema'].jsi_schema_module
RestDescription = DISCOVERY_REST_DESCRIPTION.schemas['RestDescription'].jsi_schema_module
Expand Down
2 changes: 1 addition & 1 deletion lib/scorpio/openapi/document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def v2?
end

def v3?
is_a?(OpenAPI::V3_0::Document)
is_a?(OpenAPI::Document::V3Methods)
end

def operations
Expand Down
7 changes: 3 additions & 4 deletions lib/scorpio/openapi/operation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def logger
# openapi v3?
# @return [Boolean]
def v3?
is_a?(OpenAPI::V3_0::Operation)
is_a?(OpenAPI::Operation::V3Methods)
end

# openapi v2?
Expand Down Expand Up @@ -193,9 +193,8 @@ def run(mutable: false, **configuration, &b)
end

# Runs this operation with the given request config, and yields the resulting {Scorpio::Ur}.
# If the response contains a `Link` header with a `next` link (and that link's URL
# corresponds to this operation), this operation is run again to that link's URL, that
# request's Ur yielded, and a `next` link in that response is followed.
# If the response contains a `Link` header with a `next` link, this operation is run again to
# that link's URL, that request's Ur yielded, and a `next` link in that response is followed.
# This repeats until a response does not contain a `Link` header with a `next` link.
#
# @param configuration (see Scorpio::Request#initialize)
Expand Down
17 changes: 10 additions & 7 deletions lib/scorpio/openapi/operations_scope.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@ class OperationsScope
def initialize(enum)
@enum = enum
@operations_by_id = Hash.new do |h, operationId|
op = enum.detect { |operation| operation.operationId == operationId }
unless op
raise(::KeyError, -"operationId not found: #{operationId.inspect}")
end
h[operationId] = op
h[operationId] = enum.detect { |operation| operation.operationId == operationId }
end
end
attr_reader :openapi_document
Expand All @@ -25,14 +21,21 @@ def each(&block)

include Enumerable

# @return [Scorpio::OpenAPI::Operation, nil]
def by_id(operationId)
@operations_by_id[operationId]
end

# finds an operation with the given `operationId`
# @param operationId [String] the operationId of the operation to find
# @return [Scorpio::OpenAPI::Operation]
# @raise [::KeyError] if the given operationId does not exist
def [](operationId)
@operations_by_id[operationId]
def by_id!(operationId)
@operations_by_id[operationId] || raise(::KeyError, -"operationId not found: #{operationId.inspect}")
end

alias_method(:[], :by_id!)

# @return [OperationsScope]
def select(&block)
OperationsScope.new(@enum.select(&block))
Expand Down
4 changes: 1 addition & 3 deletions lib/scorpio/openapi/v3_0.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,7 @@ module V3_0
SecurityRequirement = Document.definitions['SecurityRequirement']
Tag = Document.definitions['Tag']
ExternalDocumentation = Document.definitions['ExternalDocumentation']
ExampleXORExamples = Document.definitions['ExampleXORExamples']
SchemaXORContent = Document.definitions['SchemaXORContent']
Parameter = Document.definitions['Parameter']
Parameter = Document.definitions['Parameter']
PathParameter = Document.definitions['PathParameter']
QueryParameter = Document.definitions['QueryParameter']
HeaderParameter = Document.definitions['HeaderParameter']
Expand Down
2 changes: 1 addition & 1 deletion lib/scorpio/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ def get_param_from(param_in, name)
elsif param_in == 'query'
query_params ? query_params[name] : nil
elsif param_in == 'header'
_, value = headers.detect { |headername, _| headername.downcase == name.downcase }
_, value = headers.detect { |headername, _| headername.casecmp?(name) }
value
elsif param_in == 'cookie'
raise(NotImplementedError, -"cookies not implemented: #{name.inspect}")
Expand Down
2 changes: 1 addition & 1 deletion lib/scorpio/response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
module Scorpio
Response = Scorpio::Ur.properties['response']

# Scorpio::Response is a JSI schema module describing the same instances as ::Ur::Response.
# Scorpio::Response is a JSI schema module describing the same instances as [::Ur::Response](https://rubydoc.info/gems/ur/Ur/Response).
# It relies on methods of that module.
module Response
# the schema for this response according to its OpenAPI doc
Expand Down
2 changes: 1 addition & 1 deletion lib/scorpio/ur.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ module Ur
# raises a generic HTTPError otherwise.
#
# @raise [Scorpio::HTTPError]
# @return [void]
# @return [nil]
def raise_on_http_error
error_class = Scorpio.error_classes_by_status[response.status]
error_class ||= if (400..499).include?(response.status)
Expand Down
2 changes: 1 addition & 1 deletion lib/scorpio/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module Scorpio
VERSION = "0.6.4".freeze
VERSION = "0.7.0".freeze
end