servant-hateoas: HATEOAS extension for servant

[ bsd3, hateoas, library, rest, servant, web ] [ Propose Tags ] [ Report a vulnerability ]

Create Resource-Representations for your types and make your API HATEOAS-compliant. Generic Resource-construction where possible, manual where ypu want.


[Skip to Readme]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

  • No Candidates
Versions [RSS] 0.1.0, 0.1.1, 0.2.0, 0.2.1
Change log CHANGELOG.md
Dependencies aeson (>=2.2.3 && <2.3), base (>=4.17.2 && <5), http-media (>=0.8.1 && <0.9), servant (>=0.20.2 && <0.21), servant-server (>=0.20.2 && <0.21) [details]
Tested with ghc ==9.4.8, ghc ==9.6.4, ghc ==9.8.2
License BSD-3-Clause
Copyright © 2024 Julian Bruder
Author Julian Bruder
Maintainer julian.bruder@outlook.com
Category Servant, Web, REST, HATEOAS
Uploaded by bruderj15 at 2024-10-25T13:38:49Z
Distributions
Downloads 48 total (48 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs uploaded by user
Build status unknown [no reports yet]

Readme for servant-hateoas-0.1.0

[back to package description]

Hackage Static Badge Haskell-CI

servant-hateoas

HATEOAS support for servant.

State

This is not affiliated with the official servant maintainers.

Currently in infant state. Final goal is something similar to what has been proposed here.

What can we do already?

Define an instance for class ToResource ct api a where ct is the Content-Type, a is the datatype you want to have a resty Api for and api is the type of your Servant-Api within which the resty representation of your datatype a lives.

When providing some extra information with an instance for Related a we can derive related links.

Example

data User = User { usrId :: Int, addressId :: Int, income :: Double }
  deriving stock (Generic, Show, Eq, Ord)
  deriving anyclass ToJSON

data Address = Address { addrId :: Int, street :: String, number :: Int}
  deriving stock (Generic, Show, Eq, Ord)
  deriving anyclass ToJSON

type CompleteApi = AddressApi :<|> UserApi

type AddressApi = AddressGetOne
type AddressGetOne = "address" :> Capture "id" Int :> Get '[HAL JSON] (HALResource Address)

type UserApi = UserGetOne :<|> UserGetAll
type UserGetOne = "user" :> Capture "id" Int :> Get '[HAL JSON] (HALResource User)
type UserGetAll = "user" :> Get '[HAL JSON] (HALResource [User])

instance Related User where
  type IdSelName User      = "usrId"              -- This is type-safe because of using class HasField
  type GetOneApi User      = UserGetOne
  type CollectionName User = "users"
  type Relations User      =
    '[ 'HRel "address" "addressId" AddressGetOne  -- Also type-safe
     ]
>>> mimeRender (Proxy @JSON) $ toResource (Proxy @(HAL JSON)) (Proxy @CompleteApi) $ User 1 100 100000
{
  "_links": {
    "address": {
      "href": "address/100"
    },
    "self": {
      "href": "user/1"
    }
  },
  "addressId": 100,
  "income": 100000,
  "usrId": 1
}

Goals

  • Deriving links where possible
  • Deriving links for paging, ...
  • Type-level rewriting of APIs like CompleteAPI to make API HATEOAS-compliant

Media-Types

Currently we only serve Content-Type application/hal+json. Support for others such as application/vnd.collection+json or application/vnd.amundsen-uber+json can easily be added with instances for Accept and MimeRender.

Client usage with MimeUnrender is not yet supported but easily extensible.