apigen 0.0.6 → 0.0.7

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.
@@ -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.6
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: