Schema for REST services

September 11, 2008

Join my mailing list…

I'm currently working the integration API for Gliffy, which is a REST-based service. The API is fairly stable and we're readying a few ancillary things for release. One of those is the documentation for the API. I found it quite difficult to completely describe the REST services and ultimately ended up creating something that lists out "objects" and "methods", even though the API is not really object-based. For example, the object "Diagram" has a "method" called "list"; to "call" it, you do an HTTP GET to accounts/your account name/diagrams.

The original spec I created to work against (and thus, our initial draft of API documentation) was basically a list of URLs and the HTTP methods they responded to. Not very easy to navigate or understand on a first sitting. Some sort of schema to describe the REST API would have been really helpful (along the lines of an XML Schema). Such a schema could facilitate documentation, testing, code generation.

As an example, consider some features of the Gliffy API: you can list the users in an account, list the diagrams in an account and reference an individual diagram via id. Here's a YAML-esque description of these services:

<b>accounts:</b>

  <b>kind:</b> literal

  <b>desc:</b> <i>"Reference to all accounts"</i>

  <b>POST:</b>

    <b>desc:</b> <i>"Creates a new account"</i>

    <b>parameters:</b>

        - account_name

            <b>required:</b> true

            <b>desc:</b> <i>"Name of the account you want to create"</i>

        - admin_email

            <b>required:</b> true

            <b>desc:</b> <i>"Email address of an administrator for the new account"</i>

  <b>children:</b>

     <b>account_name:</b>

       <b>kind:</b> variable

       <b>desc:</b> <i>"The name of your account"</i>

       <b>GET:</b>

         <b>desc:</b> <i>"Returns meta-data about the account"</i>

         <b>parameters:</b>

            - show_users

              <b>required:</b> false

              <b>desc:</b> <i>"If true, users are included, if false, they are not"</i>

       <b>children:</b>

         <b>diagrams:</b>

           <b>kind:</b> literal

           <b>desc:</b> <i>"All diagrams in the account"</i>

           <b>POST:</b>

             <b>desc:</b> <i>"Creates a new diagram"</i>

             <b>parameters:</b>

               - diagram_name

                 <b>required:</b> true

                 <b>desc:</b> <i>"Desired name for this diagram"</i>

               - template_id

                 <b>required:</b> false

                 <b>type:</b> numeric

                 <b>dsec:</b> <i>"If present, the id of the diagram to copy, instead of using the blank one"</i>

           <b>GET:</b>

             <b>desc:</b> <i>"Gets a list of all diagrams in this account"</i>

           <b>children:</b>

             <b>id:</b>

               <b>kind:</b> variable

               <b>type:</b> numeric

               desc <i>"The id of a particular diagram"</i>

               <b>GET:</b>

                 <b>desc:</b> <i>"Gets the diagram; the requested encoding type will determine the form"</i>

                 <b>parameters:</b>

                   - <b>version:</b> 

                     <b>desc:</b> <i>"The version to get, 1 is the original version.  If omitted, current version is retrieved"</i>

                     <b>required:</b> false

                     <b>type:</b> numeric

                   - <b>size:</b>

                     <b>desc:</b> "For rastered formats, determins the size

                     <b>type:</b> enumeration

                       - L

                       - M

                       - S

               <b>DELETE:</b>

                 <b>desc:</b> <i>"Deletes this image"</i>

          <b>users:</b>

            <b>kind:</b> literal

            <b>desc:</b> <i>"All users in the account"</i>

            <b>GET:</b>

              <b>desc:</b> <i>"gets a list of all users in the account"</i>
Since "accounts" is the only top-level element, we are saying that every request to this service must start with accounts/. It has one child, which is a variable value for the account name. It is untyped, so any potential string is allowed. That element has two possible children: diagrams and users. diagrams indicates that it responds to the HTTP methods POST and GET. A POST requires the parameter diagram_name, while the parameter version is optional.

A standard format like this could easily be used to generate documentation, expectations, test cases, and even stub code. This format could even be delivered by an OPTIONS call to a resource. I realize there is not much standardization around how to design and implement a REST service, but something like this could at least be a stake in the ground and support a specific method.