Search code examples
haskellyesodelmghcjs

Yesod - shared types between server and client


I'm used to working with Dart, where sharing types between server and client is as simple as importing the relevant packages into your project.

Can something similar be accomplished with Yesod/Haskell? Should I use GHCJS for the client? Maybe Elm? The goal is not having to worry about the data getting mangled in transit between server and client - and also not having to write a single line of JS. :o)

I haven't been able to find any good, beginner friendly docs on how to best tackle this challenge using Haskell. I suspect I just haven't looked in the right places. Any and all help is more than welcome.


Solution

  • To achieve this with GHCJS you can just build your project out of three core packages in this fashion:

    • frontend - something based on ghcjs-dom, I like Reflex-dom
    • backend - use your favorite framework, I like Snap, Yesod should work just the same
    • shared - code shared between frontend and backend

    Where frontend and backend both depend on shared of course. Frontend is compiled with GHCJS, backend with GHC.

    If you would like to see a complete example I would highly recommend studying hsnippet. Take a look at WsApi.hs where a set of up and downstream messages is being defined. All the JSON instances are derived in one place and imported in both frontend and backend.

    Hsnippet uses websockets. This is not a requirement of course. You could use regular XHR in your own app. The principle stays the same. You define your API and serialization instances (usually JSON) in the shared package and import the relevant modules in both frontend and backend.

    Personally I also share validation code, database entity definitions generated with persistent etc. Once you set it up sharing additional stuff is mostly a copy paste to one of the shared modules and then import wherever.