servant-hateoas

Create Resource-Representations for your types and make your API HATEOAS-compliant. Automatically derive a HATEOAS-API and server-implementation from your API or straight up define a HATEOAS-API yourself. Currently HAL+JSON is the only supported Content-Type. Work for further is on progress. For now only basic hypermedia-link derivations such as the self-link are automatically generated. Expect more sophisticated link-derivation e.g. for paging in the future. This library is highly experimental and subject to change.


Keywords
hateoas, library, rest, servant, web, Propose Tags, Report a vulnerability, Skip to Readme, Index, Quick Jump, Servant.Hateoas, Servant.Hateoas.ContentType.HAL, Servant.Hateoas.HasHandler, Servant.Hateoas.Internal.Polyvariadic, Servant.Hateoas.Internal.Sym, Servant.Hateoas.Layer, Servant.Hateoas.Layer.Build, Servant.Hateoas.Layer.Merge, Servant.Hateoas.Layer.Type, Servant.Hateoas.RelationLink, Servant.Hateoas.Resource, Servant.Hateoas.ResourceServer, servant-hateoas-0.3.0.tar.gz, browse, Package description, Package maintainers, bruderj15, edit package information , here, servant-pagination
License
BSD-3-Clause
Install
cabal install servant-hateoas-0.2.0

Documentation

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 api res a where api is the type of your Servant-Api within which the resty representation of your datatype a lives and res is the resource-representation to create.

When providing some extra information with an instance for Related a there are stock instances which derive the links based on the relations in your instance.

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 '[Collection JSON] (CollectionResource User)

instance Related User where
  type IdSelName User = "usrId"
  type GetOneApi User = UserGetOne
  type CollectionName User = "users"
  type Relations User =
    '[ 'HRel "address" "addressId" AddressGetOne
     ]
>>> mimeRender (Proxy @(HAL JSON)) $ toResource @CompleteApi @HALResource $ User 1 42 100000
{
  "_links": {
    "address": {
      "href": "address/42"
    },
    "self": {
      "href": "user/1"
    }
  },
  "addressId": 42,
  "income": 100000,
  "usrId": 1
}

Goals

  • Deriving simple links for self and relations
  • Deriving more complex links...?
  • Type-level rewriting of APIs like CompleteAPI to make API HATEOAS-compliant

Media-Types

  • application/hal+json
  • application/collection+json
  • application/hal-forms+json soon
  • Others: Maybe

Client usage with MimeUnrender is not yet supported.

Contact information

Contributions, critics and bug reports are welcome!

Please feel free to contact me through GitHub.