<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Phil Sturgeon</title>
    <description>The latest articles on Forem by Phil Sturgeon (@philsturgeon).</description>
    <link>https://forem.com/philsturgeon</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F34539%2F0decd28a-00a5-48a8-b620-efab72025818.jpeg</url>
      <title>Forem: Phil Sturgeon</title>
      <link>https://forem.com/philsturgeon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/philsturgeon"/>
    <language>en</language>
    <item>
      <title>There's No Reason to Write OpenAPI By Hand</title>
      <dc:creator>Phil Sturgeon</dc:creator>
      <pubDate>Fri, 24 Apr 2020 14:28:30 +0000</pubDate>
      <link>https://forem.com/philsturgeon/there-s-no-reason-to-write-openapi-by-hand-425</link>
      <guid>https://forem.com/philsturgeon/there-s-no-reason-to-write-openapi-by-hand-425</guid>
      <description>&lt;p&gt;Some API developers use API descriptions to plan the interface of an API before building it, which is known as the "API design first" workflow. Others build the API then generate (or manually produce) API descriptions later, which is the "code-first" workflow. We wrote &lt;em&gt;&lt;a href="https://apisyouwonthate.com/blog/api-design-first-vs-code-first/" rel="noopener noreferrer"&gt;API Design-first vs Code-first&lt;/a&gt;&lt;/em&gt; recently to help get you up to speed on the differences, but how do you actually create these API descriptions? &lt;/p&gt;

