apigen 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/apigen/formats/json_base.rb +109 -0
- data/lib/apigen/formats/jsonschema.rb +11 -59
- data/lib/apigen/formats/openapi.rb +10 -64
- data/lib/apigen/formats/swagger.rb +10 -60
- data/lib/apigen/migration.rb +55 -0
- data/lib/apigen/model.rb +1 -234
- data/lib/apigen/models/array_type.rb +34 -0
- data/lib/apigen/models/enum_type.rb +25 -0
- data/lib/apigen/models/model.rb +78 -0
- data/lib/apigen/models/object_property.rb +39 -0
- data/lib/apigen/models/object_type.rb +77 -0
- data/lib/apigen/models/oneof_type.rb +33 -0
- data/lib/apigen/models/primary_type.rb +33 -0
- data/lib/apigen/models/reference_type.rb +27 -0
- data/lib/apigen/models/registry.rb +39 -0
- data/lib/apigen/rest.rb +1 -269
- data/lib/apigen/rest/api.rb +73 -0
- data/lib/apigen/rest/endpoint.rb +160 -0
- data/lib/apigen/rest/input.rb +39 -0
- data/lib/apigen/rest/output.rb +45 -0
- metadata +16 -1
@@ -0,0 +1,160 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './input'
|
4
|
+
require_relative './output'
|
5
|
+
|
6
|
+
module Apigen
|
7
|
+
module Rest
|
8
|
+
##
|
9
|
+
# Endpoint is a definition of a specific endpoint in the API, e.g. /users with GET method.
|
10
|
+
class Endpoint
|
11
|
+
PATH_PARAMETER_REGEX = /\{(\w+)\}/
|
12
|
+
|
13
|
+
attribute_setter_getter :name
|
14
|
+
attribute_setter_getter :description
|
15
|
+
attr_reader :outputs
|
16
|
+
attr_reader :path_parameters
|
17
|
+
attr_reader :query_parameters
|
18
|
+
|
19
|
+
def initialize(name)
|
20
|
+
@name = name
|
21
|
+
@method = nil
|
22
|
+
@path = nil
|
23
|
+
@path_parameters = Apigen::ObjectType.new
|
24
|
+
@query_parameters = Apigen::ObjectType.new
|
25
|
+
@input = nil
|
26
|
+
@outputs = []
|
27
|
+
@description = nil
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# Declares the HTTP method.
|
32
|
+
def method(method = nil)
|
33
|
+
return @method unless method
|
34
|
+
case method
|
35
|
+
when :get, :post, :put, :delete
|
36
|
+
@method = method
|
37
|
+
else
|
38
|
+
raise "Unknown HTTP method :#{method}."
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Declares the endpoint path relative to the host.
|
44
|
+
def path(path = nil, &block)
|
45
|
+
return @path unless path
|
46
|
+
@path = path
|
47
|
+
if PATH_PARAMETER_REGEX.match path
|
48
|
+
set_path_parameters(path, &block)
|
49
|
+
elsif block_given?
|
50
|
+
raise 'A path block was provided but no URL parameter was found.'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Declares query parameters.
|
56
|
+
def query(&block)
|
57
|
+
raise 'You must pass a block when calling `query`.' unless block_given?
|
58
|
+
@query_parameters.instance_eval(&block)
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# Declares the input type of an endpoint.
|
63
|
+
def input(&block)
|
64
|
+
return @input unless block_given?
|
65
|
+
@input = Input.new
|
66
|
+
@input.instance_eval(&block)
|
67
|
+
end
|
68
|
+
|
69
|
+
##
|
70
|
+
# Declares the output of an endpoint for a given status code.
|
71
|
+
def output(name, &block)
|
72
|
+
raise "Endpoint :#{@name} declares the output :#{name} twice." if @outputs.find { |o| o.name == name }
|
73
|
+
output = Output.new name
|
74
|
+
@outputs << output
|
75
|
+
raise 'You must pass a block when calling `output`.' unless block_given?
|
76
|
+
output.instance_eval(&block)
|
77
|
+
output
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Updates an already-declared output.
|
82
|
+
def update_output(name, &block)
|
83
|
+
output = @outputs.find { |o| o.name == name }
|
84
|
+
raise "Endpoint :#{@name} never declares the output :#{name} so it cannot be updated." unless output
|
85
|
+
raise 'You must pass a block when calling `update_output`.' unless block_given?
|
86
|
+
output.instance_eval(&block)
|
87
|
+
output
|
88
|
+
end
|
89
|
+
|
90
|
+
def validate(model_registry)
|
91
|
+
validate_properties
|
92
|
+
validate_input(model_registry)
|
93
|
+
validate_path_parameters(model_registry)
|
94
|
+
validate_outputs(model_registry)
|
95
|
+
end
|
96
|
+
|
97
|
+
def to_s
|
98
|
+
repr = "#{@name}:"
|
99
|
+
input_str = @input.to_s
|
100
|
+
repr += " #{input_str}" unless input_str.empty?
|
101
|
+
@outputs.each do |output|
|
102
|
+
repr += "\n-> #{output}"
|
103
|
+
end
|
104
|
+
repr += "\n"
|
105
|
+
repr
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def set_path_parameters(path, &block)
|
111
|
+
block = {} unless block_given?
|
112
|
+
@path_parameters.instance_eval(&block)
|
113
|
+
parameters_found_in_path = path.scan(PATH_PARAMETER_REGEX).map { |parameter, _| parameter.to_sym }
|
114
|
+
ensure_parameters_found_in_path_all_defined(parameters_found_in_path)
|
115
|
+
ensure_defined_parameters_all_appear_in_path(parameters_found_in_path)
|
116
|
+
end
|
117
|
+
|
118
|
+
def ensure_parameters_found_in_path_all_defined(parameters_found_in_path)
|
119
|
+
parameters_found_in_path.each do |parameter|
|
120
|
+
raise "Path parameter :#{parameter} in path #{@path} is not defined." unless @path_parameters.properties.key? parameter
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def ensure_defined_parameters_all_appear_in_path(parameters_found_in_path)
|
125
|
+
@path_parameters.properties.each do |parameter, _type|
|
126
|
+
raise "Parameter :#{parameter} does not appear in path #{@path}." unless parameters_found_in_path.include? parameter
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def validate_properties
|
131
|
+
raise 'One of the endpoints is missing a name.' unless @name
|
132
|
+
raise "Use `method :get/post/put/delete` to set an HTTP method for :#{@name}." unless @method
|
133
|
+
raise "Use `path \"/some/path\"` to assign a path to :#{@name}." unless @path
|
134
|
+
end
|
135
|
+
|
136
|
+
def validate_input(model_registry)
|
137
|
+
case @method
|
138
|
+
when :put, :post
|
139
|
+
raise "Use `input { type :typename }` to assign an input type to :#{@name}." unless @input
|
140
|
+
@input.validate(model_registry)
|
141
|
+
when :get
|
142
|
+
raise "Endpoint :#{@name} with method GET cannot accept an input payload." if @input
|
143
|
+
when :delete
|
144
|
+
raise "Endpoint :#{@name} with method DELETE cannot accept an input payload." if @input
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def validate_path_parameters(model_registry)
|
149
|
+
@path_parameters.validate model_registry
|
150
|
+
end
|
151
|
+
|
152
|
+
def validate_outputs(model_registry)
|
153
|
+
raise "Endpoint :#{@name} does not declare any outputs" if @outputs.empty?
|
154
|
+
@outputs.each do |output|
|
155
|
+
output.validate model_registry
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Apigen
|
4
|
+
module Rest
|
5
|
+
##
|
6
|
+
# Input is the request body expected by an API endpoint.
|
7
|
+
class Input
|
8
|
+
attribute_setter_getter :description
|
9
|
+
attribute_setter_getter :example
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@type = nil
|
13
|
+
@description = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
##
|
17
|
+
# Declares the input type.
|
18
|
+
def type(type = nil, &block)
|
19
|
+
return @type unless type
|
20
|
+
@type = Apigen::Model.type type, &block
|
21
|
+
end
|
22
|
+
|
23
|
+
def validate(model_registry)
|
24
|
+
validate_properties
|
25
|
+
model_registry.check_type @type
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
@type.to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def validate_properties
|
35
|
+
raise 'Use `type :typename` to assign a type to the input.' unless @type
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Apigen
|
4
|
+
module Rest
|
5
|
+
##
|
6
|
+
# Output is the response type associated with a specific status code for an API endpoint.
|
7
|
+
class Output
|
8
|
+
attr_reader :name
|
9
|
+
attribute_setter_getter :status
|
10
|
+
attribute_setter_getter :description
|
11
|
+
attribute_setter_getter :example
|
12
|
+
|
13
|
+
def initialize(name)
|
14
|
+
@name = name
|
15
|
+
@status = nil
|
16
|
+
@type = nil
|
17
|
+
@description = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Declares the output type.
|
22
|
+
def type(type = nil, &block)
|
23
|
+
return @type unless type
|
24
|
+
@type = Apigen::Model.type type, &block
|
25
|
+
end
|
26
|
+
|
27
|
+
def validate(model_registry)
|
28
|
+
validate_properties
|
29
|
+
model_registry.check_type @type
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_s
|
33
|
+
"#{@name} #{@status} #{@type}"
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def validate_properties
|
39
|
+
raise 'One of the outputs is missing a name.' unless @name
|
40
|
+
raise "Use `status [code]` to assign a status code to :#{@name}." unless @status
|
41
|
+
raise "Use `type :typename` to assign a type to :#{@name}." unless @type
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apigen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Francois Wouts
|
@@ -16,11 +16,26 @@ executables: []
|
|
16
16
|
extensions: []
|
17
17
|
extra_rdoc_files: []
|
18
18
|
files:
|
19
|
+
- lib/apigen/formats/json_base.rb
|
19
20
|
- lib/apigen/formats/jsonschema.rb
|
20
21
|
- lib/apigen/formats/openapi.rb
|
21
22
|
- lib/apigen/formats/swagger.rb
|
23
|
+
- lib/apigen/migration.rb
|
22
24
|
- lib/apigen/model.rb
|
25
|
+
- lib/apigen/models/array_type.rb
|
26
|
+
- lib/apigen/models/enum_type.rb
|
27
|
+
- lib/apigen/models/model.rb
|
28
|
+
- lib/apigen/models/object_property.rb
|
29
|
+
- lib/apigen/models/object_type.rb
|
30
|
+
- lib/apigen/models/oneof_type.rb
|
31
|
+
- lib/apigen/models/primary_type.rb
|
32
|
+
- lib/apigen/models/reference_type.rb
|
33
|
+
- lib/apigen/models/registry.rb
|
23
34
|
- lib/apigen/rest.rb
|
35
|
+
- lib/apigen/rest/api.rb
|
36
|
+
- lib/apigen/rest/endpoint.rb
|
37
|
+
- lib/apigen/rest/input.rb
|
38
|
+
- lib/apigen/rest/output.rb
|
24
39
|
- lib/apigen/util.rb
|
25
40
|
homepage: https://rubygems.org/gems/apigen
|
26
41
|
licenses:
|