swagger-to-rbs 0.1.0 → 0.3.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/README.md +17 -7
- data/lib/swagger2_rbs/hash_helper.rb +24 -0
- data/lib/swagger2_rbs/rest_endpoint.rb +28 -56
- data/lib/swagger2_rbs/rest_endpoint_typed.rb +74 -0
- data/lib/swagger2_rbs.rb +21 -1
- data/lib/templates/http_client.rb.erb +4 -3
- data/lib/templates/http_client.rbs.erb +8 -7
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4609330c97363e8fc3f14d202f55904f026124a77a13c9e9bfcf8728a75aab42
|
4
|
+
data.tar.gz: 4ebb0337d6d72947aa3ce27ce4e2d8a99cbc63eb7f33a8015a3dccacb668696a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7899e345942d1014a68dccf6a866295a2afafefabc80d4a2abc439a15ab4f6bb35d7ab708f3ef4eb7b548602902b66c850d015fae56b3b4efdc7ab3c4dca5781
|
7
|
+
data.tar.gz: 58a8e1db7ae6b58d0e3e0611c4e4b6346e3871ee5556f3f01018d812eb2027703d2bfa3733f63c346304cfbd322b68ec316c8ecb031dfdb356be8a3075a9157a
|
data/README.md
CHANGED
@@ -1,4 +1,10 @@
|
|
1
|
-
|
1
|
+
## Install
|
2
|
+
|
3
|
+
```
|
4
|
+
gem install swagger-to-rbs
|
5
|
+
```
|
6
|
+
|
7
|
+
## Usage
|
2
8
|
|
3
9
|
Dowload swagger spec
|
4
10
|
|
@@ -11,7 +17,7 @@ curl https://petstore3.swagger.io/api/v3/openapi.json > swagger.json
|
|
11
17
|
Generate http client based on [Httparty gem](https://github.com/jnunemaker/httparty)
|
12
18
|
|
13
19
|
```
|
14
|
-
|
20
|
+
swagger-to-rbs generate --name PetApi --spec swagger.json
|
15
21
|
```
|
16
22
|
|
17
23
|
Result:
|
@@ -24,16 +30,20 @@ class PetApi
|
|
24
30
|
base_uri "/api/v3"
|
25
31
|
#...
|
26
32
|
|
27
|
-
def
|
28
|
-
self.class.
|
33
|
+
def initialize
|
34
|
+
self.class.headers({ 'Content-Type' => 'application/json' })
|
35
|
+
end
|
36
|
+
|
37
|
+
def getPetById(petId, options = {})
|
38
|
+
self.class.get("/pet/#{petId}", options)
|
29
39
|
end
|
30
40
|
|
31
41
|
def updatePet(body, options = {})
|
32
|
-
self.class.put("/pet", body: body.to_json
|
42
|
+
self.class.put("/pet", { body: body.to_json }.merge(options))
|
33
43
|
end
|
34
44
|
|
35
45
|
def addPet(body, options = {})
|
36
|
-
self.class.post("/pet", body: body.to_json
|
46
|
+
self.class.post("/pet", { body: body.to_json }.merge(options))
|
37
47
|
end
|
38
48
|
#...
|
39
49
|
end
|
@@ -44,7 +54,7 @@ end
|
|
44
54
|
Authorization example:
|
45
55
|
|
46
56
|
```
|
47
|
-
api =
|
57
|
+
api = PetApi.new
|
48
58
|
|
49
59
|
MyApi.headers(Authorization: "Bearer #{access_token}")
|
50
60
|
MyApi.base_uri("http://otherurl.test/api/v1)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Swagger2Rbs
|
2
|
+
class HashHelper
|
3
|
+
def self.set_value(hash, key, value)
|
4
|
+
arr = key.split(".")
|
5
|
+
last_key = arr.pop()
|
6
|
+
hash.dig(*arr)[last_key] = value
|
7
|
+
hash
|
8
|
+
rescue => e
|
9
|
+
hash
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.walk(hash, &block)
|
13
|
+
hash.each do |k, v|
|
14
|
+
if v.is_a?(Hash)
|
15
|
+
walk(v) do |k2, v2|
|
16
|
+
yield "#{k}.#{k2}", v2
|
17
|
+
end
|
18
|
+
else
|
19
|
+
yield k, v
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
require 'slugify'
|
2
|
+
require_relative 'rest_endpoint_typed'
|
2
3
|
|
3
4
|
module Swagger2Rbs
|
4
5
|
class RestEndpoint
|
5
6
|
attr_reader :path, :method, :props
|
7
|
+
include RestEndpointTyped
|
6
8
|
|
7
9
|
def initialize(path, method, props)
|
8
10
|
@path = path
|
@@ -13,15 +15,31 @@ module Swagger2Rbs
|
|
13
15
|
def to_h
|
14
16
|
{
|
15
17
|
path: path_with_parameters,
|
18
|
+
http_method: method,
|
19
|
+
parameters_for_method: parameters_for_method,
|
20
|
+
typed_parameters_for_method: typed_parameters_for_method,
|
21
|
+
has_body: body?,
|
22
|
+
method_name: method_name,
|
23
|
+
response_typed: response_typed,
|
24
|
+
}
|
25
|
+
rescue => e
|
26
|
+
raise e, "Context: #{path} #{method} Message: #{e.message}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def body?
|
30
|
+
body && !body.empty?
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_yaml
|
34
|
+
{
|
35
|
+
path: path,
|
16
36
|
method: method,
|
17
37
|
parameters: parameters,
|
18
|
-
parameters_for_method: parameters_for_method,
|
19
|
-
parameters_typed: parameters_typed,
|
20
38
|
method_name: method_name,
|
21
39
|
body: body,
|
22
|
-
body_typed: body_typed,
|
23
|
-
response_typed: response_typed,
|
24
40
|
}
|
41
|
+
rescue => e
|
42
|
+
raise e, "Context: #{path} #{method} Message: #{e.message}"
|
25
43
|
end
|
26
44
|
|
27
45
|
def method_name
|
@@ -35,39 +53,7 @@ module Swagger2Rbs
|
|
35
53
|
def parameters
|
36
54
|
return [] unless props["parameters"]
|
37
55
|
|
38
|
-
props["parameters"]
|
39
|
-
end
|
40
|
-
|
41
|
-
def response_typed
|
42
|
-
schema = resolve_all_of(@props.dig("responses", "200", "content", "application/json", "schema"))
|
43
|
-
schema_to_typed(schema, {})
|
44
|
-
end
|
45
|
-
|
46
|
-
def parameters_typed
|
47
|
-
return nil if method != "get"
|
48
|
-
parameters.map{|it| "String #{it}" }
|
49
|
-
.push("?Hash[untyped, untyped] options")
|
50
|
-
.join(", ")
|
51
|
-
end
|
52
|
-
|
53
|
-
def body_typed
|
54
|
-
return nil if method != "post"
|
55
|
-
|
56
|
-
return "Hash[String, untyped]" unless body
|
57
|
-
return "Hash[String, untyped]" if body.empty?
|
58
|
-
|
59
|
-
"{" + body.map{ |k, v| to_typed(k, v) }.join(", ") + "}" + " body, ?Hash[untyped, untyped] options"
|
60
|
-
end
|
61
|
-
|
62
|
-
def to_typed(k, v)
|
63
|
-
return "#{k}: #{v&.capitalize}" unless v.is_a?(Array) || v.is_a?(Hash)
|
64
|
-
return "#{k}: {#{v.map{ |k2, v2| to_typed(k2, v2) }.join(", ")}}" if v.is_a?(Hash)
|
65
|
-
|
66
|
-
if v[0]&.is_a?(Hash)
|
67
|
-
"#{k}: Array[{" + v[0].map{ |k, v| "#{k}: #{v&.capitalize}" }.join(", ") + "}]"
|
68
|
-
else
|
69
|
-
"#{k}: Array[#{v[0]&.capitalize}]"
|
70
|
-
end
|
56
|
+
props["parameters"]&.select{|it| it["in"] == "path"}&.map{|it| it["name"]}
|
71
57
|
end
|
72
58
|
|
73
59
|
def body
|
@@ -78,26 +64,12 @@ module Swagger2Rbs
|
|
78
64
|
end
|
79
65
|
|
80
66
|
def parameters_for_method
|
81
|
-
return parameters.push("options = {}").join(", ") if
|
67
|
+
return parameters.push("options = {}").join(", ") if method == "get"
|
82
68
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
return nil unless schema
|
88
|
-
|
89
|
-
schema["properties"]&.reduce(memo)do |memo, (k,v)|
|
90
|
-
if v["type"] == "object"
|
91
|
-
memo.merge({k => schema_to_typed(v, {})})
|
92
|
-
elsif v["type"] == "array"
|
93
|
-
if v.dig("items", "type") == "object"
|
94
|
-
memo.merge({k => [schema_to_typed(v["items"], {})] })
|
95
|
-
else
|
96
|
-
memo.merge({k => [v.dig("items", "type")] })
|
97
|
-
end
|
98
|
-
else
|
99
|
-
memo.merge({k => v["type"] })
|
100
|
-
end
|
69
|
+
if body&.empty?
|
70
|
+
parameters.push("options = {}").join(", ")
|
71
|
+
else
|
72
|
+
parameters.push("body").push("options = {}").join(", ")
|
101
73
|
end
|
102
74
|
end
|
103
75
|
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Swagger2Rbs
|
2
|
+
|
3
|
+
module RestEndpointTyped
|
4
|
+
def response_typed
|
5
|
+
schema = resolve_all_of(@props.dig("responses", "200", "content", "application/json", "schema"))
|
6
|
+
schema_to_typed(schema, {})
|
7
|
+
end
|
8
|
+
|
9
|
+
def typed_parameters_for_method
|
10
|
+
options_typed = "?Hash[untyped, untyped] options"
|
11
|
+
return "(#{options_typed})" unless body && parameters
|
12
|
+
return "(#{options_typed})" if body.empty? && parameters.empty?
|
13
|
+
|
14
|
+
typed_parameters = parameters&.map{|it| "String #{it}" } || []
|
15
|
+
|
16
|
+
typed_parameters.push("#{body_typed} body") if body?
|
17
|
+
|
18
|
+
"(#{typed_parameters.push(options_typed).join(', ')})"
|
19
|
+
end
|
20
|
+
|
21
|
+
def body_typed
|
22
|
+
return nil unless body?
|
23
|
+
typed = (body.is_a?(Array) ? body[0] : body)&.map{ |k, v| to_typed(k, v) }.join(', ')
|
24
|
+
if body.is_a?(Array)
|
25
|
+
"Array[{ #{typed} }]"
|
26
|
+
else
|
27
|
+
"{ #{typed} }"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def type_case(str)
|
32
|
+
case str
|
33
|
+
when "boolean"
|
34
|
+
"bool"
|
35
|
+
else
|
36
|
+
str&.capitalize
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_typed(k, v)
|
41
|
+
return "#{k}: #{type_case(v)}" unless v.is_a?(Array) || v.is_a?(Hash)
|
42
|
+
return "#{k}: {#{v.map{ |k2, v2| to_typed(k2, v2) }.join(", ")}}" if v.is_a?(Hash)
|
43
|
+
|
44
|
+
if v[0]&.is_a?(Hash)
|
45
|
+
"#{k}: Array[{" + v[0].map{ |k, v| to_typed(k, v) }.join(", ") + "}]"
|
46
|
+
else
|
47
|
+
"#{k}: Array[#{type_case(v[0])}]"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def schema_to_typed(schema, memo = {})
|
52
|
+
return nil unless schema
|
53
|
+
|
54
|
+
properties = schema["type"]["array"] ? schema["items"]["properties"] : schema["properties"]
|
55
|
+
|
56
|
+
result = properties&.reduce(memo)do |memo, (k,v)|
|
57
|
+
if v["type"] == "object"
|
58
|
+
memo.merge({k => schema_to_typed(v, {})})
|
59
|
+
elsif v["type"] == "array"
|
60
|
+
if v.dig("items", "type") == "object"
|
61
|
+
memo.merge({k => [schema_to_typed(v["items"], {})] })
|
62
|
+
else
|
63
|
+
memo.merge({k => [v.dig("items", "type")] })
|
64
|
+
end
|
65
|
+
else
|
66
|
+
memo.merge({k => v["type"] })
|
67
|
+
end
|
68
|
+
end
|
69
|
+
return [result] if schema["type"]["array"]
|
70
|
+
|
71
|
+
result
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/swagger2_rbs.rb
CHANGED
@@ -1,12 +1,32 @@
|
|
1
1
|
require 'json'
|
2
2
|
require 'erb'
|
3
3
|
require_relative 'swagger2_rbs/rest_endpoint'
|
4
|
+
require_relative 'swagger2_rbs/hash_helper'
|
4
5
|
|
5
6
|
module Swagger2Rbs
|
6
7
|
|
8
|
+
def self.resolve_ref(hash, key, value)
|
9
|
+
ref_key = value.gsub("#/", "").split("/")
|
10
|
+
data = hash.dig(*ref_key)
|
11
|
+
update_key = key.split(".").reject{|k| k == "$ref"}.join(".")
|
12
|
+
|
13
|
+
[update_key, data]
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.resolve_all_ref(swagger_spec)
|
17
|
+
new_swagger_spec = swagger_spec.dup
|
18
|
+
HashHelper.walk(swagger_spec) do |key, value|
|
19
|
+
if key.split(".").last == "$ref"
|
20
|
+
update_key, data = resolve_ref(swagger_spec, key, value)
|
21
|
+
HashHelper.set_value(new_swagger_spec, update_key, data)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
new_swagger_spec
|
25
|
+
end
|
26
|
+
|
7
27
|
def self.swagger_to_rest_api(swagger_spec)
|
8
28
|
result = []
|
9
|
-
swagger_spec["paths"].each do |path, data|
|
29
|
+
resolve_all_ref(swagger_spec)["paths"].each do |path, data|
|
10
30
|
data.each do |method, props|
|
11
31
|
rest_data = RestEndpoint.new(path, method, props)
|
12
32
|
result << rest_data.to_h
|
@@ -1,5 +1,6 @@
|
|
1
1
|
|
2
2
|
require 'httparty'
|
3
|
+
require 'json'
|
3
4
|
|
4
5
|
class <%= @module_name %>
|
5
6
|
include HTTParty
|
@@ -11,13 +12,13 @@ class <%= @module_name %>
|
|
11
12
|
end
|
12
13
|
<%- @data[:endpoints].each do |endpoint| -%>
|
13
14
|
|
14
|
-
<%-
|
15
|
+
<%- unless endpoint[:has_body] -%>
|
15
16
|
def <%= endpoint[:method_name] %>(<%= endpoint[:parameters_for_method] %>)
|
16
|
-
self.class.<%= endpoint[:
|
17
|
+
self.class.<%= endpoint[:http_method] %>("<%= endpoint[:path] %>", options)
|
17
18
|
end
|
18
19
|
<%- else -%>
|
19
20
|
def <%= endpoint[:method_name] %>(<%= endpoint[:parameters_for_method] %>)
|
20
|
-
self.class.<%= endpoint[:
|
21
|
+
self.class.<%= endpoint[:http_method] %>("<%= endpoint[:path] %>", { body: body.to_json }.merge(options))
|
21
22
|
end
|
22
23
|
<%- end -%>
|
23
24
|
<%- end -%>
|
@@ -1,17 +1,18 @@
|
|
1
|
-
|
2
1
|
# Classes
|
3
2
|
|
3
|
+
module HTTParty
|
4
|
+
class Response
|
5
|
+
def body: -> untyped
|
6
|
+
def success?: -> bool
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
4
10
|
class <%= @module_name %>
|
5
11
|
include HTTParty
|
6
|
-
attr_accessor default_headers: bot
|
7
12
|
|
8
13
|
def initialize: -> void
|
9
14
|
<%- @data[:endpoints].each do |endpoint| -%>
|
10
15
|
|
11
|
-
|
12
|
-
def <%= endpoint[:method_name] %>(<%= endpoint[:parameters_typed] %>) -> HTTParty::Response
|
13
|
-
<%- else -%>
|
14
|
-
def <%= endpoint[:method_name] %>(<%= endpoint[:body_typed] %>) -> HTTParty::Response
|
15
|
-
<%- end -%>
|
16
|
+
def <%= endpoint[:method_name] %>: <%= endpoint[:typed_parameters_for_method] %> -> HTTParty::Response
|
16
17
|
<%- end -%>
|
17
18
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: swagger-to-rbs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miguel Savignano
|
@@ -14,14 +14,14 @@ dependencies:
|
|
14
14
|
name: thor
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '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
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
@@ -50,7 +50,9 @@ files:
|
|
50
50
|
- lib/index.rb
|
51
51
|
- lib/swagger2_rbs.rb
|
52
52
|
- lib/swagger2_rbs/cli.rb
|
53
|
+
- lib/swagger2_rbs/hash_helper.rb
|
53
54
|
- lib/swagger2_rbs/rest_endpoint.rb
|
55
|
+
- lib/swagger2_rbs/rest_endpoint_typed.rb
|
54
56
|
- lib/templates/http_client.rb.erb
|
55
57
|
- lib/templates/http_client.rbs.erb
|
56
58
|
homepage: https://github.com/MiguelSavignano/swagger-to-rbs
|