Skip to content

Commit 1bb451d

Browse files
committed
Finish building openapi.json paths and parameters
1 parent f68d4bd commit 1bb451d

5 files changed

Lines changed: 1219 additions & 1 deletion

File tree

lib/manageiq/api/open_api/generator.rb

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ module Api
33
module OpenApi
44
class Generator
55
require 'json'
6+
require_relative 'parameter_builder'
7+
require_relative 'schema_builder'
8+
require_relative 'operation_builder'
9+
require_relative 'path_builder'
610

711
OPENAPI_VERSION = "3.0.0".freeze
812
PARAMETERS_PATH = "/components/parameters".freeze
@@ -19,7 +23,13 @@ def initialize
1923
end
2024

2125
def generate!
22-
openapi_spec["components"]["schemas"] = build_schemas
26+
openapi_spec["components"]["parameters"] = ParameterBuilder.build_common_parameters
27+
openapi_spec["components"]["schemas"] = build_schemas.merge(SchemaBuilder.build_common_schemas)
28+
openapi_spec["components"]["securitySchemes"] = build_security_schemes
29+
openapi_spec["paths"] = PathBuilder.build_paths(::Api::ApiConfig.collections)
30+
openapi_spec["security"] = build_security_requirements
31+
openapi_spec["servers"] = build_servers
32+
2333
openapi_path.write("#{JSON.pretty_generate(openapi_spec)}\n")
2434
end
2535

@@ -102,6 +112,50 @@ def build_schema_properties_value(model, key, value)
102112
properties_value
103113
end
104114

