MarginEdge · API Governance Rules

MarginEdge API Rules

Spectral linting rules defining API design standards and conventions for MarginEdge.

43 Rules error 10 warn 22 info 11
View Rules File View on GitHub

Rule Categories

get global info no oas3 operation pagination parameter paths query response schema security server servers tag

Rules

warn
info-title-marginedge
Info title should identify the MarginEdge API.
$.info
warn
info-description-required
Info description is required and should be meaningful.
$.info
error
info-version-required
Info version is required.
$.info
info
info-contact-required
Provide a contact for the API.
$.info
warn
oas3-version-pinned
This catalog standardizes on OpenAPI 3.0.x.
$.openapi
error
servers-defined
At least one server must be defined.
$
error
servers-https-only
Servers must use HTTPS.
$.servers[*].url
info
server-is-marginedge-public
The public API is served under api.marginedge.com/public.
$.servers[*].url
warn
paths-no-trailing-slash
Paths must not end with a trailing slash.
$.paths[*]~
warn
paths-camelcase-segments
Path segments use camelCase (e.g. restaurantUnits, vendorItems); avoid snake_case or kebab-case.
$.paths[*]~
error
paths-no-query-string
Path keys must not contain query strings.
$.paths[*]~
error
operation-read-only-get
The MarginEdge Public API is read-only; only GET operations are permitted.
$.paths[*]
warn
operation-summary-required
Every operation needs a summary.
$.paths[*][get]
warn
operation-summary-marginedge-prefixed
Operation summaries are prefixed with "MarginEdge".
$.paths[*][get].summary
info
operation-description-required
Every operation needs a description.
$.paths[*][get]
error
operation-id-required
Every operation needs an operationId.
$.paths[*][get]
warn
operation-id-camelcase
operationId should be camelCase (e.g. getOrders, getVendorItems).
$.paths[*][get].operationId
info
operation-id-verb-prefix
Read operations should start with a get/list verb.
$.paths[*][get].operationId
warn
operation-tags-required
Every operation must be tagged.
$.paths[*][get]
info
global-tags-defined
Top-level tags array should be defined with descriptions.
$
info
tag-has-description
Each global tag should have a description.
$.tags[*]
warn
tag-title-case
Tags use Title Case (e.g. "Restaurant Units", "Vendors").
$.tags[*].name
info
parameter-description-required
Parameters should be described.
$.paths[*][get].parameters[*]
warn
parameter-camelcase
Query and path parameters use camelCase (restaurantUnitId, vendorId, nextPage).
$.paths[*][get].parameters[?(@.in=='query' || @.in=='path')].name
error
parameter-no-apikey-in-query
API keys must travel in the x-api-key header, never in the query string.
$.paths[*][get].parameters[?(@.in=='query')].name
info
pagination-cursor-name
Cursor pagination standardizes on the "nextPage" parameter name.
$.paths[*][get].parameters[?(@.in=='query')].name
error
get-no-request-body
GET operations must not declare a request body.
$.paths[*][get]
error
response-200-defined
Each operation must define a 200 success response.
$.paths[*][get].responses
warn
response-403-defined
Operations should document a 403 (unauthorized / unauthorized restaurant) response.
$.paths[*][get].responses
warn
response-json-content
Success responses should return application/json.
$.paths[*][get].responses.200.content
warn
schema-property-camelcase
Schema properties use camelCase (centralProductId, vendorItemCode, accountingCode).
$.components.schemas[*]..properties[*]~
warn
schema-property-typed
Schema properties must declare a type.
$.components.schemas[*]..properties[*]
info
pagination-nextpage-field
List response schemas should expose a "nextPage" cursor field.
$.components.schemas[?(@property.match(/ResponseModel$/))].properties
error
global-security-defined
A global security requirement must be declared.
$
warn
security-scheme-apikey-header
The API key scheme must be apiKey-in-header named x-api-key.
$.components.securitySchemes[*]
info
security-scheme-described
Security schemes should be described.
$.components.securitySchemes[*]
warn
query-params-casing
Query parameters should be camelCase (the dominant convention in this API).
$.paths[*][get,post,put,patch,delete].parameters[?(@.in=='query')]
warn
schema-names-casing
Component schema names should be PascalCase (the dominant convention in this API).
$.components.schemas
info
schema-properties-casing
Schema properties should be camelCase (the dominant convention in this API).
$.components.schemas[*].properties
warn
operation-documents-400
Operations should document a 400 response (documented on 100% of this API's operations).
$.paths[*][get,post,put,patch,delete].responses
warn
operation-documents-404
Operations should document a 404 response (documented on 100% of this API's operations).
$.paths[*][get,post,put,patch,delete].responses
warn
operation-documents-500
Operations should document a 500 response (documented on 100% of this API's operations).
$.paths[*][get,post,put,patch,delete].responses
warn
no-empty-descriptions
Descriptions must not be empty strings.
$..description

Spectral Ruleset

Raw ↑
# marginedge — Spectral ruleset (strengthened)
# Plain Spectral. Existing hand-authored rules preserved; measured rules added
# from this provider's own OpenAPI conventions by strengthen_ruleset.py,
# then self-validated against the spec.
#
# Provenance:
#   - servers-https-only: 100% of servers already https (error)
#   - servers-expected-domain: 1/1 servers on marginedge.com
#   - path-params-casing: camel @ 100% (n=4)
#   - query-params-casing: camel @ 100% (n=19)
#   - operationid-casing: camel @ 100% (n=10)
#   - schema-names-casing: pascal @ 100% (n=10)
#   - schema-properties-casing: camel @ 71% (n=34)
#   - security: global (root) — NOT emitting operation-security-required
#   - operation-documents-400: 100% adherence
#   - operation-documents-403: 100% adherence
#   - operation-documents-404: 100% adherence
#   - operation-documents-500: 100% adherence
#   - merge: kept 36 existing, added 7 measured, upgraded 0
#   - added: query-params-casing, schema-names-casing, schema-properties-casing, operation-documents-400, operation-documents-404, operation-documents-500, no-empty-descriptions
extends:
  - spectral:oas
rules:
  info-title-marginedge:
    description: Info title should identify the MarginEdge API.
    severity: warn
    given: $.info
    then:
      field: title
      function: pattern
      functionOptions:
        match: MarginEdge
  info-description-required:
    description: Info description is required and should be meaningful.
    severity: warn
    given: $.info
    then:
      field: description
      function: truthy
  info-version-required:
    description: Info version is required.
    severity: error
    given: $.info
    then:
      field: version
      function: truthy
  info-contact-required:
    description: Provide a contact for the API.
    severity: info
    given: $.info
    then:
      field: contact
      function: truthy
  oas3-version-pinned:
    description: This catalog standardizes on OpenAPI 3.0.x.
    severity: warn
    given: $.openapi
    then:
      function: pattern
      functionOptions:
        match: ^3\.0\.[0-9]+$
  servers-defined:
    description: At least one server must be defined.
    severity: error
    given: $
    then:
      field: servers
      function: truthy
  servers-https-only:
    description: Servers must use HTTPS.
    severity: error
    given: $.servers[*].url
    then:
      function: pattern
      functionOptions:
        match: ^https://
  server-is-marginedge-public:
    description: The public API is served under api.marginedge.com/public.
    severity: info
    given: $.servers[*].url
    then:
      function: pattern
      functionOptions:
        match: api\.marginedge\.com/public
  paths-no-trailing-slash:
    description: Paths must not end with a trailing slash.
    severity: warn
    given: $.paths[*]~
    then:
      function: pattern
      functionOptions:
        notMatch: .+/$
  paths-camelcase-segments:
    description: Path segments use camelCase (e.g. restaurantUnits, vendorItems); avoid snake_case or
      kebab-case.
    severity: warn
    given: $.paths[*]~
    then:
      function: pattern
      functionOptions:
        notMatch: '[_-]'
  paths-no-query-string:
    description: Path keys must not contain query strings.
    severity: error
    given: $.paths[*]~
    then:
      function: pattern
      functionOptions:
        notMatch: \?
  operation-read-only-get:
    description: The MarginEdge Public API is read-only; only GET operations are permitted.
    severity: error
    given: $.paths[*]
    then:
      field: '@key'
      function: pattern
      functionOptions:
        match: ^(get|parameters|summary|description)$
  operation-summary-required:
    description: Every operation needs a summary.
    severity: warn
    given: $.paths[*][get]
    then:
      field: summary
      function: truthy
  operation-summary-marginedge-prefixed:
    description: Operation summaries are prefixed with "MarginEdge".
    severity: warn
    given: $.paths[*][get].summary
    then:
      function: pattern
      functionOptions:
        match: '^MarginEdge '
  operation-description-required:
    description: Every operation needs a description.
    severity: info
    given: $.paths[*][get]
    then:
      field: description
      function: truthy
  operation-id-required:
    description: Every operation needs an operationId.
    severity: error
    given: $.paths[*][get]
    then:
      field: operationId
      function: truthy
  operation-id-camelcase:
    description: operationId should be camelCase (e.g. getOrders, getVendorItems).
    severity: warn
    given: $.paths[*][get].operationId
    then:
      function: pattern
      functionOptions:
        match: ^[a-z][a-zA-Z0-9]+$
  operation-id-verb-prefix:
    description: Read operations should start with a get/list verb.
    severity: info
    given: $.paths[*][get].operationId
    then:
      function: pattern
      functionOptions:
        match: ^(get|list)
  operation-tags-required:
    description: Every operation must be tagged.
    severity: warn
    given: $.paths[*][get]
    then:
      field: tags
      function: truthy
  global-tags-defined:
    description: Top-level tags array should be defined with descriptions.
    severity: info
    given: $
    then:
      field: tags
      function: truthy
  tag-has-description:
    description: Each global tag should have a description.
    severity: info
    given: $.tags[*]
    then:
      field: description
      function: truthy
  tag-title-case:
    description: Tags use Title Case (e.g. "Restaurant Units", "Vendors").
    severity: warn
    given: $.tags[*].name
    then:
      function: pattern
      functionOptions:
        match: ^[A-Z][A-Za-z]+( [A-Z][A-Za-z]+)*$
  parameter-description-required:
    description: Parameters should be described.
    severity: info
    given: $.paths[*][get].parameters[*]
    then:
      field: description
      function: truthy
  parameter-camelcase:
    description: Query and path parameters use camelCase (restaurantUnitId, vendorId, nextPage).
    severity: warn
    given: $.paths[*][get].parameters[?(@.in=='query' || @.in=='path')].name
    then:
      function: pattern
      functionOptions:
        match: ^[a-z][a-zA-Z0-9]*$
  parameter-no-apikey-in-query:
    description: API keys must travel in the x-api-key header, never in the query string.
    severity: error
    given: $.paths[*][get].parameters[?(@.in=='query')].name
    then:
      function: pattern
      functionOptions:
        notMatch: (?i)(api[-_]?key|apikey|token)
  pagination-cursor-name:
    description: Cursor pagination standardizes on the "nextPage" parameter name.
    severity: info
    given: $.paths[*][get].parameters[?(@.in=='query')].name
    then:
      function: pattern
      functionOptions:
        notMatch: ^(page|offset|cursor|pageToken)$
  get-no-request-body:
    description: GET operations must not declare a request body.
    severity: error
    given: $.paths[*][get]
    then:
      field: requestBody
      function: falsy
  response-200-defined:
    description: Each operation must define a 200 success response.
    severity: error
    given: $.paths[*][get].responses
    then:
      field: '200'
      function: truthy
  response-403-defined:
    description: Operations should document a 403 (unauthorized / unauthorized restaurant) response.
    severity: warn
    given: $.paths[*][get].responses
    then:
      field: '403'
      function: truthy
  response-json-content:
    description: Success responses should return application/json.
    severity: warn
    given: $.paths[*][get].responses.200.content
    then:
      field: application/json
      function: truthy
  schema-property-camelcase:
    description: Schema properties use camelCase (centralProductId, vendorItemCode, accountingCode).
    severity: warn
    given: $.components.schemas[*]..properties[*]~
    then:
      function: pattern
      functionOptions:
        match: ^[a-z][a-zA-Z0-9]*$
  schema-property-typed:
    description: Schema properties must declare a type.
    severity: warn
    given: $.components.schemas[*]..properties[*]
    then:
      field: type
      function: truthy
  pagination-nextpage-field:
    description: List response schemas should expose a "nextPage" cursor field.
    severity: info
    given: $.components.schemas[?(@property.match(/ResponseModel$/))].properties
    then:
      field: nextPage
      function: truthy
  global-security-defined:
    description: A global security requirement must be declared.
    severity: error
    given: $
    then:
      field: security
      function: truthy
  security-scheme-apikey-header:
    description: The API key scheme must be apiKey-in-header named x-api-key.
    severity: warn
    given: $.components.securitySchemes[*]
    then:
    - field: type
      function: pattern
      functionOptions:
        match: ^apiKey$
    - field: in
      function: pattern
      functionOptions:
        match: ^header$
  security-scheme-described:
    description: Security schemes should be described.
    severity: info
    given: $.components.securitySchemes[*]
    then:
      field: description
      function: truthy
  query-params-casing:
    description: Query parameters should be camelCase (the dominant convention in this API).
    severity: warn
    given: $.paths[*][get,post,put,patch,delete].parameters[?(@.in=='query')]
    then:
      field: name
      function: casing
      functionOptions:
        type: camel
  schema-names-casing:
    description: Component schema names should be PascalCase (the dominant convention in this API).
    severity: warn
    given: $.components.schemas
    then:
      field: '@key'
      function: casing
      functionOptions:
        type: pascal
  schema-properties-casing:
    description: Schema properties should be camelCase (the dominant convention in this API).
    severity: info
    given: $.components.schemas[*].properties
    then:
      field: '@key'
      function: casing
      functionOptions:
        type: camel
  operation-documents-400:
    description: Operations should document a 400 response (documented on 100% of this API's operations).
    severity: warn
    given: $.paths[*][get,post,put,patch,delete].responses
    then:
      field: '400'
      function: truthy
  operation-documents-404:
    description: Operations should document a 404 response (documented on 100% of this API's operations).
    severity: warn
    given: $.paths[*][get,post,put,patch,delete].responses
    then:
      field: '404'
      function: truthy
  operation-documents-500:
    description: Operations should document a 500 response (documented on 100% of this API's operations).
    severity: warn
    given: $.paths[*][get,post,put,patch,delete].responses
    then:
      field: '500'
      function: truthy
  no-empty-descriptions:
    description: Descriptions must not be empty strings.
    severity: warn
    given: $..description
    then:
      function: truthy