Skip to content

Latest commit

 

History

History
49 lines (42 loc) · 2.16 KB

README.md

File metadata and controls

49 lines (42 loc) · 2.16 KB

Servant ❤️ GDP

In a nutshell

To get more productive, produce high-quality web APIs and reduce the number of needed tests we can combine Servant (A web api framework) and GDP (Ghosts of Departed Proofs). This allows for quite expressive API declarations which leads to more knowledge captured. See a full example.

-- http://localhost/div/10/5 would return 2
type DivWebApi numerator denominator =
  "div"
    :> CaptureNamed (Int ~~ numerator 
                    ::: IsPositive numerator)
    :> CaptureNamed (Int ~~ denominator
                    ::: IsPositive denominator)
    :> Get
         '[JSON]
         ( Int ? IsEqualOrLessThan numerator
         )

or

-- http://localhost/habitats/savanna/animals/3
-- could return ["lion", "elephant"]
type GetAnimalsForHabitat user habitat pagesize =
  AuthProtect "normalUser"
    :> "habitats"
    :> CaptureNamed (String ~~ habitat ::: IsNonEmpty habitat && IsTrimmed habitat)
    :> "animals"
    :> CaptureNamed (Int ~~ pagesize ::: IsPositive pagesize)
    :> Get
         '[JSON]
         ( ( [String ? IsAValidatedAnimal habitat] ? HasAMaximumLengthOf pagesize
           )
             ::: user `HasAccessToHabitat` habitat
         )

See https://github.com/mtonnberg/gdp-demo for a full, working example.

How does it work

API-input is captured as named variables, making the named contexts span the entire request. This in turn, makes it possible to express a lot of domain knowledge/requirements in the Servant API type.

Why does this exist?

To both make the API-capabilities clearer and to make it easier to implement.

It is often quite easy to identify domain rules, invariants and preconditions for the API but hard to capture that knowledge in the types. Instead a lot of domain rules and requirements are hidden in the implementation logic.

Moving information to the types are in line with Knowledge-as-Code, read more about the benefits here: Knowledge-as-Code