115+
def build_security_schemes
116+
{
117+
"basicAuth" => {
118+
"type" => "http",
119+
"scheme" => "basic",
120+
"description" => "HTTP Basic Authentication"
121+
},
122+
"bearerAuth" => {
123+
"type" => "http",
124+
"scheme" => "bearer",
125+
"description" => "Bearer token authentication"
126+
},
127+
"tokenAuth" => {
128+
"type" => "apiKey",
129+
"in" => "header",
130+
"name" => "X-Auth-Token",
131+
"description" => "Token-based authentication"
132+
}
133+
}
134+
end
135+
136+
def build_security_requirements
137+
[
138+
{"basicAuth" => []},
139+
{"bearerAuth" => []},
140+
{"tokenAuth" => []}
141+
]
142+
end
143+
144+
def build_servers
145+
[
146+
{
147+
"url" => "https://{hostname}",
148+
"description" => "ManageIQ API Server",
149+
"variables" => {
150+
"hostname" => {
151+
"default" => "localhost",
152+
"description" => "ManageIQ server hostname"
153+
}
154+
}
155+
}
156+
]
157+
end
158+
105159
def skeletal_openapi_spec
106160
{
107161
"openapi" => OPENAPI_VERSION,
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
module ManageIQ
2+
module Api
3+
module OpenApi
4+
module OperationBuilder
5+
SCHEMAS_PATH = "/components/schemas".freeze
6+
PARAMETERS_PATH = "/components/parameters".freeze
7+
8+
def self.build_collection_index_operation(collection_name, collection, model_schema_name)
9+
{
10+
"summary" => "List #{collection[:description] || collection_name}",
11+
"description" => "Returns a paginated list of #{collection[:description] || collection_name}",
12+
"operationId" => "list_#{collection_name}",
13+
"tags" => [collection[:description] || collection_name.to_s.titleize],
14+
"parameters" => ParameterBuilder.collection_query_parameters,
15+
"responses" => {
16+
"200" => {
17+
"description" => "Success",
18+
"content" => {
19+
"application/json" => {
20+
"schema" => SchemaBuilder.build_collection_response_schema(collection_name.to_s, model_schema_name)
21+
}
22+
}
23+
}
24+
}.merge(error_responses)
25+
}
26+
end
27+
28+
def self.build_resource_show_operation(collection_name, collection, model_schema_name)
29+
{
30+
"summary" => "Get a #{collection[:description]&.singularize || collection_name.to_s.singularize}",
31+
"description" => "Returns a single #{collection[:description]&.singularize || collection_name.to_s.singularize} by ID",
32+
"operationId" => "get_#{collection_name.to_s.singularize}",
33+
"tags" => [collection[:description] || collection_name.to_s.titleize],
34+
"parameters" => [
35+
{"$ref" => "#{PARAMETERS_PATH}/resourceId"}
36+
] + ParameterBuilder.resource_query_parameters,
37+
"responses" => {
38+
"200" => {
39+
"description" => "Success",
40+
"content" => {
41+
"application/json" => {
42+
"schema" => SchemaBuilder.build_resource_response_schema(model_schema_name)
43+
}
44+
}
45+
},
46+
"404" => SchemaBuilder.build_standard_responses["404"]
47+
}.merge(error_responses)
48+
}
49+
end
50+
51+
def self.build_create_operation(collection_name, collection, model_schema_name)
52+
{
53+
"summary" => "Create a #{collection[:description]&.singularize || collection_name.to_s.singularize}",
54+
"description" => "Creates a new #{collection[:description]&.singularize || collection_name.to_s.singularize}",
55+
"operationId" => "create_#{collection_name.to_s.singularize}",
56+
"tags" => [collection[:description] || collection_name.to_s.titleize],
57+
"requestBody" => {
58+
"required" => true,
59+
"content" => {
60+
"application/json" => {
61+
"schema" => {
62+
"$ref" => "#{SCHEMAS_PATH}/#{model_schema_name}"
63+
}
64+
}
65+
}
66+
},
67+
"responses" => {
68+
"201" => {
69+
"description" => "Created",
70+
"content" => {
71+
"application/json" => {
72+
"schema" => SchemaBuilder.build_resource_response_schema(model_schema_name)
73+
}
74+
}
75+
},
76+
"400" => SchemaBuilder.build_standard_responses["400"],
77+
"422" => SchemaBuilder.build_standard_responses["422"]
78+
}.merge(error_responses)
79+
}
80+
end
81+
82+
def self.build_update_operation(collection_name, collection, model_schema_name)
83+
{
84+
"summary" => "Update a #{collection[:description]&.singularize || collection_name.to_s.singularize}",
85+
"description" => "Updates an existing #{collection[:description]&.singularize || collection_name.to_s.singularize}",
86+
"operationId" => "update_#{collection_name.to_s.singularize}",
87+
"tags" => [collection[:description] || collection_name.to_s.titleize],
88+
"parameters" => [
89+
{"$ref" => "#{PARAMETERS_PATH}/resourceId"}
90+
],
91+
"requestBody" => {
92+
"required" => true,
93+
"content" => {
94+
"application/json" => {
95+
"schema" => {
96+
"$ref" => "#{SCHEMAS_PATH}/#{model_schema_name}"
97+
}
98+
}
99+
}
100+
},
101+
"responses" => {
102+
"200" => {
103+
"description" => "Success",
104+
"content" => {
105+
"application/json" => {
106+
"schema" => SchemaBuilder.build_resource_response_schema(model_schema_name)
107+
}
108+
}
109+
},
110+
"404" => SchemaBuilder.build_standard_responses["404"],
111+
"422" => SchemaBuilder.build_standard_responses["422"]
112+
}.merge(error_responses)
113+
}
114+
end
115+
116+
def self.build_delete_operation(collection_name, collection)
117+
{
118+
"summary" => "Delete a #{collection[:description]&.singularize || collection_name.to_s.singularize}",
119+
"description" => "Deletes an existing #{collection[:description]&.singularize || collection_name.to_s.singularize}",
120+
"operationId" => "delete_#{collection_name.to_s.singularize}",
121+
"tags" => [collection[:description] || collection_name.to_s.titleize],
122+
"parameters" => [
123+
{"$ref" => "#{PARAMETERS_PATH}/resourceId"}
124+
],
125+
"responses" => {
126+
"204" => SchemaBuilder.build_standard_responses["204"],
127+
"404" => SchemaBuilder.build_standard_responses["404"]
128+
}.merge(error_responses)
129+
}
130+
end
131+
132+
def self.build_bulk_action_operation(collection_name, collection, model_schema_name)
133+
{
134+
"summary" => "Perform bulk actions on #{collection[:description] || collection_name}",
135+
"description" => "Executes actions on multiple #{collection[:description] || collection_name} or performs queries",
136+
"operationId" => "bulk_action_#{collection_name}",
137+
"tags" => [collection[:description] || collection_name.to_s.titleize],
138+
"requestBody" => {
139+
"required" => true,
140+
"content" => {
141+
"application/json" => {
142+
"schema" => {
143+
"oneOf" => [
144+
{
145+
"type" => "object",
146+
"properties" => {
147+
"action" => {
148+
"type" => "string",
149+
"description" => "Action to perform"
150+
},
151+
"resources" => {
152+
"type" => "array",
153+
"description" => "Resources to perform action on",
154+
"items" => {
155+
"type" => "object",
156+
"properties" => {
157+
"href" => {
158+
"type" => "string",
159+
"format" => "uri"
160+
}
161+
}
162+
}
163+
}
164+
},
165+
"required" => ["action"]
166+
},
167+
{
168+
"$ref" => "#{SCHEMAS_PATH}/#{model_schema_name}"
169+
}
170+
]
171+
}
172+
}
173+
}
174+
},
175+
"responses" => {
176+
"200" => {
177+
"description" => "Success",
178+
"content" => {
179+
"application/json" => {
180+
"schema" => {
181+
"type" => "object",
182+
"properties" => {
183+
"results" => {
184+
"type" => "array",
185+
"items" => {
186+
"$ref" => "#{SCHEMAS_PATH}/#{model_schema_name}"
187+
}
188+
}
189+
}
190+
}
191+
}
192+
}
193+
},
194+
"400" => SchemaBuilder.build_standard_responses["400"],
195+
"422" => SchemaBuilder.build_standard_responses["422"]
196+
}.merge(error_responses)
197+
}
198+
end
199+
200+
def self.build_resource_action_operation(collection_name, collection, model_schema_name)
201+
{
202+
"summary" => "Perform action on a #{collection[:description]&.singularize || collection_name.to_s.singularize}",
203+
"description" => "Executes a custom action on a specific #{collection[:description]&.singularize || collection_name.to_s.singularize}",
204+
"operationId" => "action_#{collection_name.to_s.singularize}",
205+
"tags" => [collection[:description] || collection_name.to_s.titleize],
206+
"parameters" => [
207+
{"$ref" => "#{PARAMETERS_PATH}/resourceId"}
208+
],
209+
"requestBody" => {
210+
"required" => true,
211+
"content" => {
212+
"application/json" => {
213+
"schema" => {
214+
"oneOf" => [
215+
{
216+
"type" => "object",
217+
"properties" => {
218+
"action" => {
219+
"type" => "string",
220+
"description" => "Action to perform"
221+
}
222+
},
223+
"required" => ["action"]
224+
},
225+
{
226+
"$ref" => "#{SCHEMAS_PATH}/#{model_schema_name}"
227+
}
228+
]
229+
}
230+
}
231+
}
232+
},
233+
"responses" => {
234+
"200" => {
235+
"description" => "Success",
236+
"content" => {
237+
"application/json" => {
238+
"schema" => SchemaBuilder.build_resource_response_schema(model_schema_name)
239+
}
240+
}
241+
},
242+
"404" => SchemaBuilder.build_standard_responses["404"],
243+
"422" => SchemaBuilder.build_standard_responses["422"]
244+
}.merge(error_responses)
245+
}
246+
end
247+
248+
def self.error_responses
249+
{
250+
"401" => SchemaBuilder.build_standard_responses["401"],
251+
"403" => SchemaBuilder.build_standard_responses["403"]
252+
}
253+
end
254+
end
255+
end
256+
end
257+
end

0 commit comments

Comments
 (0)