generated from coulomb/repo-seed
All checks were successful
Build and Deploy / build-push-deploy (push) Successful in 3m6s
894 lines
34 KiB
Haskell
894 lines
34 KiB
Haskell
module Web.Controller.Api.V2.OpenApi where
|
|
|
|
-- GET /api/v2/openapi.json — OpenAPI 3.1 spec with live type registry enums
|
|
-- GET /api/v2/openapi.yaml — YAML convenience alias
|
|
-- GET /api/v2/docs — Swagger UI
|
|
|
|
import Web.Types
|
|
import Generated.Types
|
|
import IHP.Prelude
|
|
import IHP.ControllerPrelude
|
|
import Data.Aeson (object, (.=), Array, toJSON)
|
|
import qualified Data.Aeson as A
|
|
import qualified Data.Aeson.Key as K
|
|
import qualified Data.Vector as V
|
|
import qualified Data.Text as T
|
|
import qualified Data.Text.Encoding as TE
|
|
import qualified Data.Yaml as Yaml -- yaml package
|
|
import qualified Data.ByteString.Lazy as LBS
|
|
import Application.Helper.TypeRegistry
|
|
( activeWidgetTypes, activeEventTypes, activeAnnotationCategories
|
|
, activePolicyScopes )
|
|
import Network.HTTP.Types (status200)
|
|
import Network.Wai (responseLBS)
|
|
|
|
instance Controller ApiV2OpenApiController where
|
|
|
|
action ApiV2OpenApiJsonAction = do
|
|
spec <- buildOpenApiSpec
|
|
respondAndExit $ responseLBS status200
|
|
[("Content-Type", "application/json")]
|
|
(A.encode spec)
|
|
|
|
action ApiV2OpenApiYamlAction = do
|
|
spec <- buildOpenApiSpec
|
|
let yaml = Yaml.encode spec
|
|
respondAndExit $ responseLBS status200
|
|
[("Content-Type", "application/yaml")]
|
|
(LBS.fromStrict yaml)
|
|
|
|
action ApiV2DocsAction = do
|
|
respondAndExit $ responseLBS status200
|
|
[("Content-Type", "text/html; charset=utf-8")]
|
|
swaggerUiHtml
|
|
|
|
-- | Build the full OpenAPI 3.1 document from live registry data.
|
|
buildOpenApiSpec :: (?modelContext :: ModelContext) => IO Value
|
|
buildOpenApiSpec = do
|
|
(fwWidgetTypes, ownedWidgetTypes) <- activeWidgetTypes
|
|
let allWidgetTypes = fwWidgetTypes ++ ownedWidgetTypes
|
|
eventTypes <- activeEventTypes
|
|
annCats <- activeAnnotationCategories
|
|
policyScopes <- activePolicyScopes
|
|
|
|
let wtEnum = toJSON $ map (.name) allWidgetTypes
|
|
let etEnum = toJSON $ map (.name) eventTypes
|
|
let acEnum = toJSON $ map (.name) annCats
|
|
let psEnum = toJSON $ map (.name) policyScopes
|
|
|
|
pure $ object
|
|
[ "openapi" .= ("3.1.0" :: Text)
|
|
, "info" .= object
|
|
[ "title" .= ("Interaction Hub Framework API" :: Text)
|
|
, "version" .= ("2.0" :: Text)
|
|
, "description" .= ("IHF external API v2. For the human-readable contract see /contracts/functional/interaction-reporting-v1.md" :: Text)
|
|
]
|
|
, "x-ihf-contract" .= ("/contracts/functional/interaction-reporting-v1.md" :: Text)
|
|
, "servers" .= [object ["url" .= ("/api/v2" :: Text)]]
|
|
, "paths" .= buildPaths
|
|
, "components" .= object
|
|
[ "schemas" .= object
|
|
[ "WidgetType" .= object
|
|
[ "type" .= ("string" :: Text)
|
|
, "enum" .= wtEnum
|
|
]
|
|
, "EventType" .= object
|
|
[ "type" .= ("string" :: Text)
|
|
, "enum" .= etEnum
|
|
]
|
|
, "AnnotationCategory" .= object
|
|
[ "type" .= ("string" :: Text)
|
|
, "enum" .= acEnum
|
|
]
|
|
, "PolicyScope" .= object
|
|
[ "type" .= ("string" :: Text)
|
|
, "enum" .= psEnum
|
|
]
|
|
, "PaginationMeta" .= object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "page" .= object ["type" .= ("integer" :: Text)]
|
|
, "per_page" .= object ["type" .= ("integer" :: Text)]
|
|
, "total" .= object ["type" .= ("integer" :: Text)]
|
|
]
|
|
]
|
|
, "Hub" .= hubSchema
|
|
, "CreateHubRequest" .= createHubRequestSchema
|
|
, "HubCapabilityManifest" .= manifestSchema
|
|
, "CreateHubCapabilityManifestRequest" .= createManifestRequestSchema
|
|
, "UpdateHubCapabilityManifestRequest" .= updateManifestRequestSchema
|
|
, "ApiConsumer" .= apiConsumerSchema
|
|
, "CreateApiConsumerRequest" .= createApiConsumerRequestSchema
|
|
, "ApiKey" .= apiKeySchema
|
|
, "CreateApiKeyRequest" .= createApiKeyRequestSchema
|
|
, "ApiKeyCreatedResponse" .= apiKeyCreatedResponseSchema
|
|
, "Widget" .= widgetSchema
|
|
, "CreateWidgetRequest" .= createWidgetRequestSchema
|
|
, "InteractionEvent" .= interactionEventSchema
|
|
, "CreateInteractionEventRequest" .= createInteractionEventRequestSchema
|
|
, "Annotation" .= annotationSchema
|
|
, "CreateAnnotationRequest" .= createAnnotationRequestSchema
|
|
, "RequirementCandidate" .= rcSchema
|
|
, "DecisionRecord" .= drSchema
|
|
, "DeploymentRecord" .= depSchema
|
|
, "OutcomeSignal" .= sigSchema
|
|
, "OutcomeCorrelation" .= outcomeCorrelationSchema
|
|
, "PatternPerformanceRecord" .= patternPerformanceSchema
|
|
, "InstitutionalKnowledgeEntry" .= institutionalKnowledgeSchema
|
|
, "HubRegistryEntry" .= hubRegistryEntrySchema
|
|
, "HubManifestSummary" .= hubManifestSummarySchema
|
|
, "WidgetPattern" .= widgetPatternSchema
|
|
, "WidgetPatternDetail" .= widgetPatternDetailSchema
|
|
, "WidgetPatternVersion" .= widgetPatternVersionSchema
|
|
, "PatternAdoptionResponse" .= patternAdoptionResponseSchema
|
|
]
|
|
, "securitySchemes" .= object
|
|
[ "BearerAuth" .= object
|
|
[ "type" .= ("http" :: Text)
|
|
, "scheme" .= ("bearer" :: Text)
|
|
, "description" .= ("API key or OAuth token obtained via POST /api/v2/token" :: Text)
|
|
]
|
|
]
|
|
]
|
|
, "security" .= [object ["BearerAuth" .= ([] :: [Text])]]
|
|
]
|
|
|
|
buildPaths :: Value
|
|
buildPaths = object
|
|
[ "/hubs" .= object
|
|
[ "get" .= publicPaginatedListOp "Hub" []
|
|
, "post" .= writeOp "Hub" "CreateHubRequest"
|
|
]
|
|
, "/hubs/{id}" .= getShowPath "Hub"
|
|
, "/hub-capability-manifests" .= object
|
|
[ "get" .= listOp "HubCapabilityManifest"
|
|
[ ("hubId", "string", "uuid")
|
|
, ("status", "string", "")
|
|
]
|
|
, "post" .= writeOp "HubCapabilityManifest" "CreateHubCapabilityManifestRequest"
|
|
]
|
|
, "/hub-capability-manifests/{id}" .= object
|
|
[ "get" .= showOp "HubCapabilityManifest"
|
|
, "patch" .= writeOpWithStatusAndParams
|
|
"Update HubCapabilityManifest"
|
|
"HubCapabilityManifest"
|
|
"UpdateHubCapabilityManifestRequest"
|
|
True
|
|
"200"
|
|
[pathParam "id"]
|
|
]
|
|
, "/hub-capability-manifests/{id}/activate" .= object
|
|
[ "post" .= postNoBodyOpWithStatusAndParams
|
|
"Activate HubCapabilityManifest"
|
|
"HubCapabilityManifest"
|
|
"200"
|
|
[pathParam "id"]
|
|
]
|
|
, "/api-consumers" .= object
|
|
[ "get" .= listOp "ApiConsumer" []
|
|
, "post" .= writeOp "ApiConsumer" "CreateApiConsumerRequest"
|
|
]
|
|
, "/api-consumers/{id}" .= getShowPath "ApiConsumer"
|
|
, "/api-consumers/{id}/api-keys" .= object
|
|
[ "post" .= writeOpWithResponseStatusAndParams
|
|
"Create ApiKey"
|
|
"ApiKeyCreatedResponse"
|
|
"CreateApiKeyRequest"
|
|
False
|
|
"201"
|
|
[pathParam "id"]
|
|
]
|
|
, "/widgets" .= object
|
|
[ "get" .= listOp "Widget" []
|
|
, "post" .= writeOp "Widget" "CreateWidgetRequest"
|
|
]
|
|
, "/widgets/{id}" .= getShowPath "Widget"
|
|
, "/interaction-events" .= object
|
|
[ "get" .= listOp "InteractionEvent"
|
|
[ ("widgetId", "string", "uuid")
|
|
, ("eventType", "string", "")
|
|
]
|
|
, "post" .= writeOp "InteractionEvent" "CreateInteractionEventRequest"
|
|
]
|
|
, "/annotations" .= object
|
|
[ "get" .= listOp "Annotation"
|
|
[ ("widgetId", "string", "uuid")
|
|
, ("category", "string", "")
|
|
]
|
|
, "post" .= writeOp "Annotation" "CreateAnnotationRequest"
|
|
]
|
|
, "/requirement-candidates" .= getListPath "RequirementCandidate"
|
|
, "/requirement-candidates/{id}" .= getShowPath "RequirementCandidate"
|
|
, "/decision-records" .= getListPath "DecisionRecord"
|
|
, "/decision-records/{id}" .= getShowPath "DecisionRecord"
|
|
, "/deployment-records" .= getListPath "DeploymentRecord"
|
|
, "/deployment-records/{id}" .= getShowPath "DeploymentRecord"
|
|
, "/outcome-signals" .= getListPath "OutcomeSignal"
|
|
, "/outcome-signals/{id}" .= getShowPath "OutcomeSignal"
|
|
, "/widget-types" .= publicListPath "WidgetTypeRegistry"
|
|
, "/event-types" .= publicListPath "EventTypeRegistry"
|
|
, "/annotation-categories" .= publicListPath "AnnotationCategoryRegistry"
|
|
, "/policy-scopes" .= publicListPath "PolicyScopeRegistry"
|
|
, "/token" .= tokenPath
|
|
-- Phase 10 — Hub Registry and Widget Marketplace
|
|
, "/hub-registry" .= getListPath "HubRegistryEntry"
|
|
, "/hub-registry/{hubId}" .= getShowPathWithParam "HubRegistryEntry" "hubId"
|
|
, "/widget-patterns" .= getListPath "WidgetPattern"
|
|
, "/widget-patterns/{id}" .= getShowPath "WidgetPatternDetail"
|
|
, "/widget-patterns/{id}/adopt" .= object
|
|
[ "post" .= postNoBodyOpWithStatusAndParams
|
|
"Adopt WidgetPattern"
|
|
"PatternAdoptionResponse"
|
|
"200"
|
|
[pathParam "id"]
|
|
]
|
|
]
|
|
|
|
getListPath :: Text -> Value
|
|
getListPath schemaName = object
|
|
[ "get" .= listOp schemaName [] ]
|
|
|
|
getShowPath :: Text -> Value
|
|
getShowPath schemaName = object
|
|
[ "get" .= showOp schemaName ]
|
|
|
|
getShowPathWithParam :: Text -> Text -> Value
|
|
getShowPathWithParam schemaName paramName = object
|
|
[ "get" .= showOpWithParam schemaName paramName ]
|
|
|
|
listOp :: Text -> [(Text, Text, Text)] -> Value
|
|
listOp schemaName extraParams = object
|
|
[ "summary" .= ("List " <> schemaName)
|
|
, "security" .= [object ["BearerAuth" .= ([] :: [Text])]]
|
|
, "parameters" .= (pageParams ++ map toParam extraParams)
|
|
, "responses" .= object
|
|
[ "200" .= object
|
|
[ "description" .= ("OK" :: Text)
|
|
, "content" .= object
|
|
[ "application/json" .= object
|
|
[ "schema" .= object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "data" .= object
|
|
[ "type" .= ("array" :: Text)
|
|
, "items" .= object ["$ref" .= ("#/components/schemas/" <> schemaName)]
|
|
]
|
|
, "meta" .= object ["$ref" .= ("#/components/schemas/PaginationMeta" :: Text)]
|
|
]
|
|
]
|
|
]
|
|
]
|
|
]
|
|
, "401" .= object ["description" .= ("Unauthorized" :: Text)]
|
|
]
|
|
]
|
|
where
|
|
toParam (name, typ, fmt) = object $
|
|
[ "name" .= name, "in" .= ("query" :: Text)
|
|
, "schema" .= object (["type" .= typ] ++ if fmt /= "" then [("format", A.String fmt)] else [])
|
|
]
|
|
|
|
publicPaginatedListOp :: Text -> [(Text, Text, Text)] -> Value
|
|
publicPaginatedListOp schemaName extraParams = object
|
|
[ "summary" .= ("List " <> schemaName)
|
|
, "security" .= ([] :: [Value])
|
|
, "parameters" .= (pageParams ++ map toParam extraParams)
|
|
, "responses" .= object
|
|
[ "200" .= object
|
|
[ "description" .= ("OK" :: Text)
|
|
, "content" .= object
|
|
[ "application/json" .= object
|
|
[ "schema" .= object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "data" .= object
|
|
[ "type" .= ("array" :: Text)
|
|
, "items" .= object ["$ref" .= ("#/components/schemas/" <> schemaName)]
|
|
]
|
|
, "meta" .= object ["$ref" .= ("#/components/schemas/PaginationMeta" :: Text)]
|
|
]
|
|
]
|
|
]
|
|
]
|
|
]
|
|
]
|
|
]
|
|
where
|
|
toParam (name, typ, fmt) = object $
|
|
[ "name" .= name, "in" .= ("query" :: Text)
|
|
, "schema" .= object (["type" .= typ] ++ if fmt /= "" then [("format", A.String fmt)] else [])
|
|
]
|
|
|
|
showOp :: Text -> Value
|
|
showOp schemaName = showOpWithParam schemaName "id"
|
|
|
|
showOpWithParam :: Text -> Text -> Value
|
|
showOpWithParam schemaName paramName = object
|
|
[ "summary" .= ("Get " <> schemaName)
|
|
, "security" .= [object ["BearerAuth" .= ([] :: [Text])]]
|
|
, "parameters" .= [pathParam paramName]
|
|
, "responses" .= object
|
|
[ "200" .= object
|
|
[ "description" .= ("OK" :: Text)
|
|
, "content" .= object
|
|
[ "application/json" .= object
|
|
["schema" .= object ["$ref" .= ("#/components/schemas/" <> schemaName)]]
|
|
]
|
|
]
|
|
, "401" .= object ["description" .= ("Unauthorized" :: Text)]
|
|
, "404" .= object ["description" .= ("Not found" :: Text)]
|
|
]
|
|
]
|
|
|
|
writeOp :: Text -> Text -> Value
|
|
writeOp schemaName reqSchema = writeOpWithSummary ("Create " <> schemaName) schemaName reqSchema
|
|
|
|
writeOpWithSummary :: Text -> Text -> Text -> Value
|
|
writeOpWithSummary summaryText schemaName reqSchema =
|
|
writeOpWithStatusAndParams summaryText schemaName reqSchema True "201" []
|
|
|
|
writeOpWithStatusAndParams :: Text -> Text -> Text -> Bool -> Text -> [Value] -> Value
|
|
writeOpWithStatusAndParams = writeOpWithResponseStatusAndParams
|
|
|
|
writeOpWithResponseStatusAndParams :: Text -> Text -> Text -> Bool -> Text -> [Value] -> Value
|
|
writeOpWithResponseStatusAndParams summaryText responseSchema reqSchema bodyRequired successStatus params = object
|
|
[ "summary" .= summaryText
|
|
, "security" .= [object ["BearerAuth" .= ([] :: [Text])]]
|
|
, "parameters" .= params
|
|
, "requestBody" .= object
|
|
[ "required" .= bodyRequired
|
|
, "content" .= object
|
|
[ "application/json" .= object
|
|
["schema" .= object ["$ref" .= ("#/components/schemas/" <> reqSchema)]]
|
|
]
|
|
]
|
|
, "responses" .= object
|
|
[ K.fromText successStatus .= object
|
|
[ "description" .= ("OK" :: Text)
|
|
, "content" .= object
|
|
[ "application/json" .= object
|
|
["schema" .= object ["$ref" .= ("#/components/schemas/" <> responseSchema)]]
|
|
]
|
|
]
|
|
, "400" .= object ["description" .= ("Invalid request" :: Text)]
|
|
, "401" .= object ["description" .= ("Unauthorized" :: Text)]
|
|
, "422" .= object ["description" .= ("Validation error" :: Text)]
|
|
]
|
|
]
|
|
|
|
postNoBodyOpWithStatusAndParams :: Text -> Text -> Text -> [Value] -> Value
|
|
postNoBodyOpWithStatusAndParams summaryText responseSchema successStatus params = object
|
|
[ "summary" .= summaryText
|
|
, "security" .= [object ["BearerAuth" .= ([] :: [Text])]]
|
|
, "parameters" .= params
|
|
, "responses" .= object
|
|
[ K.fromText successStatus .= object
|
|
[ "description" .= ("OK" :: Text)
|
|
, "content" .= object
|
|
[ "application/json" .= object
|
|
["schema" .= object ["$ref" .= ("#/components/schemas/" <> responseSchema)]]
|
|
]
|
|
]
|
|
, "400" .= object ["description" .= ("Invalid request" :: Text)]
|
|
, "401" .= object ["description" .= ("Unauthorized" :: Text)]
|
|
, "422" .= object ["description" .= ("Validation error" :: Text)]
|
|
]
|
|
]
|
|
|
|
pathParam :: Text -> Value
|
|
pathParam name = object
|
|
[ "name" .= name
|
|
, "in" .= ("path" :: Text)
|
|
, "required" .= True
|
|
, "schema" .= uuidProp
|
|
]
|
|
|
|
publicListPath :: Text -> Value
|
|
publicListPath schemaName = object
|
|
[ "get" .= object
|
|
[ "summary" .= ("List registered " <> schemaName <> " values" :: Text)
|
|
, "security" .= ([] :: [Value])
|
|
, "responses" .= object
|
|
[ "200" .= object ["description" .= ("OK" :: Text)] ]
|
|
]
|
|
]
|
|
|
|
tokenPath :: Value
|
|
tokenPath = object
|
|
[ "post" .= object
|
|
[ "summary" .= ("Obtain OAuth access token (client credentials)" :: Text)
|
|
, "requestBody" .= object
|
|
[ "required" .= True
|
|
, "content" .= object
|
|
[ "application/x-www-form-urlencoded" .= object
|
|
[ "schema" .= object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "grant_type" .= object ["type" .= ("string" :: Text), "enum" .= ["client_credentials" :: Text]]
|
|
, "client_id" .= object ["type" .= ("string" :: Text), "format" .= ("uuid" :: Text)]
|
|
, "client_secret" .= object ["type" .= ("string" :: Text)]
|
|
, "scope" .= object ["type" .= ("string" :: Text)]
|
|
]
|
|
]
|
|
]
|
|
]
|
|
]
|
|
, "responses" .= object
|
|
[ "200" .= object ["description" .= ("Access token issued" :: Text)]
|
|
, "400" .= object ["description" .= ("Invalid request or credentials" :: Text)]
|
|
]
|
|
]
|
|
]
|
|
|
|
pageParams :: [Value]
|
|
pageParams =
|
|
[ object ["name" .= ("page" :: Text), "in" .= ("query" :: Text), "schema" .= object ["type" .= ("integer" :: Text)]]
|
|
, object ["name" .= ("per_page" :: Text), "in" .= ("query" :: Text), "schema" .= object ["type" .= ("integer" :: Text)]]
|
|
]
|
|
|
|
-- Schemas for all resource types
|
|
|
|
hubSchema :: Value
|
|
hubSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "id" .= uuidProp
|
|
, "slug" .= strProp
|
|
, "name" .= strProp
|
|
, "domain" .= strProp
|
|
, "hubKind" .= object ["type" .= ("string" :: Text), "enum" .= ["domain" :: Text, "shared"]]
|
|
, "hubFamily" .= object ["type" .= ("string" :: Text), "enum" .= ["vsm" :: Text]]
|
|
, "vsmFunction" .= strProp
|
|
, "vsmSystem" .= object ["type" .= ("string" :: Text), "enum" .= ["1" :: Text, "2", "3", "3*", "4", "5", "environment"]]
|
|
, "createdAt" .= object ["type" .= ("string" :: Text), "format" .= ("date-time" :: Text)]
|
|
]
|
|
]
|
|
|
|
createHubRequestSchema :: Value
|
|
createHubRequestSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "required" .= (["slug", "name", "domain"] :: [Text])
|
|
, "properties" .= object
|
|
[ "slug" .= strProp
|
|
, "name" .= strProp
|
|
, "domain" .= strProp
|
|
, "hubKind" .= object ["type" .= ("string" :: Text), "enum" .= ["domain" :: Text, "shared"]]
|
|
, "hubFamily" .= object ["type" .= ("string" :: Text), "enum" .= ["vsm" :: Text]]
|
|
, "vsmFunction" .= strProp
|
|
, "vsmSystem" .= object ["type" .= ("string" :: Text), "enum" .= ["1" :: Text, "2", "3", "3*", "4", "5", "environment"]]
|
|
]
|
|
]
|
|
|
|
widgetSchema :: Value
|
|
widgetSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "id" .= uuidProp
|
|
, "hubId" .= uuidProp
|
|
, "name" .= strProp
|
|
, "widgetType" .= object ["$ref" .= ("#/components/schemas/WidgetType" :: Text)]
|
|
, "capabilityRef" .= strProp
|
|
, "viewContext" .= strProp
|
|
, "policyScope" .= strProp
|
|
, "status" .= strProp
|
|
, "version" .= object ["type" .= ("integer" :: Text)]
|
|
, "createdAt" .= object ["type" .= ("string" :: Text), "format" .= ("date-time" :: Text)]
|
|
]
|
|
]
|
|
|
|
createWidgetRequestSchema :: Value
|
|
createWidgetRequestSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "required" .= (["hubId", "name", "widgetType"] :: [Text])
|
|
, "properties" .= object
|
|
[ "hubId" .= uuidProp
|
|
, "name" .= strProp
|
|
, "widgetType" .= object ["$ref" .= ("#/components/schemas/WidgetType" :: Text)]
|
|
, "capabilityRef" .= strProp
|
|
, "viewContext" .= strProp
|
|
, "policyScope" .= object ["$ref" .= ("#/components/schemas/PolicyScope" :: Text)]
|
|
, "status" .= object ["type" .= ("string" :: Text), "enum" .= ["active" :: Text, "deprecated", "draft"]]
|
|
, "adapterSpecId" .= uuidProp
|
|
]
|
|
]
|
|
|
|
manifestSchema :: Value
|
|
manifestSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "id" .= uuidProp
|
|
, "hubId" .= uuidProp
|
|
, "manifestVersion" .= strProp
|
|
, "declaredWidgetTypes" .= object ["type" .= ("array" :: Text), "items" .= object ["$ref" .= ("#/components/schemas/WidgetType" :: Text)]]
|
|
, "declaredEventTypes" .= object ["type" .= ("array" :: Text), "items" .= object ["$ref" .= ("#/components/schemas/EventType" :: Text)]]
|
|
, "declaredAnnotationCategories" .= object ["type" .= ("array" :: Text), "items" .= object ["$ref" .= ("#/components/schemas/AnnotationCategory" :: Text)]]
|
|
, "declaredPolicyScopes" .= object ["type" .= ("array" :: Text), "items" .= object ["$ref" .= ("#/components/schemas/PolicyScope" :: Text)]]
|
|
, "capabilityDescription" .= strProp
|
|
, "contact" .= strProp
|
|
, "status" .= strProp
|
|
, "activatedAt" .= dtProp
|
|
, "createdAt" .= dtProp
|
|
, "updatedAt" .= dtProp
|
|
]
|
|
]
|
|
|
|
createManifestRequestSchema :: Value
|
|
createManifestRequestSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "required" .= (["hubId"] :: [Text])
|
|
, "properties" .= manifestRequestProperties True
|
|
]
|
|
|
|
updateManifestRequestSchema :: Value
|
|
updateManifestRequestSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= manifestRequestProperties False
|
|
]
|
|
|
|
manifestRequestProperties :: Bool -> Value
|
|
manifestRequestProperties includeHubId =
|
|
object $
|
|
(if includeHubId then ["hubId" .= uuidProp] else [])
|
|
++ [ "manifestVersion" .= strProp
|
|
, "declaredWidgetTypes" .= arrayOfRef "WidgetType"
|
|
, "declaredEventTypes" .= arrayOfRef "EventType"
|
|
, "declaredAnnotationCategories" .= arrayOfRef "AnnotationCategory"
|
|
, "declaredPolicyScopes" .= arrayOfRef "PolicyScope"
|
|
, "capabilityDescription" .= strProp
|
|
, "contact" .= strProp
|
|
]
|
|
|
|
apiConsumerSchema :: Value
|
|
apiConsumerSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "id" .= uuidProp
|
|
, "name" .= strProp
|
|
, "description" .= strProp
|
|
, "hubCapabilityManifestId" .= uuidProp
|
|
, "rateLimitPerMinute" .= object ["type" .= ("integer" :: Text)]
|
|
, "quotaPerDay" .= object ["type" .= ("integer" :: Text)]
|
|
, "quotaResetsAt" .= dtProp
|
|
, "isActive" .= object ["type" .= ("boolean" :: Text)]
|
|
, "createdAt" .= dtProp
|
|
, "updatedAt" .= dtProp
|
|
]
|
|
]
|
|
|
|
createApiConsumerRequestSchema :: Value
|
|
createApiConsumerRequestSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "required" .= (["name"] :: [Text])
|
|
, "properties" .= object
|
|
[ "name" .= strProp
|
|
, "description" .= strProp
|
|
, "hubCapabilityManifestId" .= uuidProp
|
|
, "rateLimitPerMinute" .= object ["type" .= ("integer" :: Text), "minimum" .= (1 :: Int), "default" .= (60 :: Int)]
|
|
, "quotaPerDay" .= object ["type" .= ("integer" :: Text), "minimum" .= (1 :: Int), "default" .= (10000 :: Int)]
|
|
]
|
|
]
|
|
|
|
apiKeySchema :: Value
|
|
apiKeySchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "id" .= uuidProp
|
|
, "apiConsumerId" .= uuidProp
|
|
, "keyPrefix" .= strProp
|
|
, "scopes" .= strProp
|
|
, "tokenType" .= strProp
|
|
, "expiresAt" .= dtProp
|
|
, "revokedAt" .= dtProp
|
|
, "lastUsedAt" .= dtProp
|
|
, "createdAt" .= dtProp
|
|
]
|
|
]
|
|
|
|
createApiKeyRequestSchema :: Value
|
|
createApiKeyRequestSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "scopes" .= strProp
|
|
]
|
|
]
|
|
|
|
apiKeyCreatedResponseSchema :: Value
|
|
apiKeyCreatedResponseSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "apiKey" .= object ["$ref" .= ("#/components/schemas/ApiKey" :: Text)]
|
|
, "fullKey" .= object
|
|
[ "type" .= ("string" :: Text)
|
|
, "description" .= ("Static API key secret. Returned only in this creation response; it is stored hashed and cannot be recovered later." :: Text)
|
|
]
|
|
, "displayOnce" .= boolProp
|
|
]
|
|
]
|
|
|
|
interactionEventSchema :: Value
|
|
interactionEventSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "id" .= uuidProp
|
|
, "widgetId" .= uuidProp
|
|
, "eventType" .= object ["$ref" .= ("#/components/schemas/EventType" :: Text)]
|
|
, "actorId" .= uuidProp
|
|
, "actorType" .= strProp
|
|
, "viewContextRef" .= strProp
|
|
, "metadata" .= object ["type" .= ("object" :: Text)]
|
|
, "occurredAt" .= dtProp
|
|
]
|
|
]
|
|
|
|
createInteractionEventRequestSchema :: Value
|
|
createInteractionEventRequestSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "required" .= (["widgetId", "eventType"] :: [Text])
|
|
, "properties" .= object
|
|
[ "widgetId" .= uuidProp
|
|
, "eventType" .= object ["$ref" .= ("#/components/schemas/EventType" :: Text)]
|
|
, "viewContext" .= strProp
|
|
, "metadata" .= objectProp
|
|
]
|
|
]
|
|
|
|
annotationSchema :: Value
|
|
annotationSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "id" .= uuidProp
|
|
, "widgetId" .= uuidProp
|
|
, "parentId" .= uuidProp
|
|
, "body" .= strProp
|
|
, "category" .= object ["$ref" .= ("#/components/schemas/AnnotationCategory" :: Text)]
|
|
, "severity" .= strProp
|
|
, "threadId" .= uuidProp
|
|
, "actorId" .= uuidProp
|
|
, "actorType" .= strProp
|
|
, "createdAt" .= dtProp
|
|
]
|
|
]
|
|
|
|
createAnnotationRequestSchema :: Value
|
|
createAnnotationRequestSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "required" .= (["widgetId", "category", "body"] :: [Text])
|
|
, "properties" .= object
|
|
[ "widgetId" .= uuidProp
|
|
, "category" .= object ["$ref" .= ("#/components/schemas/AnnotationCategory" :: Text)]
|
|
, "body" .= strProp
|
|
]
|
|
]
|
|
|
|
rcSchema :: Value
|
|
rcSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "id" .= uuidProp
|
|
, "title" .= strProp
|
|
, "description" .= strProp
|
|
, "sourceWidgetId" .= uuidProp
|
|
, "category" .= strProp
|
|
, "status" .= strProp
|
|
, "createdAt" .= dtProp
|
|
]
|
|
]
|
|
|
|
drSchema :: Value
|
|
drSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "id" .= uuidProp
|
|
, "title" .= strProp
|
|
, "rationale" .= strProp
|
|
, "outcome" .= strProp
|
|
, "requirementId" .= uuidProp
|
|
, "candidateId" .= uuidProp
|
|
, "decidedAt" .= dtProp
|
|
, "notes" .= strProp
|
|
, "createdAt" .= dtProp
|
|
]
|
|
]
|
|
|
|
depSchema :: Value
|
|
depSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "id" .= uuidProp
|
|
, "decisionId" .= uuidProp
|
|
, "versionRef" .= strProp
|
|
, "deployedAt" .= dtProp
|
|
, "notes" .= strProp
|
|
, "createdAt" .= dtProp
|
|
]
|
|
]
|
|
|
|
sigSchema :: Value
|
|
sigSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "id" .= uuidProp
|
|
, "widgetId" .= uuidProp
|
|
, "deploymentId" .= uuidProp
|
|
, "signalType" .= strProp
|
|
, "value" .= object ["type" .= ("number" :: Text)]
|
|
, "observedAt" .= dtProp
|
|
]
|
|
]
|
|
|
|
outcomeCorrelationSchema :: Value
|
|
outcomeCorrelationSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "id" .= uuidProp
|
|
, "hubId" .= uuidProp
|
|
, "annotationCategory" .= strProp
|
|
, "correlationType" .= strProp
|
|
, "correlationScore" .= object ["type" .= ("number" :: Text)]
|
|
, "sampleCount" .= object ["type" .= ("integer" :: Text)]
|
|
, "computedAt" .= dtProp
|
|
]
|
|
]
|
|
|
|
patternPerformanceSchema :: Value
|
|
patternPerformanceSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "id" .= uuidProp
|
|
, "widgetPatternId" .= uuidProp
|
|
, "hubId" .= uuidProp
|
|
, "adoptionCount" .= object ["type" .= ("integer" :: Text)]
|
|
, "positiveOutcomeCount" .= object ["type" .= ("integer" :: Text)]
|
|
, "totalOutcomeCount" .= object ["type" .= ("integer" :: Text)]
|
|
, "positiveOutcomeRate" .= object ["type" .= ("number" :: Text)]
|
|
, "meanOutcomeValue" .= object ["type" .= ("number" :: Text)]
|
|
, "outcomeRank" .= object ["type" .= ("integer" :: Text)]
|
|
, "calibratedAt" .= dtProp
|
|
]
|
|
]
|
|
|
|
institutionalKnowledgeSchema :: Value
|
|
institutionalKnowledgeSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "id" .= uuidProp
|
|
, "hubId" .= uuidProp
|
|
, "decisionRecordId" .= uuidProp
|
|
, "summary" .= strProp
|
|
, "tags" .= object ["type" .= ("array" :: Text)]
|
|
, "createdAt" .= dtProp
|
|
, "updatedAt" .= dtProp
|
|
]
|
|
]
|
|
|
|
hubRegistryEntrySchema :: Value
|
|
hubRegistryEntrySchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "id" .= uuidProp
|
|
, "name" .= strProp
|
|
, "slug" .= strProp
|
|
, "domain" .= strProp
|
|
, "hubKind" .= strProp
|
|
, "hubFamily" .= strProp
|
|
, "vsmFunction" .= strProp
|
|
, "vsmSystem" .= strProp
|
|
, "gaafStatus" .= object ["type" .= ("string" :: Text), "enum" .= ["compliant" :: Text, "draft_only", "no_manifest"]]
|
|
, "manifest" .= object ["$ref" .= ("#/components/schemas/HubManifestSummary" :: Text)]
|
|
, "healthScore" .= intProp
|
|
, "healthAt" .= dtProp
|
|
]
|
|
]
|
|
|
|
hubManifestSummarySchema :: Value
|
|
hubManifestSummarySchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "id" .= uuidProp
|
|
, "manifestVersion" .= strProp
|
|
, "status" .= strProp
|
|
, "declaredWidgetTypes" .= arrayOfRef "WidgetType"
|
|
, "declaredEventTypes" .= arrayOfRef "EventType"
|
|
, "declaredAnnotationCategories" .= arrayOfRef "AnnotationCategory"
|
|
, "declaredPolicyScopes" .= arrayOfRef "PolicyScope"
|
|
, "activatedAt" .= dtProp
|
|
]
|
|
]
|
|
|
|
widgetPatternSchema :: Value
|
|
widgetPatternSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "id" .= uuidProp
|
|
, "hubId" .= uuidProp
|
|
, "name" .= strProp
|
|
, "description" .= strProp
|
|
, "widgetType" .= object ["$ref" .= ("#/components/schemas/WidgetType" :: Text)]
|
|
, "isCrossHub" .= boolProp
|
|
, "isPublished" .= boolProp
|
|
, "createdAt" .= dtProp
|
|
, "updatedAt" .= dtProp
|
|
]
|
|
]
|
|
|
|
widgetPatternDetailSchema :: Value
|
|
widgetPatternDetailSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "pattern" .= object ["$ref" .= ("#/components/schemas/WidgetPattern" :: Text)]
|
|
, "versions" .= object
|
|
[ "type" .= ("array" :: Text)
|
|
, "items" .= object ["$ref" .= ("#/components/schemas/WidgetPatternVersion" :: Text)]
|
|
]
|
|
, "adopterCount" .= intProp
|
|
]
|
|
]
|
|
|
|
widgetPatternVersionSchema :: Value
|
|
widgetPatternVersionSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "id" .= uuidProp
|
|
, "versionNumber" .= intProp
|
|
, "definition" .= objectProp
|
|
, "changelog" .= strProp
|
|
, "publishedAt" .= dtProp
|
|
]
|
|
]
|
|
|
|
patternAdoptionResponseSchema :: Value
|
|
patternAdoptionResponseSchema = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "properties" .= object
|
|
[ "adopted" .= boolProp
|
|
, "adoptionId" .= uuidProp
|
|
]
|
|
]
|
|
|
|
uuidProp :: Value
|
|
uuidProp = object ["type" .= ("string" :: Text), "format" .= ("uuid" :: Text)]
|
|
|
|
strProp :: Value
|
|
strProp = object ["type" .= ("string" :: Text)]
|
|
|
|
intProp :: Value
|
|
intProp = object ["type" .= ("integer" :: Text)]
|
|
|
|
boolProp :: Value
|
|
boolProp = object ["type" .= ("boolean" :: Text)]
|
|
|
|
objectProp :: Value
|
|
objectProp = object
|
|
[ "type" .= ("object" :: Text)
|
|
, "additionalProperties" .= True
|
|
]
|
|
|
|
arrayOfRef :: Text -> Value
|
|
arrayOfRef schemaName = object
|
|
[ "type" .= ("array" :: Text)
|
|
, "items" .= object ["$ref" .= ("#/components/schemas/" <> schemaName)]
|
|
]
|
|
|
|
dtProp :: Value
|
|
dtProp = object ["type" .= ("string" :: Text), "format" .= ("date-time" :: Text)]
|
|
|
|
-- | Embedded Swagger UI HTML using CDN assets (no build step required)
|
|
swaggerUiHtml :: LBS.ByteString
|
|
swaggerUiHtml = LBS.fromStrict $ TE.encodeUtf8 swaggerUiHtmlText
|
|
|
|
swaggerUiHtmlText :: Text
|
|
swaggerUiHtmlText =
|
|
"<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" />" <>
|
|
"<title>IHF API v2 \x2014 Documentation</title>" <>
|
|
"<link rel=\"stylesheet\" href=\"https://unpkg.com/swagger-ui-dist@5/swagger-ui.css\" />" <>
|
|
"</head><body>" <>
|
|
"<div id=\"swagger-ui\"></div>" <>
|
|
"<script src=\"https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js\"></script>" <>
|
|
"<script>window.onload=function(){SwaggerUIBundle({" <>
|
|
"url:\"/api/v2/openapi.json\"," <>
|
|
"dom_id:\"#swagger-ui\"," <>
|
|
"presets:[SwaggerUIBundle.presets.apis,SwaggerUIBundle.SwaggerUIStandalonePreset]," <>
|
|
"layout:\"StandaloneLayout\"" <>
|
|
"});}</script>" <>
|
|
"</body></html>"
|