Quantcast
Channel: Silk Engineering Blog
Viewing all articles
Browse latest Browse all 32

A RESTful API with automatically generated bindings

$
0
0

Silk is mainly built on two languages: Haskell and Javascript. We use Haskell for our back-end to get a stable, type-checked core and Javascript to bring the content to our users. While both these languages are high-level programming languages, the communication via the web forces us to write much lower-level HTTP requests and marshaling code. At Silk, we make an effort to avoid writing low-level code manually. A previous result of this are our generic XML/JSON picklers as described in this previous post. Since then we have not been idle and we took the code automation one step further: We now generate our documentation and Javascript wrappers directly from our own Haskell web-EDSL.

The benefits of this approach are obvious. Instead of having to update documentation and javascript wrappers on every web API change, these parts are always kept up to date and correct. This saves work and avoids errors.

The heart of this system is our Haskell web-API-EDSL. This system allows the programmer to define API resources in a declarative way together with the associated functionality. The EDSL forces the resources to be constructed in a RESTful way. The EDSL constructs an abstract representation of web resources, which we can then interpret to generate the following functionality:

  • We construct the actual web-API using Happstack. Because we kept the API abstract, we could easily switch out Happstack for another framework.
  • We generate documentation which gives an overview of what entry points the API has and what parameters/methods entry points can be called with.
  • We generate a javascript wrapper which simplifies access to the API resources.

All this is best illustrated with an example. We could for example define a User API resource in the following way:

user :: Resource Root WithUser User
user = mkResource 
  { identifier     = "user"
  , multiGetBy     = [ ("search",  search)  ]
  , singleGet      = [ ("current", current) ]
  , singleGetBy    = [ ("email",   byEmail) ]
  , singleCreate   = Just create
  , singleDelete   = Just delete
  }

We can bundle such resources into an API:

myApi = 
  api ---/ user --/ permissions
                --/ subscriptions
      ---/ site

This also shows that resources can be nested. We use a monad stack to allow child resources to access their parents’ context information. We could now request the permissions of a certain user by requesting the following URL:

/user/email/e@mail.com/permissions

This would list all permissions for the user with email adress e@mail.com. A sneak peek of what the documentation looks like for such URLs can be found here. All information on this page is automatically generated, including the examples and schemas for XML and JSON.

We could also access this resource using our Javascript API as follows:

silkApi.User.byEmail("e@mail.com).Permissions.list()

We are currently in the process of constructing similar wrappers for Ruby and Haskell. We are also working on finalizing the base EDSL and we plan to open source it in the near future.


Viewing all articles
Browse latest Browse all 32

Trending Articles