Hello,
We have a PS codebase that makes use of a REST API and I was wondering if this can be more streamlined in Purescript. Currently what bothers me is the disassociation of URL and the data that is sent over.
match action with data
So in theory it’s possible that I have a bug like this:
fetchUsers :: Aff (Array User)
fetchUsers = get (url Teams)
Notice that I mistyped the Action. This compiles but results in bad AP requests.
I guess this was the reason to write the Swagger client library to automatically derive all this from the URL specification. I’m wondering whether something like this exists, given that (like I presume) PureScript is more widely used on the frontend side, i.e. as a client, and not for server code (where Haskell has a bigger ecosystem).
data Action a
= GetUsers (Users -> a)
| GetTeams (Teams -> a)
url :: ∀ a. Action a -> String
url =
case _ of
GetUsers _ -> "/users"
GetTeams _ -> "/teams"
get :: ∀ a. Action a -> Aff a
get action = makeRequest (url action)
fetchUsers :: Aff Users
fetchUsers = get (GetTeams identity) -- will error
You can take that a step further and make the definition of actions succinct (scroll to the end), at the cost of loads of fluff to assist it:
data ActionSpec resp path method as
= ActionSpec (as ~ (Proxy (ActionSpec resp path method)))
class (IsSymbol p) <= Path as p | as -> p
instance IsSymbol path => Path (Proxy (ActionSpec resp path method)) path
class Method as m | as -> m
instance Method (Proxy (ActionSpec resp path method)) method
class (SimpleJSON.ReadForeign r) <= Response as r | as -> r
instance SimpleJSON.ReadForeign resp => Response (Proxy (ActionSpec resp path method)) resp
class (Path as p, Method as m, Response as r) <= ActionSpec' as r p m | as -> r p m
instance
( Path as path
, Method as method
, Response as resp
) => ActionSpec' as resp path method
url :: ∀ as path. Path as path => Action as -> String
url _ = reflectSymbol (Proxy :: Proxy path)
getAction :: ∀ as path resp. ActionSpec' as resp path GET => Action as -> Aff resp
getAction action = get (url action)
data Action as
= GetUsers (ActionSpec Users "/users" GET as)
| GetTeams (ActionSpec Teams "/teams" GET as)
-- inferred: getUsers :: Aff Users
getUsers = getAction $ GetUsers (ActionSpec identity)