Content Type Bliss

Recently I came across Timo von Holtz’s servant-JuicyPixels package. It describes servant-compatible content-types for JuicyPixel’s DynamicImage data type, and clocks under 100 airy lines.

Timo and I realized there is a pretty neat demonstration of the advantage of abstracting away content-type serialization and deserialization: the world’s most concise image-conversion web service. Essentially the same application is available as the image conversion example in Timo’s package.

(If you want to know more about how content-types work in servant, the content-type section of the tutorial has more information.)

The Application

Our goal is to provide a service that converts images between formats based on the Content-Type and Accept headers of the request:

$ curl localhost:8001 -H "Content-Type: image/png"  \
                      -H "Accept: image/jpeg"  \
                      --data-binary "@haskell-logo.png" \
                      > haskell-logo.jpeg

To get there, we need to do a couple of things. We need to of course run the application:

main :: IO ()
main = run 8001 conversion

And describe the API:

type ConversionApi
     = ReqBody '[BMP, GIF, JPEG 50, PNG, TIFF, RADIANCE] DynamicImage
    :> Post '[BMP, GIF, JPEG 50, PNG, TIFF, RADIANCE] DynamicImage

As you can see, we state that we accept and can return a variety of image formats.

The application is then:

conversion :: Application
conversion = serve (Proxy :: Proxy ConversionApi) handler

And for the clincher, the handler:

    where handler = return

And that’s it!

Conclusion

This is just the limit of the relative gain of abstracting content-types - there is nothing to the application besides them!

Essentially the same idea could of course be applied to other areas. Document conversion with Pandoc, video and audio formats, etc.

Posted on August 5, 2015 by Julian K. Arni