rules: # INFO / METADATA info-title-format: description: API title must follow the Workday Recruiting naming pattern severity: warn given: $.info.title then: function: pattern functionOptions: match: "^Workday Recruiting .+" info-description-required: description: API info must have a description severity: error given: $.info then: field: description function: truthy info-description-min-length: description: API description should be at least 50 characters severity: warn given: $.info.description then: function: length functionOptions: min: 50 info-version-required: description: API info must specify a version severity: error given: $.info then: field: version function: truthy info-version-format: description: Version should follow the v{n} or v{n}.{n} pattern (e.g. v1, v41.2) severity: warn given: $.info.version then: function: pattern functionOptions: match: "^v[0-9]+(\\.[0-9]+)?$" info-contact-required: description: API info must include contact information severity: warn given: $.info then: field: contact function: truthy info-terms-of-service: description: API info should reference Workday terms of service severity: info given: $.info then: field: termsOfService function: truthy external-docs-required: description: APIs should provide external documentation links severity: info given: $ then: field: externalDocs function: truthy # OPENAPI VERSION openapi-version: description: APIs must use OpenAPI 3.1.x severity: error given: $.openapi then: function: pattern functionOptions: match: "^3\\.1\\." # SERVERS servers-defined: description: At least one server must be defined severity: error given: $ then: field: servers function: truthy servers-https: description: All server URLs must use HTTPS severity: error given: $.servers[*].url then: function: pattern functionOptions: match: "^https://" servers-description-required: description: All servers should include a description severity: warn given: $.servers[*] then: field: description function: truthy servers-versioned-path: description: Server URLs should include a version segment (e.g. /v41.2) severity: warn given: $.servers[*].url then: function: pattern functionOptions: match: "/v[0-9]+(\\.[0-9]+)?(/|$)" servers-recruiting-path: description: Server URLs should include the /recruiting/ API segment severity: info given: $.servers[*].url then: function: pattern functionOptions: match: "/recruiting/" # PATHS — NAMING CONVENTIONS paths-camel-case: description: Path segments must use camelCase resource names (Workday convention) severity: warn given: $.paths[*]~ then: function: pattern functionOptions: match: "^(/[a-z][a-zA-Z0-9]*(/\\{[a-zA-Z][a-zA-Z0-9]*\\})?)+$" paths-no-trailing-slash: description: Paths must not have trailing slashes severity: error given: $.paths[*]~ then: function: pattern functionOptions: notMatch: "/$" paths-no-query-strings: description: Paths must not contain query strings severity: error given: $.paths[*]~ then: function: pattern functionOptions: notMatch: "\\?" paths-plural-resources: description: Top-level collection paths should use plural resource nouns severity: info given: $.paths[*]~ then: function: pattern functionOptions: match: "^/[a-z][a-zA-Z0-9]*(s|es|ies|Statuses|Sites|Categories|Brands|Regions|Packages|Postings|Settings|Calendars)(/.*)?$" # OPERATIONS operation-summary-required: description: All operations must have a summary severity: error given: $.paths[*][get,post,put,patch,delete] then: field: summary function: truthy operation-summary-prefix: description: Operation summaries should start with "Workday Recruiting" severity: warn given: $.paths[*][get,post,put,patch,delete].summary then: function: pattern functionOptions: match: "^Workday Recruiting " operation-description-required: description: All operations must have a description severity: warn given: $.paths[*][get,post,put,patch,delete] then: field: description function: truthy operation-id-required: description: All operations must have an operationId severity: error given: $.paths[*][get,post,put,patch,delete] then: field: operationId function: truthy operation-id-camel-case: description: operationId must use camelCase severity: warn given: $.paths[*][get,post,put,patch,delete].operationId then: function: pattern functionOptions: match: "^[a-z][a-zA-Z0-9]+$" operation-id-verb-prefix: description: operationId should start with a recognized recruiting verb severity: warn given: $.paths[*][get,post,put,patch,delete].operationId then: function: pattern functionOptions: match: "^(list|get|create|update|edit|delete|close|manage|add|assess|refer|move|offer|post|unpost|submit|initiate|import|schedule)[A-Z]" operation-tags-required: description: All operations must have at least one tag severity: error given: $.paths[*][get,post,put,patch,delete] then: field: tags function: truthy # TAGS global-tags-defined: description: Top-level tags array should be defined for documentation grouping severity: warn given: $ then: field: tags function: truthy tags-title-case: description: Global tag names should use Title Case (multi-word allowed) severity: warn given: $.tags[*].name then: function: pattern functionOptions: match: "^[A-Z][A-Za-z]*((-|\\s)[A-Z][A-Za-z]*)*$" tags-description-required: description: All global tags must have descriptions severity: warn given: $.tags[*] then: field: description function: truthy # PARAMETERS parameter-description-required: description: All parameters must have descriptions severity: error given: "#Parameter" then: field: description function: truthy parameter-camel-case: description: Parameter names should use camelCase (Workday convention) severity: warn given: "#Parameter" then: field: name function: pattern functionOptions: match: "^[a-z][a-zA-Z0-9]*$" parameter-schema-required: description: All parameters must define a schema severity: error given: "#Parameter" then: field: schema function: truthy parameter-pagination-limit: description: Pagination should use a "limit" parameter, not page-size or perPage severity: warn given: $.paths[*][get,post,put,patch,delete].parameters[?(@.in == 'query')].name then: function: pattern functionOptions: notMatch: "^(pageSize|perPage|page_size|per_page|size)$" parameter-pagination-offset: description: Pagination should use an "offset" parameter, not page or pageNumber severity: warn given: $.paths[*][get,post,put,patch,delete].parameters[?(@.in == 'query')].name then: function: pattern functionOptions: notMatch: "^(page|pageNumber|page_number|pageNo)$" parameter-no-api-key-in-query: description: API keys must not be passed as query parameters severity: error given: $.paths[*][get,post,put,patch,delete].parameters[?(@.in == 'query')].name then: function: pattern functionOptions: notMatch: "(?i)(api[_-]?key|apikey|access[_-]?token|token)" resource-id-path-param-naming: description: Resource identifier path parameters should be named "id" (Workday WID convention) severity: info given: $.paths[*][get,post,put,patch,delete].parameters[?(@.in == 'path' && @.name =~ /id$/i)].name then: function: enumeration functionOptions: values: - id # REQUEST BODIES request-body-json-content: description: Request bodies must support application/json content type severity: error given: $.paths[*][post,put,patch].requestBody.content then: field: application/json function: truthy request-body-schema-required: description: Request body content must reference a schema severity: warn given: $.paths[*][post,put,patch].requestBody.content[*] then: field: schema function: truthy # RESPONSES response-success-required: description: All operations must define at least one 2xx response severity: error given: $.paths[*][get,post,put,patch,delete].responses then: function: schema functionOptions: schema: type: object patternProperties: "^2[0-9][0-9]$": {} minProperties: 1 response-401-required: description: Operations should define a 401 Unauthorized response severity: warn given: $.paths[*][get,post,put,patch,delete].responses then: field: '401' function: truthy response-404-on-resource-get: description: GET operations on a single resource should define a 404 Not Found response severity: warn given: $.paths[?(@property.match(/\\{[a-zA-Z]+\\}$/))].get.responses then: field: '404' function: truthy response-400-on-mutations: description: POST/PUT/PATCH operations should define a 400 Bad Request response severity: warn given: $.paths[*][post,put,patch].responses then: field: '400' function: truthy response-description-required: description: All responses must have a description severity: error given: $.paths[*][get,post,put,patch,delete].responses[*] then: field: description function: truthy response-json-content: description: Success responses must use application/json content type severity: warn given: $.paths[*][get,post,put,patch,delete].responses['200','201','202'].content then: field: application/json function: truthy response-error-schema-fields: description: Reusable error responses should reference a schema with message/error fields severity: warn given: $.components.responses[*].content.application/json then: field: schema function: truthy # SCHEMAS — PROPERTY NAMING schema-property-camel-case: description: Schema property names must use camelCase (Workday convention) severity: warn given: $.components.schemas[*].properties[*]~ then: function: pattern functionOptions: match: "^[a-z][a-zA-Z0-9]*$" schema-type-defined: description: Top-level schemas must define a type severity: warn given: $.components.schemas[*] then: field: type function: truthy schema-description-required: description: Top-level schemas should include a description severity: warn given: $.components.schemas[*] then: field: description function: truthy schema-id-property-string: description: Resource id properties must be strings (Workday WID convention) severity: warn given: $.components.schemas[*].properties.id then: field: type function: enumeration functionOptions: values: - string schema-timestamps-date-time: description: createdOn, updatedOn, submittedOn, postedOn, scheduledOn, completedOn properties should use date-time format severity: warn given: $.components.schemas[*].properties[?(@property.match(/^(createdOn|updatedOn|submittedOn|postedOn|scheduledOn|completedOn|approvedOn|processedOn|startedAt|completedAt)$/))] then: field: format function: enumeration functionOptions: values: - date-time schema-recruiting-date-format: description: targetHireDate, targetEndDate, postingStartDate, postingEndDate, interviewDate, fromDate, toDate properties should use date format severity: warn given: $.components.schemas[*].properties[?(@property.match(/^(targetHireDate|targetEndDate|postingStartDate|postingEndDate|interviewDate|fromDate|toDate|startDate|endDate|effectiveDate)$/))] then: field: format function: enumeration functionOptions: values: - date collection-response-data-array: description: Collection (list) responses must include a data array property severity: warn given: $.paths[*].get.responses['200'].content.application/json.schema.properties then: field: data function: truthy collection-response-total: description: Collection (list) responses should include a total property indicating full result count severity: warn given: $.paths[*].get.responses['200'].content.application/json.schema.properties then: field: total function: truthy reference-schema-shape: description: Reference schema must have id and descriptor properties (Workday Reference convention) severity: warn given: $.components.schemas.Reference.properties then: field: descriptor function: truthy # SECURITY global-security-defined: description: Global security must be declared severity: error given: $ then: field: security function: truthy security-schemes-defined: description: Security schemes must be defined under components severity: error given: $ then: field: components.securitySchemes function: truthy security-oauth2-required: description: An oauth2 security scheme is required for Workday Recruiting APIs severity: error given: $.components.securitySchemes then: field: oauth2 function: truthy security-oauth2-type: description: The oauth2 security scheme must declare type oauth2 severity: error given: $.components.securitySchemes.oauth2 then: field: type function: enumeration functionOptions: values: - oauth2 security-oauth2-flows: description: The oauth2 security scheme must define flows severity: error given: $.components.securitySchemes.oauth2 then: field: flows function: truthy security-scheme-description: description: Security schemes must include a description severity: warn given: $.components.securitySchemes[*] then: field: description function: truthy # HTTP METHOD CONVENTIONS get-no-request-body: description: GET operations must not have a request body severity: error given: $.paths[*].get then: field: requestBody function: falsy delete-no-request-body: description: DELETE operations should not have a request body severity: warn given: $.paths[*].delete then: field: requestBody function: falsy post-has-request-body: description: POST operations should have a request body severity: warn given: $.paths[*].post then: field: requestBody function: truthy patch-has-request-body: description: PATCH operations must have a request body severity: error given: $.paths[*].patch then: field: requestBody function: truthy put-has-request-body: description: PUT operations must have a request body severity: error given: $.paths[*].put then: field: requestBody function: truthy # GENERAL QUALITY no-empty-descriptions: description: Descriptions must not be empty strings severity: error given: $..description then: function: pattern functionOptions: match: ".+" examples-encouraged: description: Response and request examples improve developer experience severity: info given: $.paths[*][get,post,put,patch,delete].responses['200','201'].content.application/json then: field: examples function: truthy deprecation-documented: description: Deprecated operations should explain the migration path in their description severity: warn given: $.paths[*][?(@.deprecated == true)] then: field: description function: truthy