Client Libraries in Haskell

Are there any best practices/guidelines/good examples of 3rd-party api client libraries in Haskell? I know we’re a proud people and less itchy for basically-a-thin-wrapper-around-http “SDK” libraries than other communities but there are still times when it’s nice to have auth/urls/payloads abstracted away, or at least hidden somewhat.

Say you’ve got an API that has multiple root urls (sandbox/prod, free/paid, etc.) and some OAuth(ish/-inspired) auth situation, with credentials that need to be renewed periodically, etc. Would it be more ergonomic/dev-friendly to have a wholly isolated newtype Api = Api { runApi :: ReaderT ApiSpecificConfig IO (Either ApiSpecificError ApiSpecificResult) }, or HasApiSpecificConfig typeclasses (and optics etc)/makeApiRequest :: HasApiSpecificConfig m, MonadIO m => ApiSpecificData -> m (Either ApiSpecificError ApiSpecificResult)? I just haven’t seen (m)any examples of this kind of thing floating around.

2 Likes

I often refer back to amazonka as an example of great API design. It uses both a concrete ReaderT type with all the instances, as well as classy lenses for accessing various parts of the state, handling exceptions etc.
It also uses type families to great effect for associating request and response types (https://hackage.haskell.org/package/amazonka-1.6.1/docs/Control-Monad-Trans-AWS.html#t:AWSRequest).

Edit: see e.g. here (https://hackage.haskell.org/package/amazonka-s3-1.6.1/docs/src/Network.AWS.S3.ListObjects.html#line-150) for an example instance of the AWSRequest typeclass: listing objects from an S3 bucket

3 Likes