dnsimple / dnsimple-developer

The DNSimple API Documentation.
https://developer.dnsimple.com/
35 stars 40 forks source link

Request: JSON Schema for API v2 #126

Closed 3flex closed 6 years ago

3flex commented 7 years ago

Now v2 is GA and the API is stable, it would be great to enhance the documentation a bit.

In many cases it's unclear whether a returned value could be null or not, and the type of data returned is not specified. It can be inferred from the example fixture, but they don't cover all cases - for example, on the Zone Records page you need to look at a couple of fixtures to know that priority is expected to be either an integer or null.

JSON Schema seems like a logical way to document these and something than is both human and machine readable. While this could be specified for GET, POST and PATCH requests, I think it's most valuable for GET, since the inputs for POST and PATCH are already well defined in the documentation.

There are lots of ways to play with this, but at a minimum I'd want to see definitions for each of the possible return types (like a zone record, a domain, etc).

For a zone record, it would be something like:

{
  "$schema":"http://json-schema.org/draft-04/schema#",
  "type":"object",
  "oneOf":[
    {
      "properties":{
        "type":{
          "enum":[
            "MX"
          ]
        },
        "priority":{
          "type":"integer"
        }
      }
    },
    {
      "properties":{
        "type":{
          "not":{
            "enum":[
              "MX"
            ]
          }
        },
        "priority":{
          "type":"null"
        }
      }
    }
  ],
  "properties":{
    "type":{
      "type":"string"
    },
    "priority":{
      "type":[
        "null",
        "integer"
      ]
    },
    "id":{
      "type":"integer"
    },
    "zone_id":{
      "type":"string"
    },
    "parent_id":{
      "type":[
        "string",
        "null"
      ]
    },
    "name":{
      "type":"string"
    },
    "content":{
      "type":"string"
    },
    "ttl":{
      "type":"integer"
    },
    "regions":{
      "type":"array",
      "minItems":1,
      "uniqueItems":true,
      "oneOf":[
        {
          "items":{
            "enum":[
              "SV1",
              "ORD",
              "IAD",
              "AMS",
              "TKO"
            ]
          }
        },
        {
          "items":{
            "enum":[
              "global"
            ]
          }
        }
      ]
    },
    "system_record":{
      "type":"boolean"
    },
    "created_at":{
      "type":"string",
      "format":"date-time"
    },
    "updated_at":{
      "type":"string",
      "format":"date-time"
    }
  }
}

A reasonably strict example for "List records for a zone" endpoint might look like this (this is valid), but doing this for every endpoint is a more tedious task that coming up with schemas for the objects themselves:

{
  "$schema":"http://json-schema.org/draft-04/schema#",
  "type":"object",
  "properties":{
    "data":{
      "type":"array",
      "items":{
        "$ref":"#/definitions/zone_record"
      }
    },
    "pagination":{
      "$ref":"#/definitions/pagination"
    }
  },
  "definitions":{
    "zone_record":{
      "oneOf":[
        {
          "properties":{
            "type":{
              "enum":[
                "MX"
              ]
            },
            "priority":{
              "type":"integer"
            }
          }
        },
        {
          "properties":{
            "type":{
              "not":{
                "enum":[
                  "MX"
                ]
              }
            },
            "priority":{
              "type":"null"
            }
          }
        }
      ],
      "type":"object",
      "properties":{
        "type":{
          "type":"string"
        },
        "priority":{
          "type":[
            "null",
            "integer"
          ]
        },
        "id":{
          "type":"integer"
        },
        "zone_id":{
          "type":"string"
        },
        "parent_id":{
          "type":[
            "string",
            "null"
          ]
        },
        "name":{
          "type":"string"
        },
        "content":{
          "type":"string"
        },
        "ttl":{
          "type":"integer"
        },
        "regions":{
          "type":"array",
          "minItems":1,
          "uniqueItems":true,
          "oneOf":[
            {
              "items":{
                "enum":[
                  "SV1",
                  "ORD",
                  "IAD",
                  "AMS",
                  "TKO"
                ]
              }
            },
            {
              "items":{
                "enum":[
                  "global"
                ]
              }
            }
          ]
        },
        "system_record":{
          "type":"boolean"
        },
        "created_at":{
          "type":"string",
          "format":"date-time"
        },
        "updated_at":{
          "type":"string",
          "format":"date-time"
        }
      }
    },
    "pagination":{
      "type":"object",
      "properties":{
        "current_page":{
          "type":"integer"
        },
        "per_page":{
          "type":"integer"
        },
        "total_entries":{
          "type":"integer"
        },
        "total_pages":{
          "type":"integer"
        }
      }
    }
  }
}
weppos commented 7 years ago

We originally had a RAML definition used internally, but we failed to maintain it. http://raml.org/

I still believe it is valuable to provide a sort of scheme for the API, I'm quite overwhelmed though by the number of possibilities and the lack of standardization.

3flex commented 7 years ago

Hadn't heard of RAML, but I see how this would be valuable as an internal development and design tool, though perhaps not as useful for end-users.

Some advantages of JSON Schema:

That said, it may be a lot of work for little gain.

The biggest gap I see in the docs is the lack of documentation on the possible return types, and what they represent (e.g. #121). JSON Schema's just one way to document this that seemed like it might be a good fit.

weppos commented 6 years ago

https://blog.dnsimple.com/2018/02/openapi/ 🎉

3flex commented 6 years ago

Fantastic! I saw the blog post but didn't think to close this.