Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Augmented API Design Reviewer

The Augmented API Design Reviewer

API Design Reviews can be a total nightmare when it comes to check API Design Guidelines conformance. Hopefully, this can be automatized using the OpenAPI Specification and Spectral and you'll be able to focus on other more interesting tasks. But that will only work if you know how to build and use Spectral rulesets.

More Decks by Arnaud Lauret API Handyman

Other Decks in Technology

Transcript

  1. The Augmented API Design Reviewer Improving API Design Reviews PARTIAL

    AUTOMATION OPENAPI SPECIFICATION SPECTRAL LINTER
  2. API Design Review Problem API NAME API DESCRIPTION BASEPATH FORMAT

    VERSION FORMAT PATH FORMAT PATH CASE COLLECTION PLURAL NAME PARAMETER NAME SUFFIX PREFIX PARAMETER NAME CASE AUTHORIZED AUTHORIZED PARAMETER TYPES HTTP METHODS MANDATORY HTTP STATUS CODES AUTHORIZED HTTP STATUS CODES AUTHORIZE RESPONSE TYPE SCHEMA NAME SUFFIX PREFIX SCHEMA NAME CASE SCHEMA DEPTH REQUIRED PROPERTIES AUTHORIZED MEDIA TYPES DATE VS DATETIME FORMATS SECURITY DEFINITIONS SCOPES … MANY GUIDELINES CONFORMANCE CHECKS
  3. Machine Readable API Description OpenAPI Specification openapi: 3.0.3 paths: /users/{userId}:

    get: summary: Read a user responses: 200: description: The user content: application/json: schema: $ref: #/components/schemas/User
  4. Machine Readable API Description OpenAPI Specification (JSON Schema) components: schemas:

    User: properties: id: type: integer first_name: type: string last_name: type: string address: $ref: #/components/schemas/Address required: [id, first_name, last_name]
  5. API Description Linter Spectral A flexible JSON/YAML linter, with out

    of the box support for OpenAPI v2/v3 and AsyncAPI v2.
  6. API Description Linter Running Spectral CLI > spectral lint openapi.yaml

    1:1 warning oas3-api-servers OpenAPI `servers` must be present and non-empty array. […more…] 7:9 warning operation-tags Operation should have non-empty `tags` array. ✖ 7 problems (0 errors, 7 warnings, 0 infos, 0 hints)
  7. API Description Linter Running Spectral CLI PROBLEM LOCATION (LINE:CHAR) 7:9

    warning operation-tags Operation should have non-empty `tags` array.
  8. API Description Linter Running Spectral CLI PROBLEM LEVEL 7:9 warning

    operation-tags Operation should have non-empty `tags` array.
  9. API Description Linter Running Spectral CLI RULE NAME 7:9 warning

    operation-tags Operation should have non-empty `tags` array.
  10. API Description Linter Running Spectral CLI PROBLEM DESCRIPTION 7:9 warning

    operation-tags Operation should have non-empty `tags` array.
  11. API Description Linter Predefined Rules contact-properties info-contact info-description info-license license-url

    no-$ref-siblings no-eval-in-markdown no-script-tags-in-markdown oas2-anyOf oas2-api-host oas2-api-schemes oas2-host-not-example oas2-host-trailing-slash oas2-oneOf oas2-operation-formData-consume-check oas2-operation-security-defined oas2-parameter-description oas2-unused-definition oas2-valid-definition-example oas2-valid-parameter-example oas3-api-servers oas3-examples-value-or-externalValue oas3-operation-security-defined oas3-parameter-description oas3-schema oas3-server-not-example.com oas3-server-trailing-slash oas3-unused-components-schema oas3-valid-content-schema-example oas3-valid-header-schema-example oas3-valid-oas-content-example oas3-valid-oas-header-example oas3-valid-oas-parameter-example …
  12. API Description Linter Creating Spectral Ruleset alphabetical enumeration falsy length

    pattern casing schema schemaPath truthy undefined unreferencedReusableObject xor typedEnum CORE FUNCTIONS
  13. API Description Linter Creating Spectral Ruleset rules: properties-id-string: given: $.components.schemas.*.properties.id

    then: field: type function: enumeration functionOptions: values: - string description: All id properties must be of type string
  14. API Description Linter Running Spectral CLI with Custom Ruleset >

    spectral lint -r ruleset.yaml openapi.yaml
  15. API Description Linter Running Spectral CLI with Custom Ruleset >

    spectral lint -r ruleset.yaml openapi.yaml 28:17 warning properties-id-string All id properties must be of type string ✖ 1 problem (0 errors, 1 warning, 0 infos, 0 hints)
  16. API Description Linter Running Spectral CLI with Custom Ruleset components:

    schemas: User: properties: id: type: integer RULE OPENAPI given: $.components.schemas.*.properties.id then: field: type function: enumeration functionOptions: values: - string LINE 28
  17. Ruleset Design Rule Granularity GET /whatever/<plural noun> { “items”: [

    { … } ], “page”: { “current”: 1, “total”: 12 } }
  18. Ruleset Design Rule Granularity rules: valid-collection-schema: description: A list response

    must be an encapsulated inside an items property of an object, elements must be objects and the object list may come with optional pagination data
  19. Ruleset Design Rule Granularity rules: valid-collection-schema: description: A list response

    must … given: $.paths[?(/(s|i?es|ves)$/.test(@property))] .get.responses.200.content.’application/json'.schema
  20. Ruleset Design Rule Granularity rules: valid-collection-schema: description: A list response

    must … given: $.paths[?(/(s|i?es|ves)$/.test(@property))] .get.responses.200.content.’application/json'.schema
  21. Ruleset Design Rule Granularity rules: valid-collection-schema: description: A list response

    must … given: $.paths[?(/(s|i?es|ves)$/.test(@property))] .get.responses.200.content.’application/json'.schema
  22. Ruleset Design Rule Granularity rules: valid-collection-schema: description: A list response

    must … given: $.paths[?(/(s|i?es|ves)$/.test(@property))] .get.responses.200.content.’application/json'.schema TIP ALERT
  23. Ruleset Design Rule Granularity rules: valid-collection-schema: description: A list response

    must … given: $.paths… then: function: schema functionOptions: schema: # Put expected JSON Schema here …
  24. Ruleset Design Rule Granularity then: function: schema functionOptions: schema: #

    JSON Schema of the expected JSON Schema type: object required: - properties properties: properties: type: object TIP ALERT
  25. Ruleset Design Rule Granularity paths: /users: get: responses: 200: content:

    application/json: schema: type: array items: $ref: #/components/schemas/User GET /USERS RETURNS AN ARRAY OF USER
  26. Ruleset Design Rule Granularity > spectral lint -r ruleset.yaml openapi.yaml

    54:11 warning valid-collection-schema A list response must be an encapsulated inside an items property of an object, elements must be objects and the object list may come with optional pagination data ✖ 1 problem (0 errors, 1 warning, 0 infos, 0 hints) SO WHAT?
  27. Ruleset Design Rule Granularity rules: valid-collection-schema: description: A list response

    must be an encapsulated inside an items property of an object, elements must be objects and the object list may come with optional pagination data message: "{{description}} ({{path}}: {{error}})" TIP ALERT
  28. Ruleset Design Rule Granularity > spectral lint -r ruleset.yaml openapi.yaml

    54:11 warning valid-collection-schema A list response must be an encapsulated inside an items property of an object, elements must be objects and the object list may come with optional pagination data (#/components/schemas/Users: Object should have required property `properties`) ✖ 1 problem (0 errors, 1 warning, 0 infos, 0 hints) TOO COARSE GRAINED RULE
  29. Ruleset Design Rule Granularity > spectral lint -r ruleset.yaml openapi.yaml

    54:11 warning response-list-is-encapsulated A list response (get /whatever/<plural name>) must be an object with a mandatory property items which is a list 55:13 warning response-is-object A success (2xx, except 204) or an error (4xx or 5xx) response must be an object ✖ 2 problem (0 errors, 2 warnings, 0 infos, 0 hints) EXPLICIT PROBLEM
  30. Ruleset Design Rule Severity rules: rulename: severity: error description: must

    be fixed without discussion 204 NO CONTENT RETURNING DATA
  31. Ruleset Design Rule Severity rules: rulename: severity: hint description: further

    investigation needed NON APPLICATION/JSON MEDIA TYPE SHOULD NOT GO THROUGH API GATEWAY
  32. Ruleset Design Rule Severity rules: fix: severity: error fix-if-needed: severity:

    warning possible-improvement: severity: info further-investigation-needed: severity: hint
  33. Ruleset Design Rules Organisation oas-ruleset.yaml info-ruleset.yaml basepath-ruleset.yaml path-ruleset.yaml model-ruleset.yaml model-response-ruleset.yaml

    http-method-ruleset.yaml http-status-code-ruleset.yaml parameter-ruleset.yaml security-ruleset.yaml MULTIPLE RULESETS
  34. Ruleset Design Rules Organisation extends: - oas-ruleset.yaml - info-ruleset.yaml -

    basepath-ruleset.yaml - path-ruleset.yaml - http-method-ruleset.yaml - http-status-code-ruleset.yaml - parameter-ruleset.yaml - model-ruleset.yaml - model-response-ruleset.yaml - security-ruleset.yaml MAIN RULESET
  35. Testing Rulesets Version 1 - Monolithic Manual Testing > spectral

    lint -r ruleset.yaml test-openapi.yaml SINGLE RULESET + SINGLE TEST FILE
  36. Testing Rulesets Version 2 - Split Manual Testing > spectral

    lint -r security-ruleset.yaml \ security-test-openapi.yaml MULTIPLE RULESETS + TEST FILES
  37. Testing Rulesets Version 3 - Automatic Testing > npm install

    —save-dev @stoplight/spectral > mocha test/security-test.js MOCHA UNIT TESTS RUNNIG SPECTRAL LIBRARY
  38. Testing Rulesets Version 4 - Isolated Automatic Testing beforeEach(function ()

    { this.linterTester.disableAllRulesExcept(this.rule) }) ONLY 1 RULE KEPT ACTIVE
  39. Testing Rulesets Version 4 - Isolated Automatic Testing const document

    = { paths: { '/some/path': { anymethod: { responses: { 204: {} }}}}} linterTester.runAndCheckNoError(document) ALSO ABLE TO USE PARTIAL DOCUMENTS
  40. Testing Rulesets Version 5 - Checking Tests Exhaustivity it('should exist

    a test file for each ruleset', function () { … }) it('should have no untested rule', function () { … }) CHECKING EVERYTHING IS TESTED
  41. Testing Rulesets Version 6 - JSON Paths Testing const {

    JSONPath } = require('jsonpath-plus') const document = { … } const expectedPaths = [ ['paths', '/some/path', 'anymethod', 'responses', ‘201'], ['paths', '/some/path', 'anymethod', 'responses', '401'], ] linterTester.checkGivenFound(document, expectedPaths) TESTING JSON PATH INDEPENDENTLY TIP ALERT
  42. Testing Rulesets Testing Summary describe('ruleset name', function () { describe('rule

    name', function() { it('should find …', … ) it('should ignore …', … ) it('should return errors …', … ) it('should return no errors …’, … ) } } TESTS GIVEN TESTS THEN
  43. Testing Rulesets Testing Summary describe('ruleset name', function () { describe('rule

    name', function() { it('should find …', … ) it('should find …', … ) it('should return errors …', … ) it('should return no errors …’, … ) } … describe('check exhaustive tests', … ) } CHECKS NO UNTESTED RULE
  44. Designing Rulesets Take aways GUIDELINES FIRST RULE GRANULARITY RULE SEVERITY

    ORGANIZE IN RULESETS TEST USER FRIENDLINESS MAINTAINABILITY
  45. Using Spectral in 3 Different Ways Quick Check With CLI

    > spectral lint -r \ https://raw.git.com/api/release/main-ruleset.yaml \ user-v1-openapi.yaml 54:11 error response-list-is-encapsulated A list response… 55:13 error response-is-object A success (2xx, except 204)… ✖ 2 problem (2 errors, 0 warnings, 0 infos, 0 hints) TIP ALERT USE RULESET IN GIT REPO
  46. Using Spectral in 3 Different Ways In Depth Analysis In

    Stoplight Studio extends: - https://raw.git.com/api/release/main-ruleset.yaml
  47. Using Spectral in 3 Different Ways In Depth Analysis In

    Stoplight Studio PROBLEMS LIST OPENAPI CODE
  48. Using Spectral in 3 Different Ways Spreadsheet Review Summary >

    spectral lint -r \ https://raw.git.com/api/release/main-ruleset.yaml \ user-v1-openapi.yaml ✖ 435 problems (335 errors, 68 warnings, 20 infos, 2 hints)
  49. Using Spectral in 3 Different Ways Spreadsheet Review Summary >

    spectral lint -q -f json -r ruleset.yaml openapi.yaml [ { "code": "response-list-is-encapsulated", "path": [ "components", "schemas", "Users"], "message": "A list response ...", "severity": 0, "range": { "start": { "line": 53, "character": 10 }, "end": { "line": 56, "character": 41 } }, "source": "/path/to/openapi.yaml" }, ... ] JSON OUTPUT TIP ALERT
  50. Using Spectral in 3 Different Ways Spreadsheet Review Summary >

    spectral lint -q -f json -r ruleset.yaml openapi.yaml \ | jq -r -f csv.jq code,severity,path,line,message response-list-is-encapsulated,error,#/components/schemas/ Users,53,A list response … response-is-an-object,error,#/components/schemas/Users/type,54,A success … JSON TO CSV (JQ’S MAGIC) TIP ALERT
  51. The Augmented API Design Reviewer Take aways OPENAPI + SPECTRAL:

    MUST HAVE FOR API DESIGN + DESIGN REVIEWS LINTER NEED DESIGN AND TEST LINTER DO NOT REPLACE HUMANS LINTER HELP HUMANS FOCUS ON WHAT THEY’RE GOOD AT