apigen 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: