typespec1-2 Exercise 3: Linting, and Fixing What the Spec Left Out ========================================================================= First, the chapter's file linted with the recommended ruleset: No configurations were provided -- using built in recommended configuration by default. validating tsp-output/v3.1.0/openapi.yaml... tsp-output/v3.1.0/openapi.yaml: 1:1 error no-empty-servers Servers must be present. 8:5 error operation-summary Operation object should contain `summary` field. 26:5 error operation-summary Operation object should contain `summary` field. 43:5 error operation-summary Operation object should contain `summary` field. 8:5 error security-defined Every operation should have security defined on it or on the root level. 26:5 error security-defined Every operation should have security defined on it or on the root level. 43:5 error security-defined Every operation should have security defined on it or on the root level. 2:1 warning info-license Info object should contain `license` field. 17:7 warning operation-4xx-response Operation must have at least one `4XX` response. 29:7 warning operation-4xx-response Operation must have at least one `4XX` response. 51:7 warning operation-4xx-response Operation must have at least one `4XX` response. tsp-output/v3.1.0/openapi.yaml: validated in 28ms ❌ Validation failed with 7 errors and 4 warnings. run `redocly lint --generate-ignore-file` to add all problems to the ignore file. WHAT EACH ERROR MEANS no-empty-servers (1) the document has no servers: nobody can tell where to send requests operation-summary (3) none of the three operations has a one-line summary security-defined (3) no authentication is declared, on the operations or at the root (warnings) info-license, operation-4xx-response (3): no licence; no error response on any operation The fixed spec (this previews chapters 4 and 5, so the decorators are not explained here): import "@typespec/http"; import "@typespec/openapi"; using Http; using OpenAPI; @service(#{ title: "Widget Service" }) @info(#{ license: #{ name: "MIT" } }) @server("https://api.example.com", "Production") @useAuth(BearerAuth) namespace WidgetService; enum Color { red, blue } model Widget { id: string; name: string; weight: int32; color: Color; nickname: string | null; tags?: string[]; } @error model NotFound { @statusCode _: 404; message: string; } @route("/widgets") interface Widgets { @summary("List widgets") @get list(@query color?: Color): Widget[]; @summary("Read one widget") @get read(@path id: string): Widget | NotFound; @summary("Create a widget") @post create(@body widget: Widget): Widget; } Lint result for the fixed spec (compiled to OpenAPI 3.1.0): No configurations were provided -- using built in recommended configuration by default. validating tsp-output/fixed/openapi.yaml... tsp-output/fixed/openapi.yaml: 4:3 warning info-license-strict License object should contain one of the fields: `url`, `identifier`. 116:10 warning no-server-example.com Server `url` should not point to example.com or localhost. 20:7 warning operation-4xx-response Operation must have at least one `4XX` response. 33:7 warning operation-4xx-response Operation must have at least one `4XX` response. tsp-output/fixed/openapi.yaml: validated in 28ms Woohoo! Your API description is valid. 🎉 You have 4 warnings. WHAT THE FIXES DID @server(url, description) added a servers entry (and the lint now objects that the URL is example.com) @summary(...) a summary on each of the three operations @useAuth(BearerAuth) a security scheme (HTTP bearer) and a root-level security requirement @info(#{ license: #{ name: "MIT" } }) a licence name, so info-license passes but the stricter info-license-strict wants a url too a NotFound error model on read a 404 response on GET /widgets/{id}, which cleared operation-4xx-response for that one operation only All seven errors are gone. Four warnings remain: the licence has no URL, the server is an example.com address, and list and create still have no 4xx response. WHY THIS WORKS AS AN ANSWER --------------------------- A linter turns 'a good contract' into a list of concrete omissions, and each omission has a place in the TypeSpec where it can be put right: nothing was edited in the generated file. The remaining warnings are a good prompt for chapter 4's work on responses: what can go wrong with a list or a create, and what should the contract promise when it does.