fraiseql_server/routes/api/openapi.rs
1//! `OpenAPI` specification for FraiseQL REST APIs.
2//!
3//! Provides a static `OpenAPI` 3.0.0 specification documenting all API endpoints,
4//! request/response schemas, and authentication requirements.
5
6/// Get complete `OpenAPI` 3.0.0 specification as JSON string.
7#[must_use]
8pub fn get_openapi_spec() -> String {
9 serde_json::json!({
10 "openapi": "3.0.0",
11 "info": {
12 "title": "FraiseQL Agent APIs",
13 "description": "GraphQL query intelligence, federation discovery, and administration APIs for FraiseQL",
14 "version": "1.0.0",
15 "contact": {
16 "name": "FraiseQL Support",
17 "url": "https://github.com/fraiseql/fraiseql"
18 },
19 "license": {
20 "name": "MIT OR Apache-2.0"
21 }
22 },
23 "servers": [
24 {
25 "url": "http://localhost:8080",
26 "description": "Local development server"
27 },
28 {
29 "url": "https://api.fraiseql.example.com",
30 "description": "Production server"
31 }
32 ],
33 "paths": {
34 "/api/v1/query/explain": {
35 "post": {
36 "summary": "Analyze GraphQL query complexity",
37 "description": "Analyzes a GraphQL query for depth, field count, and estimated execution cost. Returns complexity metrics and optimization recommendations.",
38 "tags": ["Query Intelligence"],
39 "requestBody": {
40 "required": true,
41 "content": {
42 "application/json": {
43 "schema": {
44 "$ref": "#/components/schemas/ExplainRequest"
45 }
46 }
47 }
48 },
49 "responses": {
50 "200": {
51 "description": "Query analysis successful",
52 "content": {
53 "application/json": {
54 "schema": {
55 "$ref": "#/components/schemas/ApiResponseExplain"
56 }
57 }
58 }
59 },
60 "400": {
61 "description": "Invalid query or validation error"
62 }
63 }
64 }
65 },
66 "/api/v1/query/validate": {
67 "post": {
68 "summary": "Validate GraphQL query syntax",
69 "description": "Validates GraphQL query syntax without executing analysis. Fast validation for batch operations.",
70 "tags": ["Query Intelligence"],
71 "requestBody": {
72 "required": true,
73 "content": {
74 "application/json": {
75 "schema": {
76 "$ref": "#/components/schemas/ValidateRequest"
77 }
78 }
79 }
80 },
81 "responses": {
82 "200": {
83 "description": "Query validation result",
84 "content": {
85 "application/json": {
86 "schema": {
87 "$ref": "#/components/schemas/ApiResponseValidate"
88 }
89 }
90 }
91 }
92 }
93 }
94 },
95 "/api/v1/query/stats": {
96 "get": {
97 "summary": "Get query performance statistics",
98 "description": "Retrieves historical performance metrics for queries. Requires metrics collection to be enabled.",
99 "tags": ["Query Intelligence"],
100 "responses": {
101 "200": {
102 "description": "Query statistics",
103 "content": {
104 "application/json": {
105 "schema": {
106 "$ref": "#/components/schemas/ApiResponseStats"
107 }
108 }
109 }
110 }
111 }
112 }
113 },
114 "/api/v1/federation/subgraphs": {
115 "get": {
116 "summary": "List federation subgraphs",
117 "description": "Returns all federated subgraphs with their URLs, managed entities, and health status.",
118 "tags": ["Federation"],
119 "responses": {
120 "200": {
121 "description": "List of subgraphs",
122 "content": {
123 "application/json": {
124 "schema": {
125 "$ref": "#/components/schemas/ApiResponseSubgraphs"
126 }
127 }
128 }
129 }
130 }
131 }
132 },
133 "/api/v1/federation/graph": {
134 "get": {
135 "summary": "Export federation dependency graph",
136 "description": "Exports the federation structure showing subgraph relationships and entity resolution paths. Supports multiple output formats.",
137 "tags": ["Federation"],
138 "parameters": [
139 {
140 "name": "format",
141 "in": "query",
142 "description": "Output format: json (default), dot (Graphviz), or mermaid",
143 "schema": {
144 "type": "string",
145 "enum": ["json", "dot", "mermaid"],
146 "default": "json"
147 }
148 }
149 ],
150 "responses": {
151 "200": {
152 "description": "Federation graph in requested format",
153 "content": {
154 "application/json": {
155 "schema": {
156 "$ref": "#/components/schemas/ApiResponseGraph"
157 }
158 }
159 }
160 },
161 "400": {
162 "description": "Invalid format parameter"
163 }
164 }
165 }
166 },
167 "/api/v1/schema.graphql": {
168 "get": {
169 "summary": "Export schema as GraphQL SDL",
170 "description": "Exports the compiled schema in GraphQL Schema Definition Language (SDL) format. Returns text/plain response.",
171 "tags": ["Schema"],
172 "responses": {
173 "200": {
174 "description": "Schema in SDL format",
175 "content": {
176 "text/plain": {
177 "schema": {
178 "type": "string",
179 "example": "type Query { users: [User!]! }\ntype User { id: ID! name: String! }"
180 }
181 }
182 }
183 }
184 }
185 }
186 },
187 "/api/v1/schema.json": {
188 "get": {
189 "summary": "Export schema as JSON",
190 "description": "Exports the full compiled schema in JSON format with type information and metadata.",
191 "tags": ["Schema"],
192 "responses": {
193 "200": {
194 "description": "Schema as JSON",
195 "content": {
196 "application/json": {
197 "schema": {
198 "$ref": "#/components/schemas/ApiResponseSchemaJson"
199 }
200 }
201 }
202 }
203 }
204 }
205 },
206 "/api/v1/admin/reload-schema": {
207 "post": {
208 "summary": "Hot reload schema",
209 "description": "Reload schema from file without restarting the server. Supports validation-only mode.",
210 "tags": ["Admin"],
211 "security": [
212 {
213 "BearerAuth": []
214 }
215 ],
216 "requestBody": {
217 "required": true,
218 "content": {
219 "application/json": {
220 "schema": {
221 "$ref": "#/components/schemas/ReloadSchemaRequest"
222 }
223 }
224 }
225 },
226 "responses": {
227 "200": {
228 "description": "Schema reload result",
229 "content": {
230 "application/json": {
231 "schema": {
232 "$ref": "#/components/schemas/ApiResponseReloadSchema"
233 }
234 }
235 }
236 },
237 "401": {
238 "description": "Unauthorized - admin token required"
239 },
240 "400": {
241 "description": "Invalid schema or validation error"
242 }
243 }
244 }
245 },
246 "/api/v1/admin/cache/clear": {
247 "post": {
248 "summary": "Clear cache entries",
249 "description": "Invalidate cache by scope: all (clear everything), entity (by type), or pattern (by glob).",
250 "tags": ["Admin"],
251 "security": [
252 {
253 "BearerAuth": []
254 }
255 ],
256 "requestBody": {
257 "required": true,
258 "content": {
259 "application/json": {
260 "schema": {
261 "$ref": "#/components/schemas/CacheClearRequest"
262 }
263 }
264 }
265 },
266 "responses": {
267 "200": {
268 "description": "Cache clear result",
269 "content": {
270 "application/json": {
271 "schema": {
272 "$ref": "#/components/schemas/ApiResponseCacheClear"
273 }
274 }
275 }
276 },
277 "401": {
278 "description": "Unauthorized - admin token required"
279 }
280 }
281 }
282 },
283 "/api/v1/admin/config": {
284 "get": {
285 "summary": "Get runtime configuration",
286 "description": "Returns sanitized runtime configuration (secrets excluded). Requires admin token.",
287 "tags": ["Admin"],
288 "security": [
289 {
290 "BearerAuth": []
291 }
292 ],
293 "responses": {
294 "200": {
295 "description": "Runtime configuration",
296 "content": {
297 "application/json": {
298 "schema": {
299 "$ref": "#/components/schemas/ApiResponseConfig"
300 }
301 }
302 }
303 },
304 "401": {
305 "description": "Unauthorized - admin token required"
306 }
307 }
308 }
309 }
310 },
311 "components": {
312 "securitySchemes": {
313 "BearerAuth": {
314 "type": "http",
315 "scheme": "bearer",
316 "description": "Bearer token for admin endpoints"
317 }
318 },
319 "schemas": {
320 "ExplainRequest": {
321 "type": "object",
322 "required": ["query"],
323 "properties": {
324 "query": {
325 "type": "string",
326 "description": "GraphQL query to analyze",
327 "example": "query { users { id name } }"
328 }
329 }
330 },
331 "ComplexityInfo": {
332 "type": "object",
333 "properties": {
334 "depth": {
335 "type": "integer",
336 "description": "Query nesting depth",
337 "example": 2
338 },
339 "field_count": {
340 "type": "integer",
341 "description": "Total fields requested",
342 "example": 10
343 },
344 "score": {
345 "type": "integer",
346 "description": "Complexity score (depth × field_count)",
347 "example": 45
348 }
349 }
350 },
351 "ExplainResponse": {
352 "type": "object",
353 "properties": {
354 "query": {
355 "type": "string"
356 },
357 "sql": {
358 "type": "string",
359 "nullable": true,
360 "description": "Generated SQL execution plan"
361 },
362 "estimated_cost": {
363 "type": "integer"
364 },
365 "complexity": {
366 "$ref": "#/components/schemas/ComplexityInfo"
367 },
368 "warnings": {
369 "type": "array",
370 "items": {
371 "type": "string"
372 }
373 }
374 }
375 },
376 "ValidateRequest": {
377 "type": "object",
378 "required": ["query"],
379 "properties": {
380 "query": {
381 "type": "string",
382 "description": "GraphQL query to validate"
383 }
384 }
385 },
386 "ValidateResponse": {
387 "type": "object",
388 "properties": {
389 "valid": {
390 "type": "boolean"
391 },
392 "errors": {
393 "type": "array",
394 "items": {
395 "type": "string"
396 }
397 }
398 }
399 },
400 "StatsResponse": {
401 "type": "object",
402 "properties": {
403 "query_count": {
404 "type": "integer"
405 },
406 "avg_latency_ms": {
407 "type": "number"
408 }
409 }
410 },
411 "SubgraphInfo": {
412 "type": "object",
413 "properties": {
414 "name": {
415 "type": "string",
416 "example": "users"
417 },
418 "url": {
419 "type": "string",
420 "example": "http://users.local/graphql"
421 },
422 "entities": {
423 "type": "array",
424 "items": {
425 "type": "string"
426 }
427 },
428 "healthy": {
429 "type": "boolean"
430 }
431 }
432 },
433 "SubgraphsResponse": {
434 "type": "object",
435 "properties": {
436 "subgraphs": {
437 "type": "array",
438 "items": {
439 "$ref": "#/components/schemas/SubgraphInfo"
440 }
441 }
442 }
443 },
444 "GraphResponse": {
445 "type": "object",
446 "properties": {
447 "format": {
448 "type": "string",
449 "enum": ["json", "dot", "mermaid"]
450 },
451 "content": {
452 "type": "string",
453 "description": "Graph in requested format"
454 }
455 }
456 },
457 "JsonSchemaResponse": {
458 "type": "object",
459 "properties": {
460 "schema": {
461 "type": "object",
462 "description": "Compiled schema as JSON"
463 }
464 }
465 },
466 "ReloadSchemaRequest": {
467 "type": "object",
468 "required": ["schema_path"],
469 "properties": {
470 "schema_path": {
471 "type": "string",
472 "description": "Path to compiled schema file",
473 "example": "/path/to/schema.compiled.json"
474 },
475 "validate_only": {
476 "type": "boolean",
477 "description": "If true, only validate without applying",
478 "default": false
479 }
480 }
481 },
482 "ReloadSchemaResponse": {
483 "type": "object",
484 "properties": {
485 "success": {
486 "type": "boolean"
487 },
488 "message": {
489 "type": "string"
490 }
491 }
492 },
493 "CacheClearRequest": {
494 "type": "object",
495 "required": ["scope"],
496 "properties": {
497 "scope": {
498 "type": "string",
499 "enum": ["all", "entity", "pattern"],
500 "description": "Scope for cache clearing"
501 },
502 "entity_type": {
503 "type": "string",
504 "nullable": true,
505 "description": "Required if scope is 'entity'"
506 },
507 "pattern": {
508 "type": "string",
509 "nullable": true,
510 "description": "Required if scope is 'pattern'"
511 }
512 }
513 },
514 "CacheClearResponse": {
515 "type": "object",
516 "properties": {
517 "success": {
518 "type": "boolean"
519 },
520 "entries_cleared": {
521 "type": "integer"
522 },
523 "message": {
524 "type": "string"
525 }
526 }
527 },
528 "AdminConfigResponse": {
529 "type": "object",
530 "properties": {
531 "version": {
532 "type": "string",
533 "example": "2.0.0-a1"
534 },
535 "config": {
536 "type": "object",
537 "description": "Sanitized configuration (no secrets)",
538 "additionalProperties": {
539 "type": "string"
540 }
541 }
542 }
543 },
544 "ApiResponse": {
545 "type": "object",
546 "properties": {
547 "status": {
548 "type": "string",
549 "example": "success"
550 },
551 "data": {
552 "type": "object"
553 }
554 }
555 },
556 "ApiResponseExplain": {
557 "allOf": [
558 {
559 "$ref": "#/components/schemas/ApiResponse"
560 },
561 {
562 "type": "object",
563 "properties": {
564 "data": {
565 "$ref": "#/components/schemas/ExplainResponse"
566 }
567 }
568 }
569 ]
570 },
571 "ApiResponseValidate": {
572 "allOf": [
573 {
574 "$ref": "#/components/schemas/ApiResponse"
575 },
576 {
577 "type": "object",
578 "properties": {
579 "data": {
580 "$ref": "#/components/schemas/ValidateResponse"
581 }
582 }
583 }
584 ]
585 },
586 "ApiResponseStats": {
587 "allOf": [
588 {
589 "$ref": "#/components/schemas/ApiResponse"
590 },
591 {
592 "type": "object",
593 "properties": {
594 "data": {
595 "$ref": "#/components/schemas/StatsResponse"
596 }
597 }
598 }
599 ]
600 },
601 "ApiResponseSubgraphs": {
602 "allOf": [
603 {
604 "$ref": "#/components/schemas/ApiResponse"
605 },
606 {
607 "type": "object",
608 "properties": {
609 "data": {
610 "$ref": "#/components/schemas/SubgraphsResponse"
611 }
612 }
613 }
614 ]
615 },
616 "ApiResponseGraph": {
617 "allOf": [
618 {
619 "$ref": "#/components/schemas/ApiResponse"
620 },
621 {
622 "type": "object",
623 "properties": {
624 "data": {
625 "$ref": "#/components/schemas/GraphResponse"
626 }
627 }
628 }
629 ]
630 },
631 "ApiResponseSchemaJson": {
632 "allOf": [
633 {
634 "$ref": "#/components/schemas/ApiResponse"
635 },
636 {
637 "type": "object",
638 "properties": {
639 "data": {
640 "$ref": "#/components/schemas/JsonSchemaResponse"
641 }
642 }
643 }
644 ]
645 },
646 "ApiResponseReloadSchema": {
647 "allOf": [
648 {
649 "$ref": "#/components/schemas/ApiResponse"
650 },
651 {
652 "type": "object",
653 "properties": {
654 "data": {
655 "$ref": "#/components/schemas/ReloadSchemaResponse"
656 }
657 }
658 }
659 ]
660 },
661 "ApiResponseCacheClear": {
662 "allOf": [
663 {
664 "$ref": "#/components/schemas/ApiResponse"
665 },
666 {
667 "type": "object",
668 "properties": {
669 "data": {
670 "$ref": "#/components/schemas/CacheClearResponse"
671 }
672 }
673 }
674 ]
675 },
676 "ApiResponseConfig": {
677 "allOf": [
678 {
679 "$ref": "#/components/schemas/ApiResponse"
680 },
681 {
682 "type": "object",
683 "properties": {
684 "data": {
685 "$ref": "#/components/schemas/AdminConfigResponse"
686 }
687 }
688 }
689 ]
690 }
691 }
692 }
693 }).to_string()
694}