&lt;p&gt;Many of these API descriptions (&lt;a href="https://www.openapis.org/" rel="noopener noreferrer"&gt;OpenAPI&lt;/a&gt;, &lt;a href="https://json-schema.org/" rel="noopener noreferrer"&gt;JSON Schema&lt;/a&gt;, or &lt;a href="https://graphql.org/learn/schema/" rel="noopener noreferrer"&gt;GraphQL Schemas&lt;/a&gt;) involve writing out a bunch of special keywords in YAML, JSON, or another text language. Neither the design-first or code-first crew enjoy writing thousands of lines of that by hand. Why? Well, say you've got a list of integers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;array&lt;/span&gt;
     &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;List of IDs&lt;/span&gt;
     &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
       &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pet ID&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Designing an API with 100 endpoints like that will get you through at least one keyboard (maybe two if it's a Macbook). Designing a few APIs could drive you bonkers. &lt;/p&gt;

&lt;p&gt;Let's look at some alternatives to hand-rolling your own homegrown artisanal YAML, and how these approaches fit into design-first or code-first. More importantly, let's see how they can be used to achieve the ultimate goal for API designers: one source of truth for API descriptions that power mocks, documentation, request validation, shareable design libraries, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Annotations
&lt;/h2&gt;

&lt;p&gt;Some programming languages support a syntax-level feature called "Annotations", for example &lt;a href="https://www.baeldung.com/java-default-annotations" rel="noopener noreferrer"&gt;Java Annotations&lt;/a&gt;. An OpenAPI annotation framework provides a bunch of keywords that help the API developer describe the interface of the HTTP request and response, and hopefully it's telling the truth.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@OpenApi&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/users"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HttpMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;POST&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some languages do not have any support for annotations, and they achieve this with docblock comments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
  * @OA\Get(path="/2.0/users/{username}",
  *   operationId="getUserByName",
  *   @OA\Parameter(name="username",
  *     in="path",
  *     required=true,
  *     description=Explaining all about the username parameter
  *     @OA\Schema(type="string")
  *   ),
  *   @OA\Response(response="200",
  *     description="The User",
  *     @OA\JsonContent(ref="#/components/schemas/user"),
  *     @OA\Link(link="userRepositories", ref="#/components/links/UserRepositories")
  *   )
  * )
  */&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getUserByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$newparam&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// implementation logic ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In JavaScript it looks a bit like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @swagger
 * /users:
 *   get:
 *     description: Returns users
 *     produces:
 *      - application/json
 *     responses:
 *       200:
 *         description: users
 *         schema:
 *           type: array
 *           items:
 *             $ref: '#/definitions/User'
 */&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// implementation logic ...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach is the oldest around, and is primarily used by the code-first people. It's easy to understand why: you wrote the code already, so now lets get some docs! Sprinkle some keywords around the code, and the annotation system will integrate with your framework to emit a &lt;code&gt;/docs&lt;/code&gt; endpoint, and boom, you've got some documentation. Great, if all you want is documentation.&lt;/p&gt;

&lt;p&gt;Design-first people also sometimes use this approach. They design the entire API (writing YAML by hand or with one of the other approaches we're going to mention), then use Server Generators like &lt;a href="https://openapi-generator.tech/" rel="noopener noreferrer"&gt;openapi-generator&lt;/a&gt; or &lt;a href="https://github.com/swagger-api/swagger-codegen" rel="noopener noreferrer"&gt;swagger-generator&lt;/a&gt; to create their API code. This API code is created from the machine-readable documents that were made in the design process, and the code that is generated is chock full of annotations already, which in turn can generate documentation. Throw those machine-readable documents away, the annotated code is the source of truth now... right?&lt;/p&gt;

&lt;p&gt;One downside to annotations is that they don't confirm the code is doing what it says. I've heard the argument "Annotations are closer to the code they describe, so developers are more likely to keep it up to date". Do not confuse proximity with accuracy. Developers can forget to make the changes, and developers can make mistakes.&lt;/p&gt;

&lt;p&gt;Annotation users need to find a way to contract test the actual output against these annotations, which we've written about before in &lt;a href="https://apisyouwonthate.com/blog/keeping-documentation-honest" rel="noopener noreferrer"&gt;Keeping Documentation Honest&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The tools in this article generally involve the machine-readable OpenAPI / JSON Schema files around, so you need to export them back to a machine-readable format in order to compare them to the code... This means running a command in the command line which pulls the annotations out into a machine-readable file, then running a tool like Dredd or a JSON Schema validators, which is a pretty awkward step.&lt;/p&gt;

&lt;p&gt;Design-first is incompatible with all this, unless you chose to design the API, then generate code with annotations, then figure out how to keep the code, the annotations AND the machine readable designs up to date. If there's anything worse than two sources of truth it's three...&lt;/p&gt;

&lt;p&gt;For this reason, folks who like design-first run and hide from annotations, but the folks who like annotations generally really really love them because to them their code is the source of truth and if they can crowbar one of these test suites in to confirm that then they're perfectly happy. This mindset can lead to API clients being a bit of an afterthought, but that's another topic for another article.&lt;/p&gt;

&lt;h2&gt;
  
  
  DSL (Domain Specific Language)
&lt;/h2&gt;

&lt;p&gt;A few DSLs popped up over the years, created by people who wanted to create API Descriptions, but didn't fancy writing it out in that specific format, with articles like &lt;em&gt;&lt;a href="https://developer.squareup.com/blog/making-openapi-swagger-bearable-with-your-own-dsl/" rel="noopener noreferrer"&gt;Making OpenAPI / Swagger Bearable With Your Own DSL&lt;/a&gt;&lt;/em&gt;.  &lt;/p&gt;

&lt;p&gt;DSL's can be used in code-first or design-first. You have your code, you have your DSL-based descriptions, and whatever format they were written in doesn't make much difference here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;;;; ENTITIES
(define pet-entity
 (entity "Pet"
    'race (string "What kind of dog / cat this is (labrador, golden retriever, siamese, etc...)" "Labrador")
    'origin (string "Country of origin" "Egypt")
    'birthday (datetime "Birth date of the pet" "2017-10-20T00:14:02+0000")
    'species (string "What kind of animal is this" "dog" #:enum '("dog" "cat"))))
(define $pet (schema-reference 'Pet pet-entity))

;;; RESPONSES
(define list-pets-response (jsonapi-paginated-response "List of pets" ($pet)))

;;; REQUESTS
(define pet-request (json-request "Pet Request Body" ($pet)))

;;; MAIN DOC
(define swagger
 (my-service-api-doc "Pet Store" "Per store pets management"
   (path "/pets") (endpoint-group
      'tags pet-tags
      'parameters (list store-id-param)
      'get (endpoint
              'operationId "listPets"
              'summary "Retrieve all the pets for this store"
              'parameters pagination-params
              'responses (with-standard-get-responses 200 list-pets-response))
      'post (endpoint
              'operationId "createPet"
              'summary "Create a new Pet record"
              'requestBody pet-request
              'parameters (list xsrf-token)
              'responses (with-standard-post-responses 200 single-pet-response)))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is shorter than the OpenAPI YAML it replaces, but it's also another format for people to learn. People who know how to write up OpenAPI will need to learn this format, and the folks familiar with a different DSL will have to learn this format too. Your editor will also need to learn about this format if you want autocomplete, syntax highlighting, linting and validation. The "native" description formats all have this, but these DSLs usually do not.&lt;/p&gt;

&lt;p&gt;This approach, just like annotations, do not help you ensure that what you're writing in the DSL is actually correct. The contract written down in the description could be completely incorrect. Some DSLs like &lt;a href="https://github.com/rswag/rswag" rel="noopener noreferrer"&gt;RSawg&lt;/a&gt; aim to solve this by having their DSL be written as integration texts. The source of truth for how you create OpenAPI is literally integration tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s1"&gt;'Blogs API'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'/blogs/{id}'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s1"&gt;'Retrieves a blog'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;tags&lt;/span&gt; &lt;span class="s1"&gt;'Blogs'&lt;/span&gt;
      &lt;span class="n"&gt;produces&lt;/span&gt; &lt;span class="s1"&gt;'application/json'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'application/xml'&lt;/span&gt;
      &lt;span class="n"&gt;parameter&lt;/span&gt; &lt;span class="ss"&gt;name: :id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:in&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:type&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;

      &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="s1"&gt;'200'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'blog found'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="ss"&gt;type: :object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="ss"&gt;properties: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;type: :integer&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;type: :string&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="ss"&gt;content: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;type: :string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="ss"&gt;required: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'title'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'content'&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;Blog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="s1"&gt;'foo'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;content: &lt;/span&gt;&lt;span class="s1"&gt;'bar'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;run_test!&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach is pretty handy for &lt;a href="https://en.wikipedia.org/wiki/Test-driven_development" rel="noopener noreferrer"&gt;Test-driven development (TDD)&lt;/a&gt; advocates, but you're just writing OpenAPI in another form which isn't particularly any shorter, just more Ruby-ish. RSwag was a big favourite at my last job, but it's had a rough time getting updated onto OpenAPI v3.0 (still a work in progress 3 years after OpenAPI v3.0 was released).&lt;/p&gt;

&lt;p&gt;Writing in a DSL or annotations means you're at the mercy of that maintainer to support functionality that you could already use if you could just... edit the OpenAPI yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Graphical Design Editors
&lt;/h2&gt;

&lt;p&gt;What is the alternative to editing the files but now having to wrangle YAML? Visual thinkers and non-technical people might want a wizard mode, the ability to create arrays of objects with a few buttons, and selection boxes for &lt;a href="https://stoplight.io/blog/keeping-openapi-dry-and-portable/" rel="noopener noreferrer"&gt;shared models&lt;/a&gt; without having to think about the filepath. Graphical design editors are pretty new in the world of OpenAPI and GraphQL, with a few popping up over the last year or two. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyx4s4gbnbfx5dhjs4kgq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyx4s4gbnbfx5dhjs4kgq.png"&gt;&lt;/a&gt;&lt;br&gt;&lt;a href="https://stoplight.io/studio" rel="noopener noreferrer"&gt;Stoplight Studio&lt;/a&gt; main form editor view, showing some the &lt;code&gt;$ref&lt;/code&gt; selector for picking OpenAPI models.
  &lt;/p&gt;

&lt;p&gt;Two years ago I was looking around for a beautiful, effective graphical editor to satisfy some code-first sticklers pushing back against &lt;a href="https://apisyouwonthate.com/blog/weworks-api-specification-workflow/" rel="noopener noreferrer"&gt;API design-first at WeWork&lt;/a&gt;. I figured a GUI would help them convert, and Stoplight told me they were planning a new GUI. Shortly after seeing their amazing prototype I joined the company to help roll it out to even more folks, and now my job is gathering feedback from the API community to make &lt;a href="https://stoplight.io/studio/" rel="noopener noreferrer"&gt;Studio&lt;/a&gt;, our open-source tools, and the upcoming SaaS platform even better. 🥳&lt;/p&gt;

&lt;p&gt;Modern GUI editors have mocks and docs publishing built right in so you no longer have to figure out your own "DocOps". Editors like Stoplight Studio add "Design Libraries", where you can manage shared models between multiple APIs in an organization. These editors support organization-wide &lt;a href="https://www.apisyouwonthate.com/blog/automated-style-guides-for-rest-graphql-and-grpc" rel="noopener noreferrer"&gt;style guides to have the editor lint&lt;/a&gt; during editing (and/or in continuous integration) to enforce consistency, and a bajillion other things. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9imxaxc2gmd4mkzkbvwq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9imxaxc2gmd4mkzkbvwq.png"&gt;&lt;/a&gt;&lt;br&gt;&lt;a href="https://stoplight.io/studio" rel="noopener noreferrer"&gt;Stoplight Studio&lt;/a&gt; with &lt;a href="https://stoplight.io/open-source/spectral" rel="noopener noreferrer"&gt;Spectral&lt;/a&gt; linting results from a custom rule written to stop folks designing a GET endpoint with a body.
  &lt;/p&gt;

&lt;p&gt;There are a bunch of different OpenAPI-based graphical editors around, check out our list on &lt;a href="https://openapi.tools/#gui-editors" rel="noopener noreferrer"&gt;OpenAPI.Tools&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.apicur.io/" rel="noopener noreferrer"&gt;Apicurio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.apitive.com/" rel="noopener noreferrer"&gt;Apitive Studio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.reprezen.com/" rel="noopener noreferrer"&gt;Reprezen API Studio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stoplight.io/studio/" rel="noopener noreferrer"&gt;Stoplight Studio&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GraphQL fans, who are having a lot of &lt;a href="https://blog.logrocket.com/code-first-vs-schema-first-development-graphql/" rel="noopener noreferrer"&gt;the same conversations&lt;/a&gt; right now, can check out these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://graphqldesigner.com/" rel="noopener noreferrer"&gt;GraphQL Designer&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://graphqleditor.com/" rel="noopener noreferrer"&gt;GraphQL Editor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some editors will help you with part of the API design life-cycle, but make a lot of difficult assumptions about what order you're going to do what in. They might help you &lt;em&gt;create&lt;/em&gt; a design, then they'd assume you wanted to export it and generate some code, leaving your machine-readable description documents floating around to become obsolete, and giving you no way to edit them even if you wanted to. Other tools let you import an OpenAPI document, but convert it to their own internal format and provide no way to pull the OpenAPI back out again.&lt;/p&gt;

&lt;p&gt;Using tools where the format changes entirely at different points locks you into whatever workflows they support, instead of letting you plug-and-play your own tooling at every stage of the process. For me the ideal solution is supporting a git-based flow, where they live in the repository (maybe before the code exists), and regardless of how these API descriptions were created you can edit them and send a pull request back to that repo with the changes you made.&lt;/p&gt;

&lt;p&gt;Leaving the machine-readable source of truth in the repo means any integrations are possible. Continuous integration processes can deploy documentation to any documentation provider, you can use use &lt;a href="https://openapi.tools/#sdk" rel="noopener noreferrer"&gt;any code-generators&lt;/a&gt; to build and publish SDKs, sync with popular HTTP clients like Postman or Insomnia instead of maintaining API descriptions &lt;em&gt;and&lt;/em&gt; bookmarks, and fully take care of contract testing in-repo or end-to-end repositories. If your editor is backed by a design library then the repositories will be analyzed on push, allowing others to use these updated models instead of having 1000 different versions of a "User", "Company" or a "Flight".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbuy780cvjp7i4x6x9ce9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbuy780cvjp7i4x6x9ce9.png"&gt;&lt;/a&gt;&lt;br&gt;The main Stoplight Explorer dashboard, providing search across all APIs in an organization. This has only been available for &lt;a href="https://stoplight.io/enterprise" rel="noopener noreferrer"&gt;Enterprise&lt;/a&gt; users, but is available for everyone this April.
  &lt;/p&gt;

&lt;p&gt;But, how does having an editor help you catch mistakes? Stoplight Studio has a &lt;a href="https://stoplight.io/p/docs/gh/stoplightio/studio/docs/Design-and-Modeling/05-request-maker.md" rel="noopener noreferrer"&gt;built in HTTP Client&lt;/a&gt;, which amongst other things is watching for mismatches between the OpenAPI defined for the API and the actual HTTP requests you send. It will also notice mismatches between OpenAPI and the responses coming back, so you'll see mistakes popping up like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fasviu8hdzwwsmp4xug14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fasviu8hdzwwsmp4xug14.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Noticing contract mismatches in a HTTP client is all well and good for spotting mistakes in requests you're making, but you'll want to automate this checking too. &lt;/p&gt;

&lt;p&gt;Instead of having all your model validation rules and header checking written in code, and then also writing it down in the API descriptions, use the existing machine-readable descriptions for &lt;a href="https://www.apisyouwonthate.com/blog/server-side-validation-with-api-descriptions" rel="noopener noreferrer"&gt;validating incoming requests&lt;/a&gt;. If your request logic is powered by API descriptions, there is no need to check that it matches the code, because it... is the code. Framework middlewares for every framework and every language implement this. NodeJS has about 100.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PHP:&lt;/strong&gt; &lt;a href="https://github.com/thephpleague/openapi-psr7-validator" rel="noopener noreferrer"&gt;league/openapi-psr7-validator&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node.js:&lt;/strong&gt; &lt;a href="https://github.com/fastify/fastify/blob/master/docs/Validation-and-Serialization.md" rel="noopener noreferrer"&gt;fastify&lt;/a&gt; / &lt;a href="https://github.com/Zooz/express-ajv-swagger-validation" rel="noopener noreferrer"&gt;express-swagger-ajv-validator&lt;/a&gt; / &lt;a href="https://github.com/Hilzu/express-openapi-validate" rel="noopener noreferrer"&gt;express-openapi-validate&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ruby/Rails:&lt;/strong&gt; &lt;a href="https://github.com/interagent/committee" rel="noopener noreferrer"&gt;committee&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python:&lt;/strong&gt; &lt;a href="https://github.com/zalando/connexion" rel="noopener noreferrer"&gt;connexion&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Perl:&lt;/strong&gt; &lt;a href="https://metacpan.org/pod/Mojolicious::Plugin::OpenAPI" rel="noopener noreferrer"&gt;Mojolicious::Plugin::OpenAPI&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Rails one, for example, takes a single line to set up the Rack middleware:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Committee&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Middleware&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;RequestValidation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;schema_path: &lt;/span&gt;&lt;span class="s2"&gt;"./openapi.yaml"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That covers incoming requests, but how to ensure the responses are doing the right thing? Some of those middlewares will implement response validation too, which can confirm the response coming through it matches the code. This is a great thing to enable in dev and staging, but turn that off for production. 🤣&lt;/p&gt;

&lt;p&gt;Another approach to checking responses is contract testing. Instead of having some DSL-based integration testing suite specifically for checking the responses, or using some other tool where you have to write out the contract again, you can can just &lt;a href="https://www.apisyouwonthate.com/blog/writing-documentation-via-contract-testing" rel="noopener noreferrer"&gt;use the API descriptions as contract tests&lt;/a&gt;. So easy, and all it takes is a few lines of code to mush the response into a data validator for the API description format of your choice.&lt;/p&gt;

&lt;p&gt;Another approach is using &lt;a href="https://stoplight.io/p/docs/gh/stoplightio/prism/docs/guides/03-validation-proxy.md" rel="noopener noreferrer"&gt;Prism Proxy&lt;/a&gt; in end-to-end testing to blow up if any requests or responses are invalid throughout the test suite. This can be implemented with little to no buy in from the folks producing the APIs, because you can just funnel existing cross-API traffic through the proxy in the testing environment without modifying any code.&lt;/p&gt;

&lt;p&gt;Code first and editors do not jive at all, because the editors do not understand the annotation system in the Java/PHP/Pyhton/etc sourcecode. According to an extremely scientific &lt;a href="https://twitter.com/philsturgeon/status/1234455612265725952" rel="noopener noreferrer"&gt;poll on my Twitter&lt;/a&gt;, 35% of teams are battling through with a mixture of code-first and design-first. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwzrjwsmb8ks90oczj9hu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwzrjwsmb8ks90oczj9hu.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;&lt;a href="https://twitter.com/philsturgeon/status/1234455612265725952" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So long as the code-first folks add a build step (pre-commit or in CI) to generate a machine-readable file in the filesystem (like &lt;code&gt;openapi.yaml&lt;/code&gt;), then hosted solutions like Stoplight Platform can analyze repo contents to give the same hosted docs, mocks, and design libraries, to all the projects. No editing for them of course, but those who want editors are on the same remaining workflow as those who don't. 🥳 &lt;/p&gt;
&lt;h2&gt;
  
  
  Annotations-as-Code Web Frameworks
&lt;/h2&gt;

&lt;p&gt;Many web-frameworks third-party support for request/response validation, which we've mentioned above. This is usually in the form of middlewares or just baked right in, and they read API descriptions from the filesystem.&lt;/p&gt;

&lt;p&gt;Other frameworks have first-party or third-party support for annotations, which are purely descriptive repetitions of the actual code they sit above at best. At worst they're just lies.&lt;/p&gt;

&lt;p&gt;There is a new category of API description integration popping up in some web frameworks which is somewhat like Annotations or DSLs, but instead of being purely descriptive it's actually powering logic and reducing code, giving you one source of truth. Effectively they do the same thing as the machine-readable powered validation middlewares, but instead of coming from &lt;code&gt;openapi.yaml&lt;/code&gt; the logic is coming from the annotations. &lt;/p&gt;

&lt;p&gt;Here's an example from &lt;a href="https://github.com/lukeautry/tsoa" rel="noopener noreferrer"&gt;tsoa&lt;/a&gt;, which is a TypeScript and NodeJS framework for building OpenAPI-compliant REST APIs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SuccessResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tsoa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;UserCreationRequest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../models/user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../services/userService&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UsersController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{id}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;SuccessResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;201&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Created&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Custom success response&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;requestBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserCreationRequest&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// set return status 201&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a brand new approach. Instead of descriptive annotations or comments shoved in as an afterthought, the API framework has been designed around the use of annotations. &lt;/p&gt;

&lt;p&gt;Beyond simple things like request validation, &lt;a href="https://github.com/lukeautry/tsoa#authentication" rel="noopener noreferrer"&gt;TSOA handles authentication&lt;/a&gt; quite nicely. Numerous times I've seen API documentation say bearer tokens are required, or an OAuth token needs a certain scope, only to find out the developer forgot to register that in the API controller. Free sensitive data anyone?&lt;/p&gt;

&lt;p&gt;TSOA solves that by having you register security definitions, then reference them in your annotations, and have middlewares created to handle the actual logic. This way the annotations are all the actual source of truth for authentication, instead of just being lies in comments or YAML.&lt;/p&gt;

&lt;p&gt;Then, OpenAPI can be generated from a command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tsoa swagger.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whilst I definitely have a preference for design-first development for all the prototyping benefits it brings (changing a few lines of YAML in an awesome GUI is easier than rewriting a bunch of code every time you get feedback on a prototype), this new approach for making annotations useful is very much closing the gap. If you're going to use a code-first approach, you should absolutely try and find a framework like TSOA to power your API and reduce the chance of mismatches.&lt;/p&gt;

&lt;p&gt;Ideally the file-based middlewares and these new annotation-driven middlewares would share a bunch of dependencies. As I mentioned before there's a million of these file-based validation middlewares out there, and some get more love and attention than others. I convinced three PHP request validation middleware authors to combine efforts and make &lt;a href="https://github.com/thephpleague/openapi-psr7-validator" rel="noopener noreferrer"&gt;one amazing one&lt;/a&gt;, so it'd be great if some of these other middleware developers could team up with some annotations-as-code framework people to allow them as inputs to their existing middleware. With &lt;a href="https://www.apisyouwonthate.com/blog/openapi-v31-and-json-schema-2019-09" rel="noopener noreferrer"&gt;OpenAPI v3.1.0 coming out soon&lt;/a&gt;, it'll be a lot better for us tooling vendors to start collaborating on a smaller number of higher quality tools, instead of everyone battling through the upgrade process individually.&lt;/p&gt;

&lt;p&gt;Whatever you're up to: code-first, or design-first, make sure you're doing what you can to avoid maintaining two sources of truth. Of all the options possible, try and stick to:&lt;/p&gt;

&lt;p&gt;a) awesome editors like &lt;a href="https://stoplight.io/studio/" rel="noopener noreferrer"&gt;Stoplight Studio&lt;/a&gt; or &lt;a href="https://graphqldesigner.com/" rel="noopener noreferrer"&gt;GraphQL Designer&lt;/a&gt; to maintain API description documents, then reference them in the code, or&lt;/p&gt;

&lt;p&gt;b) frameworks which support annotations-as-code that knows how to express itself as API descriptions&lt;/p&gt;

&lt;p&gt;Just don't maintain code and descriptions separately, because having two sources of truth just means waste time trying to find out which one of them is lying.&lt;/p&gt;

</description>
      <category>apidesign</category>
      <category>openapi</category>
      <category>planning</category>
    </item>
    <item>
      <title>Automated Style Guides for REST, GraphQL and gRPC</title>
      <dc:creator>Phil Sturgeon</dc:creator>
      <pubDate>Tue, 05 Nov 2019 20:48:20 +0000</pubDate>
      <link>https://forem.com/philsturgeon/automated-style-guides-for-rest-graphql-and-grpc-3ci0</link>
      <guid>https://forem.com/philsturgeon/automated-style-guides-for-rest-graphql-and-grpc-3ci0</guid>
      <description>&lt;p&gt;Ask 100 developers where a semicolon should go, and you'll either get 100 answers, or a all-on-all fist fight. To save this from happening at work, most folks implement a style guide, which beyond helping with consistent style to avoid new developers getting shouted at for "doing it wrong". Linters can advise best practices, shout about things which are technically allowed but likely to cause trouble, and shape the API of code as it's being written (snake_case that method!) This is always done for code, and is becoming increasingly popular for API descriptions.&lt;/p&gt;

&lt;p&gt;JavaScript users have &lt;a href="https://eslint.org/"&gt;eslint&lt;/a&gt;, PHP users have &lt;a href="https://github.com/squizlabs/PHP_CodeSniffer"&gt;PHP Code Sniffer&lt;/a&gt;, and Ruby has &lt;a href="https://www.rubocop.org/"&gt;rubocop&lt;/a&gt;. These linters don't just check that the user is writing valid syntax. They check against existing sets of rules, sometimes written by a company, like the almost defacto-standard &lt;a href="https://www.npmjs.com/package/eslint-config-airbnb"&gt;eslint-airbnb&lt;/a&gt;. Sometimes the rules are made by standards bodies like PSR-12 by the &lt;a href="https://github.com/squizlabs/PHP_CodeSniffer/tree/master/src/Standards/PSR12"&gt;PHP-FIG&lt;/a&gt;, and the tools create a ruleset to match, like the &lt;a href="https://github.com/squizlabs/PHP_CodeSniffer/blob/master/src/Standards/PSR12/ruleset.xml"&gt;PSR-12 ruleset for CodeSniffer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Today I even had to use &lt;a href="https://github.com/sindresorhus/awesome-lint"&gt;awesome-lint&lt;/a&gt; in order to make sure &lt;a href="https://github.com/philsturgeon/awesome-earth"&gt;awesome-earth&lt;/a&gt; was conforming to their rules, which were built using the &lt;a href="https://github.com/remarkjs/remark-lint"&gt;Remark&lt;/a&gt; Markdown linter.&lt;/p&gt;

&lt;p&gt;When it comes to API descriptions, most companies of a certain size end up with a "Style Guide", "Style Book", "Design Guide", etc. These are often on a Google Doc, wiki, or some other sort of docs/content management system. I've seen loads of these, and written plenty. Many companies &lt;a href="http://apistylebook.com/design/guidelines/"&gt;even publish them&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Text-based Style Guides are a Time Suck
&lt;/h2&gt;

&lt;p&gt;The trouble with these text-based documents is that they are large, terse, unexciting documents, which developers rarely read. If developers &lt;em&gt;do&lt;/em&gt; read them cover to cover, &lt;em&gt;and&lt;/em&gt; remember everything in there, that knowledge becomes partially out of date when new rules are added because they won't know about them until they re-read everything cover to cover again. &lt;/p&gt;

&lt;p&gt;At &lt;em&gt;&lt;a href="https://apithedocs.org/amsterdam2019"&gt;API the Docs&lt;/a&gt;&lt;/em&gt; I saw a talk from &lt;em&gt;Kelsey Lambert&lt;/em&gt; at Salesforce, and their style guide is an example OpenAPI description document which they ask people to check now and then when they are working on something to get ideas of the sorts of things they should use. Salesforce... The giant company with 238479347 APIs who maintain 40 major versions per API, their style guide enforcement approach is eyeballing and memory. Agh I feel for you folks! I have been here and it was bad.&lt;/p&gt;

&lt;p&gt;No developers can be blamed for any of this mess. API developers are busy, and the folks writing style guides are just trying to figure it out as they go along. This mess is an industry problem, but thankfully tools have popped up which can enforce these same style guide concepts through automation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/googleapis/api-linter"&gt;api-linter&lt;/a&gt; by Google&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/cap-collectif/graphql-doctor"&gt;graphql-doctor&lt;/a&gt; by &lt;a href="https://cap-collectif.com/"&gt;Cap Collectif&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/cjoudrey/graphql-schema-linter"&gt;graphql-schema-linter&lt;/a&gt; by &lt;a href="https://twitter.com/cjoudrey"&gt;Christian Joudrey&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stoplight.io/open-source/spectral/"&gt;Spectral&lt;/a&gt; by &lt;a href="https://stoplight.io/"&gt;Stoplight&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each one of these projects sets out to do relatively similar things, but for different types of API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spectral for HTTP APIs
&lt;/h2&gt;

&lt;p&gt;Spectral is a JSON/YAML data linter, with built in rules for OpenAPI v2/v3 and JSON Schema. &lt;/p&gt;

&lt;p&gt;Running the default OpenAPI ruleset on the average document will find plenty of suggestions, which can be helpful for developers not entirely familiar with OpenAPI. Something as small as reminding people to add &lt;code&gt;parameter-descriptions&lt;/code&gt; can help make &lt;a href="https://apisyouwonthate.com/blog/turning-contracts-into-beautiful-documentation"&gt;human-readable docs more useful&lt;/a&gt;, and they might not have even realized that was possible. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hGUaj9oE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/yql68tzs4ija046fuajp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hGUaj9oE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/yql68tzs4ija046fuajp.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can use Spectral to create &lt;a href="https://stoplight.io/p/docs/gh/stoplightio/spectral/docs/getting-started/rulesets.md"&gt;rulesets&lt;/a&gt;, and these rulesets can have custom rules, and even custom functions! &lt;/p&gt;

&lt;p&gt;These custom rules can look a bit like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schema-names-pascal-case&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Schema names MUST be written in PascalCase&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{property}}&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;is&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;not&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;PascalCase:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{error}}'&lt;/span&gt;
    &lt;span class="na"&gt;recommended&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;style&lt;/span&gt;
    &lt;span class="na"&gt;given&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$.components.schemas.*~'&lt;/span&gt;
    &lt;span class="na"&gt;then&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;function&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pattern&lt;/span&gt;
      &lt;span class="na"&gt;functionOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;^[A-Z][a-zA-Z0-9]*$'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This one is a popular one. OpenAPI does not care how you capitalize your models, but a lot of code generators will use the model names for code, and having inconsistent class names will upset people. &lt;/p&gt;

&lt;p&gt;Let's take it a step further:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;paths-kebab-case&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Should paths be kebab-case.&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{property}}&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;is&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;not&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;kebab-case:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{error}}'&lt;/span&gt;
    &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;warn&lt;/span&gt;
    &lt;span class="na"&gt;recommended&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;given&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$.paths[*]~&lt;/span&gt;
    &lt;span class="na"&gt;then&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;function&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pattern&lt;/span&gt;
      &lt;span class="na"&gt;functionOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;^(&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;/[a-z0-9-{}]+)+$"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This rule is actually looking beyond the metadata of your API descriptions, and is looking at the actual API design itself. This is saying that the "paths" (endpoints) must be hyphenated, so &lt;code&gt;/recent-files&lt;/code&gt; is good but &lt;code&gt;/recent_files&lt;/code&gt; is not ok. &lt;/p&gt;

&lt;p&gt;You can start to get really creative with this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;no-x-headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Please&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;do&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;not&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;use&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;headers&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;X-"&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Headers&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;cannot&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;start&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;X-,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;so&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;please&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;find&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;new&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{property}}.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;More:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;https://tools.ietf.org/html/rfc6648"&lt;/span&gt;
    &lt;span class="na"&gt;recommended&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;given&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$..parameters.[?(@.in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;===&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'header')].name"&lt;/span&gt;
    &lt;span class="na"&gt;then&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;function&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pattern&lt;/span&gt;
      &lt;span class="na"&gt;functionOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;notMatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;^(x|X)-'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I don't know why but at some point during the lifecycle of any given API, some developer will suggest adding an &lt;code&gt;X-Foo&lt;/code&gt; header, despite over &lt;a href="https://www.mnot.net/blog/2009/02/18/x-"&gt;a decade of it causing issues&lt;/a&gt;. Well, we can keep them outta here with this rule.&lt;/p&gt;

&lt;p&gt;Done early enough, this will shape the actual API as it is being developed. If you are doing code first then ok, you have to go back and change a bunch of code. Hopefully you didn't ship it, because now you need to go and make a bunch of redirects for &lt;code&gt;/recent_files  /recent_files&lt;/code&gt;. If you use an &lt;a href="https://apisyouwonthate.com/blog/api-design-first-vs-code-first"&gt;API design first workflow&lt;/a&gt;, then you notice this early on when you've just got some YAML, and your API gets built right in the first place.&lt;/p&gt;

&lt;p&gt;Seeing as Spectral is a CLI/JS tool, enforcing this style guide can be done&lt;br&gt;
in all sorts of ways. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;in &lt;a href="https://stoplight.io/p/docs/gh/stoplightio/spectral/docs/guides/workflows.md#git-hooks"&gt;a git hook&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;in a JS test suite&lt;/li&gt;
&lt;li&gt;on &lt;a href="https://stoplight.io/p/docs/gh/stoplightio/spectral/docs/guides/workflows.md#continuous-integration"&gt;continuous integration&lt;/a&gt; to fail builds with errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're using &lt;a href="https://stoplight.io/studio/"&gt;Stoplight Studio&lt;/a&gt; then it's baked right into the editor, so people designing APIs just do it all correctly straight away. No need to alt tab away to the CLI or wait until a PR is made.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qUttDZxI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/s5fus02gskpsbnzolugx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qUttDZxI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/s5fus02gskpsbnzolugx.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am trying to find time to take a style guides from &lt;a href="http://apistylebook.com/design/guidelines/heroku-http-api-design-guide"&gt;Heroku&lt;/a&gt; or &lt;a href="http://apistylebook.com/design/guidelines/paypal-api-style-guide"&gt;PayPal&lt;/a&gt; and turn them into a huge example ruleset. At the very least, I can take some inspiration for a new ruleset I'm putting together: The &lt;a href="https://github.com/openapi-contrib/style-guide"&gt;OpenAPI Contrib &amp;gt; Style Guide&lt;/a&gt;. This should be an interesting  community effort.&lt;/p&gt;

&lt;p&gt;Spectral also has a &lt;a href="https://github.com/stoplightio/spectral-action"&gt;GitHub Action&lt;/a&gt; and a &lt;a href="https://github.com/stoplightio/spectral-bot"&gt;GitHub Bot&lt;/a&gt; which we are working on improving. Commenting on ranges and suggestions coming soon! 😎&lt;/p&gt;
&lt;h2&gt;
  
  
  GraphQL Doctor &amp;amp; Schema Linter
&lt;/h2&gt;

&lt;p&gt;GraphQL has it's own &lt;a href="https://graphql.org/learn/schema/"&gt;built-in type system&lt;/a&gt;, which has some of the same sort of keywords as OpenAPI / JSON Schema based stuff. &lt;/p&gt;

&lt;p&gt;GraphQL makes some design decisions easier, like how you handle relationships. No need to pick between nesting/embedding related resources, inlining everything with a compound documents, or using hyperlinks to link to related data, GraphQL decides that for you. Still, there is a lot of inconsistency that can occur outside of the default decisions GraphQL makes. GraphQL people do not escape the need to lint, but luckily a great linter exists: &lt;a href="https://github.com/cjoudrey/graphql-schema-linter"&gt;GraphQL Schema Linter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uXpO51jt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/oebnn34pt0sppe9ql3ah.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uXpO51jt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/oebnn34pt0sppe9ql3ah.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/cjoudrey/graphql-schema-linter#customizing-rules"&gt;Custom rules&lt;/a&gt; can be written for this one too, so you can automate your style guide in CI. No bot  or GitHub Action that I can see, but they aren't too tough to knock together.&lt;/p&gt;

&lt;p&gt;One schema tool in GraphQL land with a great bot is GraphQL Doctor. It seems like it wants to help with a lot more linting in general, but so far it is focused on detecting breaking changes. Like any type system, there is a fine line between &lt;a href="https://apisyouwonthate.com/blog/surviving-deprecations-to-resources-and-properties-on-other-apis"&gt;careful evolution&lt;/a&gt; and recklessly changing stuff, and GraphQL Doctor will spot the latter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4dcovRbX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/uk0btootdzpvmaj5wffx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4dcovRbX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/uk0btootdzpvmaj5wffx.jpg" alt="A preview of graphql doctor bot, commenting on a github pull request showing the line where a failure happens"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It would be nice to see the two tools merge, or maybe the GraphQL Doctor bot can bake in support for GraphQL Schema Linter, but for now it's a two-stop shop. &lt;/p&gt;
&lt;h2&gt;
  
  
  Google's "API Linter"
&lt;/h2&gt;

&lt;p&gt;Google is doing some pretty interesting work in the API space. They were one of the first big players in the API space consistently explaining "Sometimes you want REST, sometimes you want RPC", and they're keeping at it with a general tool that works for &lt;a href="https://aip.dev/127"&gt;gRPC and HTTP-in-general too&lt;/a&gt;. API linter operates on the protobuf surface layer, but can be set up to work with HTTP endpoints:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When using protocol buffers, each RPC must define the HTTP method and path using the google.api.http annotation:&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rpc CreateBook(CreateBookRequest) returns (Book) {
  option (google.api.http) = {
    post: "/v1/{parent=publishers/*}/books/*"
    body: "book"
  };
}

message CreateBookRequest {
  // The publisher who will publish this book.
  // When using HTTP/JSON, this field is automatically populated based
  // on the URI, because of the `{parent=publishers/*}` syntax.
  string parent = 1;

  // The book to create.
  // When using HTTP/JSON, this field is populated based on the HTTP body,
  // because of the `body: "book"` syntax.
  Book book = 2;

  // The user-specified ID for the book.
  // When using HTTP/JSON, this field is populated based on a query string
  // argument, such as `?book_id=foo`. This is the fallback for fields that
  // are not included in either the URI or the body.
  string book_id = 3;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://googleapis.github.io/api-linter/rules/core/"&gt;core ruleset&lt;/a&gt; for API Linter is rather impressive, and focuses a lot on awkward bits in the HTTP specification which are a bit unclear. Like, should GET have a body? The answer is a very squishy kinda maybe it can, but probably don't, depends on the tool you are building, ugh. Help.&lt;/p&gt;

&lt;p&gt;Google decided to just answer that with: nope.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gkxTCqDR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/srog5vwfsufyjo6hjuoi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gkxTCqDR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/srog5vwfsufyjo6hjuoi.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;They also decided to persuade teams upgrade from proto2 to proto3.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--J59mpgS9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3y98ufrw3v48rb2r8rkc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--J59mpgS9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3y98ufrw3v48rb2r8rkc.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule Ideas
&lt;/h2&gt;

&lt;p&gt;You can automate pretty much anything with this stuff, and I've been thinking a lot &lt;br&gt;
of rules that go beyond the common use cases of enforcing naming or pluralization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Ban HTTP Basic entirely&lt;/li&gt;
&lt;li&gt;Make sure every endpoint has some sort of security (OAuth 2, API Key, but not both)&lt;/li&gt;
&lt;li&gt;Every response should support &lt;code&gt;application/vnd.api+json&lt;/code&gt; (JSON:API) not just plain-old JSON&lt;/li&gt;
&lt;li&gt;ID's as integers let people &lt;a href="https://phil.tech/http/2015/09/03/auto-incrementing-to-destruction/"&gt;crawl your API&lt;/a&gt; incredibly easily, switch to UUID&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Errors
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Your 20X response seems to have errors in it, why do you hate your consumers&lt;/li&gt;
&lt;li&gt;There are no URLs in your errors, how can anyone find out more information about what went wrong&lt;/li&gt;
&lt;li&gt;Error format should be &lt;a href="https://tools.ietf.org/html/rfc7807"&gt;RFC 7807&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Versioning
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Keep &lt;a href="https://apisyouwonthate.com/blog/api-versioning-has-no-right-way/"&gt;version numbers out of the URL&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Version numbers in headers please&lt;/li&gt;
&lt;li&gt;Ban all versioning and &lt;a href="https://apisyouwonthate.com/blog/api-evolution-for-rest-http-apis/"&gt;demand evolution&lt;/a&gt; (prepare for battle)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many of these rules are HTTP API specific but you get the idea. Over time I'll be working on some of these and adding them to OpenAPI Contrib's &lt;a href="https://github.com/openapi-contrib/style-guide"&gt;Style Guide&lt;/a&gt;, and if you'd like to contribute I'll be happy to guide you through the process over on GitHub.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;If you've heard the term API Governance, this is pretty much what most people are talking about. Currently a lot of the people trying to do governance are eyeballing API descriptions on every single PR, and training people to memorize all the quality rules they've come up with. &lt;/p&gt;

&lt;p&gt;Manual API training is a thankless, inefficient, never-ending task, and it can be replaced (or drastically streamlined) with a linter baked into an editor, git hook, CI pipeline, GitHub Action, or a bot.&lt;/p&gt;

&lt;p&gt;Don't waste customers time forcing them to try and figure out your inconsistencies. Don't waste all API developers time learning to memorizing style guides. Don't waste the API governance teams time reviewing APIs manually. Don't waste everyone's time fixing inconsistencies in production later. &lt;/p&gt;

</description>
      <category>api</category>
      <category>graphql</category>
      <category>grpc</category>
      <category>openapi</category>
    </item>
    <item>
      <title>API Design-First vs Code First</title>
      <dc:creator>Phil Sturgeon</dc:creator>
      <pubDate>Thu, 24 Oct 2019 01:28:54 +0000</pubDate>
      <link>https://forem.com/philsturgeon/api-design-first-vs-code-first-l1g</link>
      <guid>https://forem.com/philsturgeon/api-design-first-vs-code-first-l1g</guid>
      <description>&lt;p&gt;&lt;a href="https://medium.com/apis-you-wont-hate/api-design-first-vs-code-first-a8e1708dd48b?source=rss-63d3c9a9b3be------2"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B-KEOIex--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/900/0%2ACKfOj4Hd0COpm43G.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Should you do “API Design-first” or “code-first”, and what do these things even mean?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/apis-you-wont-hate/api-design-first-vs-code-first-a8e1708dd48b?source=rss-63d3c9a9b3be------2"&gt;Continue reading on APIs You Won't Hate »&lt;/a&gt;&lt;/p&gt;

</description>
      <category>restapidesign</category>
      <category>api</category>
      <category>apidesign</category>
      <category>openapi</category>
    </item>
    <item>
      <title>Server-Side Validation with API Descriptions</title>
      <dc:creator>Phil Sturgeon</dc:creator>
      <pubDate>Mon, 27 May 2019 12:31:44 +0000</pubDate>
      <link>https://forem.com/philsturgeon/server-side-validation-with-api-descriptions-5doc</link>
      <guid>https://forem.com/philsturgeon/server-side-validation-with-api-descriptions-5doc</guid>
      <description>&lt;p&gt;Validation can mean a lot of things, but in API land it generally means figuring out if the data being set to the API is any good or not. Validation can happen in a lot of different places, it can happen on the server, and it can happen in the client. Traditionally client-side and server-side validation have both played a role, covering different use-cases.&lt;/p&gt;

&lt;p&gt;Client-side validation is generally used to very quickly provide feedback to a user, to do things like highlighting the input box that failed, with red outlines, tooltips explaining that the email address doesn’t look valid, explaining that the “Amount to pay off your credit card” should be higher than 0, etc. These days browsers take care of a lot of the visual feedback so often client-side validation is not doing quite as much as it used to, but it is still required for “either field A or B should be set, but not both, and if B is set, we C should be too.” sorts of thing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--R_Cybk-L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/500/0%2AVLT_tCuqQX4svep4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--R_Cybk-L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/500/0%2AVLT_tCuqQX4svep4.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Server-side validation has always been required and for an API is the most important of the two. An API that relies entirely on the client is going to end up with problems. Data coming from the client can never be trusted because it’s impossible for the server to know what happened on the client. Even if you’re developing a private API for only two known clients, there are always chances that validation in those clients breaks down; or someone will hit those APIs with curl or Postman and send some invalid stuff. Even if the database catches invalid data, the &lt;a href="https://www.apisyouwonthate.com/blog/creating-good-api-errors-in-rest-graphql-and-grpc"&gt;errors won’t be useful&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Writing validation rules has always been a major source of pains in my… neck, for the last 15 years, so an approach to syncing the two has forever been on my mind.&lt;/p&gt;

&lt;h3&gt;
  
  
  API Description Documents
&lt;/h3&gt;

&lt;p&gt;Server-side validation is usually doing the most mundane of tasks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is this property required&lt;/li&gt;
&lt;li&gt;Is this property an email address&lt;/li&gt;
&lt;li&gt;Is this property a credit card number&lt;/li&gt;
&lt;li&gt;Is this property required if other property is present&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some frameworks shove this logic in the controller, which is a pain when you need to validate the same payload in two different use cases. Others shove it in the data model, like Ruby on Rails:&lt;/p&gt;

&lt;p&gt;Doesn’t this all sound incredibly familiar? This is exactly what API description docs &lt;a href="https://www.apisyouwonthate.com/blog/resolving-overloaded-terms-for-api-specifications-descriptions-contract"&gt;(also known as specifications)&lt;/a&gt; are talking about, required, types, formats, etc… all of this is already handled for us entirely by the same API descriptions we used to &lt;a href="http://github.com/stoplightio/prism/"&gt;generate our mock servers&lt;/a&gt; for trial integrations, that we wrote to get &lt;a href="https://www.apisyouwonthate.com/blog/turning-contracts-into-beautiful-documentation"&gt;beautiful reference docs&lt;/a&gt;, that we are using to manage our API Gateway, etc.&lt;/p&gt;

&lt;p&gt;Some of you may have read our article a while back about &lt;a href="https://www.apisyouwonthate.com/blog/the-many-amazing-uses-of-json-schema-client-side-validation"&gt;using JSON Schema for client-side validation&lt;/a&gt;, and now we want to show you how to leverage your existing source of truth for drastically reducing the amount of validation code you need to write server-side too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which Description Format
&lt;/h3&gt;

&lt;p&gt;OpenAPI and JSON Schema are the two biggest API description formats, and there are a lot of options for all the programming languages.&lt;/p&gt;

&lt;p&gt;OpenAPI tools are listed on &lt;a href="https://openapi.tools/"&gt;OpenAPI.Tools&lt;/a&gt; and JSON Schema has a whole huge list on &lt;a href="https://json-schema.org/implementations.html"&gt;JSON Schema: Implementations&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  JSON Schema Example
&lt;/h3&gt;

&lt;p&gt;JSON Schema is not aware of metadata like URLs or HTTP methods as its designed to work with any JSON data instance. In API land the JSON data instance we’re most likely to work with is the HTTP request body or the response body.&lt;/p&gt;

&lt;p&gt;For example purposes we are gonna make some JSON Schema validation happen in Node.js, but you can use any language that has a &lt;a href="https://json-schema.org/implementations.html#validators"&gt;JSON Schema Validator&lt;/a&gt; (which is most of them).&lt;/p&gt;

&lt;p&gt;To use JSON Schema for server-side validation, you normally just grab one of the validators, shove it in your controller, or “routing” or whatever your language/framework of choice calls it. Using &lt;a href="https://expressjs.com/"&gt;Express.js&lt;/a&gt;, we can put this logic in our route.&lt;/p&gt;

&lt;p&gt;A fairly familiar app.js to Node users, we are just requiring a few bits of code, and loading the userSchema.&lt;/p&gt;

&lt;p&gt;That userSchema file comes from schemas/user.json which you can make locally, and will have contents like this:&lt;/p&gt;

&lt;p&gt;When you inspect the structure, you can infer that our JSON object has the following list of properties: name, email, and date_of_birth. The first two are strings, and the third is a date. Also, name is marked as required.&lt;/p&gt;

&lt;p&gt;Now we can run this Node app with node app.js and fire HTTP requests at it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ http -v PUT http://localhost:3000/123 name=Frank

HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 14
Content-Type: text/html; charset=utf-8
Date: Sat, 25 May 2019 08:09:10 GMT
ETag: W/"e-4o7E1rWH1O+7xJOCXIMFqIbMSxE"
X-Powered-By: Express

that was great
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Ok it liked that because name was set but email and date_of_birth are optional. Let's try sending them, but bad.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ http -v PUT http://localhost:3000/123 name=Frank email=notanemail

HTTP/1.1 400 Bad Request
Connection: keep-alive
Content-Length: 164
Content-Type: application/json; charset=utf-8
X-Powered-By: Express

{
 "errors": [
 {
 "dataPath": ".email",
 "keyword": "format",
 "message": "should match format \"email\"",
 "params": {
 "format": "email"
 },
 "schemaPath": "#/properties/email/format"
 }
 ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Oh no! Some errors happened. Sorry!&lt;/p&gt;

&lt;p&gt;These errors are not the best format because we just dumped them out for demo purposes, but this can be tidied up with a simple helper.&lt;/p&gt;

&lt;p&gt;If you were already doing validation in the controller, then your controller should be a lot cleaner, and if you are doing extensive validation in your model then this will remove a lot of the cruft. If you did not have validation before, then using this approach means you don’t need to start writing it. Win win win!&lt;/p&gt;

&lt;p&gt;Also, whilst this works in any language, Ruby folks using Rack (therefore anyone using Rails too) can use &lt;a href="https://github.com/interagent/committee"&gt;committee&lt;/a&gt;, a fantastic middleware for making this a bit easier.&lt;/p&gt;

&lt;p&gt;JSON Schema is pretty good at handling request body validation, but having to put this in every controller can be a bit annoying. OpenAPI can help us out here.&lt;/p&gt;

&lt;h3&gt;
  
  
  OpenAPI Middleware Example
&lt;/h3&gt;

&lt;p&gt;OpenAPI can be a bit easier to implement here, due to it covering the service model too, not just the data model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openapi: "3.0.0"
# ... snip ...
paths:
 /pets:
 post:
 description: Creates a new pet in the store
 operationId: addPet
 requestBody:
 description: Pet to add to the store
 required: true
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/NewPet'
 responses:
 '200':
 description: pet response
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/Pet'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Seeing as OpenAPI will say “this schema should be used for this combination or HTTP Method and Path” you do not need to provide the glue. Instead, many languages offer tools that let you just register a middleware, tell that middleware which OpenAPI file to use, then job done.&lt;/p&gt;

&lt;p&gt;Sticking with Node/Express for the examples, let’s take a look at using OpenAPI and registering a middleware:&lt;/p&gt;

&lt;p&gt;Tadaaa! You don’t have to put the validation checks in all the routes, because the middleware can handle that for you, and your route/controller code won’t even bother getting invoked if the request coming in is invalid. The framework middleware is able to look at the request, compare it to the API descriptions, and reject it with an error format (hopefully something like &lt;a href="https://tools.ietf.org/html/rfc7807"&gt;RFC 7807&lt;/a&gt;) before your code even needs to wake up.&lt;/p&gt;

&lt;p&gt;There are a decent number of options out there, but there should be more:&lt;/p&gt;

&lt;p&gt;For OpenAPI v3.0:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PHP:&lt;/strong&gt; &lt;a href="https://github.com/lezhnev74/openapi-psr7-validator"&gt;openapi-psr7-validator&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node.js:&lt;/strong&gt; &lt;a href="https://github.com/Zooz/express-ajv-swagger-validation"&gt;express-swagger-ajv-validator&lt;/a&gt; / &lt;a href="https://github.com/Hilzu/express-openapi-validate"&gt;express-openapi-validate&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ruby/Rails:&lt;/strong&gt; &lt;a href="https://github.com/interagent/committee"&gt;committee&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Perl:&lt;/strong&gt; &lt;a href="https://metacpan.org/pod/Mojolicious::Plugin::OpenAPI"&gt;Mojolicious::Plugin::OpenAPI&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For OpenAPI v2.0:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rails:&lt;/strong&gt; &lt;a href="https://github.com/amcaplan/swagger_shield"&gt;swagger_shield&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Rails tool swagger_shield is great. It wins maximum “Wont Hate Points” for using RFC 7807 on failure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
 "errors": [
 {
 "status": "422",
 "detail": "The property '#/widget/price' of type string did not match the following type: integer",
 "source": {
 "pointer": "#/widget/price"
 }
 }
 ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Some Validation Still Required
&lt;/h3&gt;

&lt;p&gt;This is only going to handle validation rules which do not require looking in a data store, or need some other sort of programming to run. You can do rather a lot with JSON Schema or OpenAPI, but it cannot tell you if the email address is valid, or if this resource is generally in the right state to be doing the thing you are trying to do.&lt;/p&gt;

&lt;p&gt;Not a problem. You can still perform your own checks after this validation is done, and because everything is all &lt;a href="https://www.apisyouwonthate.com/blog/server-side-validation-with-api-descriptions/"&gt;using RFC 7807&lt;/a&gt; the whole way through then your code and the middleware and everything else will all match. Lovely!&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing Benefits
&lt;/h3&gt;

&lt;p&gt;There are two huge benefits we have not quite got to yet, beyond the time and money saved from not having to write out a bunch of validation code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;The whole idea of trying to&lt;/em&gt;&lt;/strong&gt; &lt;a href="https://www.apisyouwonthate.com/blog/keeping-documentation-honest"&gt;&lt;strong&gt;&lt;em&gt;keep docs in sync with code&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;&lt;em&gt;goes out the window when your description documents are literally code.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Seeing as you are using the same description documents to handle request validation that you are using for your documentation, mock server, etc, there is no need for extra logic to ensure your requests are correctly described (or documented). You can just do your usual integration testing on requests, and you are all set.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expect(goodApple).to.be.jsonSchema(fruitSchema);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Your test suite handling bog standard unit and integration tests are now proving your documented requests are correct, and if somebody changes how requests work without updating the description docs, they’ve been caught in the act and their pull requests will fail. If they update the description in the pull request to fix the tests, boom, we can now have a little chat about why they just tried to commit a breaking change…! 🧐&lt;/p&gt;

&lt;p&gt;Using description docs for validations only covers requests, so &lt;a href="https://www.apisyouwonthate.com/blog/tricking-colleagues-into-writing-documentation-via-contract-testing"&gt;use the API description document to power contract testing&lt;/a&gt; to make sure responses are good too.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.apisyouwonthate.com/tricking-colleagues-into-writing-documentation-via-contract-testing-206308b47e05"&gt;Tricking Colleagues into Writing Documentation via Contract Testing&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Future of Server-Side Validation
&lt;/h3&gt;

&lt;p&gt;This is a very old concept which has recently picked up steam as more developers catch onto the API Design-first workflow.&lt;/p&gt;

&lt;p&gt;One of the benefits of writing HTTP APIs is that you usually are not locked into a single implementation, and do not have to try and force the “one size fits all” tooling that comes with it. Sadly that means some of the tools for some of the languages aren’t as excellent as others, but as we are a community of open-source developers we can fix that.&lt;/p&gt;

&lt;p&gt;I’ve heard developers say “this is not performant” but there is no reason to believe that. A specific tool might not be written the most efficient way, but that can be fixed with PRs. So long as the tool is not parsing the entire document on the fly, and on startup constructs some sort of artifacts in memory, this could easily be more performant than running whatever behemoth of a “validation library” you’ve loaded up to do all this manually.&lt;/p&gt;

&lt;p&gt;Another approach is to skip out on doing it in the server-side, and move it up a level: to the API Gateway. We’ll be writing more about that soon, but most API gateways are starting to get smarter about how they accept API descriptions as input, and how they use that input.&lt;/p&gt;

&lt;p&gt;One example is &lt;a href="https://www.express-gateway.io/"&gt;Express Gateway&lt;/a&gt;, who &lt;a href="https://www.express-gateway.io/docs/policies/customization/conditions/#json-schema"&gt;added JSON Schema Validation&lt;/a&gt;, a project maintained by my friend and &lt;a href="https://stoplight.io/"&gt;Stoplight.io&lt;/a&gt; colleague &lt;a href="https://twitter.com/D3DVincent"&gt;Vincenzo Chianese&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;The days of treating descriptions like some annoying thing you have to do later to get docs are long behind us. API descriptions now come first, are used for &lt;a href="https://www.apisyouwonthate.com/blog/tricking-colleagues-into-writing-documentation-via-contract-testing"&gt;contract testing&lt;/a&gt;, getting feedback on implementation, and a whole &lt;a href="https://www.toptal.com/api-developers/5-new-things-rest-specification"&gt;bunch of other stuff&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Use this as another carrot to convince your laggard teammates or boss that this is the way to go.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lzK3vb3S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AgJBqIwe1FYx3iO1DONgJIQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lzK3vb3S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AgJBqIwe1FYx3iO1DONgJIQ.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;




</description>
      <category>openapi</category>
      <category>jsonschema</category>
      <category>api</category>
      <category>apidesign</category>
    </item>
  </channel>
</rss>
