package api import "git.threesix.ai/jordan/sp4-verify-1770325799/pkg/openapi" // NewServiceSpec builds the OpenAPI specification for the auth-svc service. func NewServiceSpec() *openapi.OpenAPISpec { spec := openapi.NewOpenAPISpec("auth-svc API", "1.0.0"). WithDescription("REST API for the auth-svc service"). WithBearerSecurity("bearer", "JWT authentication token"). WithTag("Health", "Service health endpoints"). WithTag("Auth", "Authentication and token validation"). WithTag("Examples", "Example CRUD endpoints") // Define reusable schemas spec.WithSchema("Example", openapi.Object(map[string]openapi.Schema{ "id": openapi.UUID().WithDescription("Unique identifier"), "name": openapi.String().WithDescription("Name of the example").WithExample("My Example"), "description": openapi.String().WithDescription("Optional description").WithExample("A description"), "created_at": openapi.DateTime().WithDescription("Creation timestamp"), "updated_at": openapi.DateTime().WithDescription("Last update timestamp"), }, "id", "name")) spec.WithSchema("CreateExampleRequest", openapi.Object(map[string]openapi.Schema{ "name": openapi.StringWithMinMax(1, 100).WithDescription("Name of the example"), "description": openapi.StringWithMinMax(0, 500).WithDescription("Optional description"), }, "name")) spec.WithSchema("UpdateExampleRequest", openapi.Object(map[string]openapi.Schema{ "name": openapi.StringWithMinMax(1, 100).WithDescription("Updated name"), "description": openapi.StringWithMinMax(0, 500).WithDescription("Updated description"), })) // Validate response schema spec.WithSchema("ValidateResponse", openapi.Object(map[string]openapi.Schema{ "valid": openapi.Boolean().WithDescription("Whether the token is valid"), "user": openapi.Object(map[string]openapi.Schema{ "id": openapi.String().WithDescription("User ID"), "email": openapi.String().WithDescription("User email"), "roles": openapi.Array(openapi.String()).WithDescription("User roles"), "scopes": openapi.Array(openapi.String()).WithDescription("User scopes"), }).WithDescription("User information (only present if valid)"), "error": openapi.String().WithDescription("Error message (only present if invalid)"), }, "valid")) // Health spec.AddPath("/api/auth-svc/health", "get", map[string]any{ "summary": "Health check", "tags": []string{"Health"}, "responses": map[string]any{ "200": openapi.OpResponse("Service is healthy", openapi.Object(map[string]openapi.Schema{ "service": openapi.String(), "status": openapi.String(), })), }, }) // Validate token spec.AddPath("/api/auth-svc/validate", "post", map[string]any{ "summary": "Validate token", "description": "Validates a JWT token and returns user information. Used by sibling services for authentication.", "tags": []string{"Auth"}, "security": []map[string][]string{{"bearer": {}}}, "responses": map[string]any{ "200": openapi.OpResponse("Validation result", openapi.ResponseSchema(openapi.Ref("ValidateResponse"))), "400": openapi.OpResponse("Bad request", openapi.ErrorResponseSchema()), }, }) spec.AddPath("/api/auth-svc/validate", "get", map[string]any{ "summary": "Validate token (GET)", "description": "Validates a JWT token. Accepts token via Authorization header or query parameter.", "tags": []string{"Auth"}, "parameters": []any{ map[string]any{ "name": "token", "in": "query", "description": "JWT token to validate (alternative to Authorization header)", "schema": openapi.String(), }, }, "responses": map[string]any{ "200": openapi.OpResponse("Validation result", openapi.ResponseSchema(openapi.Ref("ValidateResponse"))), "400": openapi.OpResponse("Bad request", openapi.ErrorResponseSchema()), }, }) // List examples spec.AddPath("/api/auth-svc/examples", "get", map[string]any{ "summary": "List examples", "description": "Returns a paginated list of examples.", "tags": []string{"Examples"}, "parameters": []any{openapi.PageParam(), openapi.PerPageParam()}, "responses": map[string]any{ "200": openapi.OpResponse("Success", openapi.ResponseSchema(openapi.RefArray("Example"))), }, }) // Get example spec.AddPath("/api/auth-svc/examples/{id}", "get", map[string]any{ "summary": "Get example by ID", "tags": []string{"Examples"}, "parameters": []any{openapi.IDParam()}, "responses": map[string]any{ "200": openapi.OpResponse("Success", openapi.ResponseSchema(openapi.Ref("Example"))), "404": openapi.OpResponse("Not found", openapi.ErrorResponseSchema()), }, }) // Create example spec.AddPath("/api/auth-svc/examples", "post", map[string]any{ "summary": "Create example", "description": "Creates a new example. Requires authentication.", "tags": []string{"Examples"}, "security": []map[string][]string{{"bearer": {}}}, "requestBody": openapi.RequestBody(openapi.Ref("CreateExampleRequest"), true), "responses": map[string]any{ "201": openapi.OpResponse("Created", openapi.ResponseSchema(openapi.Ref("Example"))), "400": openapi.OpResponse("Bad request", openapi.ErrorResponseSchema()), "401": openapi.OpResponse("Unauthorized", openapi.ErrorResponseSchema()), "422": openapi.OpResponse("Validation error", openapi.ErrorResponseSchema()), }, }) // Update example spec.AddPath("/api/auth-svc/examples/{id}", "put", map[string]any{ "summary": "Update example", "description": "Updates an existing example. Requires authentication.", "tags": []string{"Examples"}, "security": []map[string][]string{{"bearer": {}}}, "parameters": []any{openapi.IDParam()}, "requestBody": openapi.RequestBody(openapi.Ref("UpdateExampleRequest"), true), "responses": map[string]any{ "200": openapi.OpResponse("Updated", openapi.ResponseSchema(openapi.Ref("Example"))), "400": openapi.OpResponse("Bad request", openapi.ErrorResponseSchema()), "401": openapi.OpResponse("Unauthorized", openapi.ErrorResponseSchema()), "404": openapi.OpResponse("Not found", openapi.ErrorResponseSchema()), }, }) // Delete example spec.AddPath("/api/auth-svc/examples/{id}", "delete", map[string]any{ "summary": "Delete example", "description": "Deletes an example by ID. Requires authentication.", "tags": []string{"Examples"}, "security": []map[string][]string{{"bearer": {}}}, "parameters": []any{openapi.IDParam()}, "responses": map[string]any{ "204": openapi.OpResponseNoContent(), "401": openapi.OpResponse("Unauthorized", openapi.ErrorResponseSchema()), "404": openapi.OpResponse("Not found", openapi.ErrorResponseSchema()), }, }) return spec }