# 1Forge Spectral Ruleset # Enforces conventions observed across the 1Forge Forex Data API. The 1Forge surface # is tiny (5 operations, single-host, query-key auth), so the ruleset focuses on # documentation quality, naming consistency, and the patterns used by the live API. extends: - spectral:oas rules: # --- INFO / METADATA --------------------------------------------------------- oneforge-info-title-prefix: description: API info.title must begin with "1Forge". severity: warn given: $.info then: field: title function: pattern functionOptions: match: '^1Forge' oneforge-info-description-required: description: API info.description must be present and at least 80 characters. severity: warn given: $.info then: field: description function: length functionOptions: min: 80 oneforge-info-contact-required: description: info.contact.email must be present. severity: warn given: $.info.contact then: field: email function: truthy # --- OPENAPI VERSION -------------------------------------------------------- oneforge-openapi-version: description: Use OpenAPI 3.0.x. severity: error given: $.openapi then: function: pattern functionOptions: match: '^3\.0\.' # --- SERVERS ---------------------------------------------------------------- oneforge-servers-required: description: At least one server must be defined. severity: error given: $.servers then: function: length functionOptions: min: 1 oneforge-servers-https: description: All server URLs must use HTTPS. severity: error given: $.servers[*].url then: function: pattern functionOptions: match: '^https://' oneforge-servers-canonical-host: description: REST server URL must point at api.1forge.com. severity: warn given: $.servers[*].url then: function: pattern functionOptions: match: '^https://api\.1forge\.com' # --- PATHS / NAMING --------------------------------------------------------- oneforge-paths-snake-case: description: Path segments use snake_case (matches /market_status, /quotes, /convert, /symbols, /quota). severity: warn given: $.paths.*~ then: function: pattern functionOptions: match: '^(/[a-z][a-z0-9_]*)+$' oneforge-paths-no-trailing-slash: description: Paths must not end with a trailing slash. severity: error given: $.paths.*~ then: function: pattern functionOptions: notMatch: '.+/$' oneforge-paths-no-query-string: description: Path keys must not include a query string. severity: error given: $.paths.*~ then: function: pattern functionOptions: notMatch: '\?' # --- OPERATIONS ------------------------------------------------------------- oneforge-operation-summary-required: description: Operation summary must be present. severity: error given: $.paths[*][get,post,put,patch,delete] then: field: summary function: truthy oneforge-operation-summary-prefix: description: Operation summaries must begin with "1Forge". severity: warn given: $.paths[*][get,post,put,patch,delete].summary then: function: pattern functionOptions: match: '^1Forge\s' oneforge-operation-description-required: description: Operation description must be present and at least 40 characters. severity: warn given: $.paths[*][get,post,put,patch,delete] then: field: description function: length functionOptions: min: 40 oneforge-operation-id-camel-case: description: operationId must be camelCase. severity: error given: $.paths[*][get,post,put,patch,delete] then: field: operationId function: pattern functionOptions: match: '^[a-z][a-zA-Z0-9]+$' oneforge-operation-id-verb-prefix: description: operationId should begin with a verb (get, list, convert, check). severity: info given: $.paths[*][get,post,put,patch,delete] then: field: operationId function: pattern functionOptions: match: '^(get|list|convert|check)' oneforge-operation-tags-required: description: Operations must declare at least one tag. severity: warn given: $.paths[*][get,post,put,patch,delete] then: field: tags function: length functionOptions: min: 1 oneforge-operation-microcks-extension: description: Operations should declare x-microcks-operation for mock-server compatibility. severity: info given: $.paths[*][get,post,put,patch,delete] then: field: x-microcks-operation function: truthy # --- TAGS ------------------------------------------------------------------- oneforge-tag-description-required: description: Each global tag must declare a description. severity: warn given: $.tags[*] then: field: description function: truthy oneforge-tag-title-case: description: Tag names should use Title Case (e.g. "Market Status", "Quotes"). severity: info given: $.tags[*].name then: function: pattern functionOptions: match: '^[A-Z][a-zA-Z0-9 ]*$' # --- PARAMETERS ------------------------------------------------------------- oneforge-parameter-description-required: description: Every parameter must have a description. severity: warn given: $.paths[*][*].parameters[*] then: field: description function: truthy oneforge-parameter-snake-case: description: Query parameter names use snake_case (matches api_key, pairs, from, to, quantity). severity: warn given: $.paths[*][*].parameters[?(@.in=='query')] then: field: name function: pattern functionOptions: match: '^[a-z][a-z0-9_]*$' oneforge-parameter-api-key-required: description: Every operation must accept the api_key query parameter (the only auth method). severity: warn given: $.paths[*][get,post,put,patch,delete] then: field: parameters function: schema functionOptions: schema: type: array contains: type: object properties: name: const: api_key in: const: query required: const: true required: [name, in, required] # --- RESPONSES -------------------------------------------------------------- oneforge-response-200-required: description: Operations must define a 200 response. severity: error given: $.paths[*][get,post,put,patch,delete].responses then: field: '200' function: truthy oneforge-response-401-defined: description: Operations should document the 401 (invalid api_key) response. severity: warn given: $.paths[*][get,post,put,patch,delete].responses then: field: '401' function: truthy oneforge-response-content-json: description: 200 responses must declare application/json content. severity: warn given: $.paths[*][get,post,put,patch,delete].responses['200'].content then: field: application/json function: truthy oneforge-response-description-required: description: Each response must include a description. severity: warn given: $.paths[*][*].responses[*] then: field: description function: truthy # --- SCHEMAS ---------------------------------------------------------------- oneforge-schema-type-required: description: Top-level component schemas must declare a type. severity: error given: $.components.schemas[*] then: field: type function: truthy oneforge-schema-title-required: description: Top-level component schemas must declare a title. severity: warn given: $.components.schemas[*] then: field: title function: truthy oneforge-schema-description-required: description: Top-level component schemas must declare a description. severity: warn given: $.components.schemas[*] then: field: description function: truthy oneforge-schema-property-snake-case: description: Schema property names should use snake_case (or the documented single-letter quote keys s/p/b/a/t). severity: info given: $.components.schemas[*].properties.*~ then: function: pattern functionOptions: match: '^([a-z]|[a-z][a-z0-9_]*)$' # --- SECURITY --------------------------------------------------------------- oneforge-security-defined: description: Global security must be declared. severity: error given: $.security then: function: truthy oneforge-security-scheme-apikey: description: Security scheme must be an apiKey scheme bound to the api_key query parameter. severity: error given: $.components.securitySchemes[*] then: function: schema functionOptions: schema: type: object properties: type: const: apiKey in: const: query name: const: api_key required: [type, in, name] # --- HTTP METHOD CONVENTIONS ------------------------------------------------ oneforge-only-get-methods: description: 1Forge only exposes GET operations across its REST surface. severity: warn given: $.paths[*] then: function: schema functionOptions: schema: type: object not: anyOf: - required: [post] - required: [put] - required: [patch] - required: [delete]