servant-zeppelin alternatives and similar packages
Based on the "servant" category.
Alternatively, view servant-zeppelin alternatives based on common mentions on social networks and blogs.
-
servant
Main repository for the servant libraries — DSL for describing, serving, querying, mocking, documenting web applications and more! -
servant-elm
Automatically derive Elm functions to query servant webservices -
servant-purescript
Translate servant API to purescript code, with the help of purescript-bridge. -
servant-swagger-ui
Provide embedded swagger UI for servant and swagger -
servant-response
Moved to http://github.com/haskell-servant -
servant-js
Automatically derive javascript functions to query servant webservices. -
servant-auth-cookie
Authentication via encrypted cookies -
servant-router
Servant router for non-server applications. -
servant-aeson-specs
Generically obtain tests for JSON serialization -
servant-github-webhook
Servant combinators for writing secure GitHub webhooks -
servant-pandoc
Render a servant API to Pandoc's native representation -
servant-cli
Generate a command line client from a servant API -
servant-pagination
Type-safe pagination for Servant APIs -
servant-mock
Derive a mock server for free from your servant API types -
servant-matrix-param
Matrix parameter combinator for servant -
servant-auth-token-acid
Servant based API and server for token based authorisation -
servant-auth-token-leveldb
Servant based API and server for token based authorisation -
servant-jsonrpc
Tools to build JSON-RPC clients and servers the Servant way -
servant-reason
Automatically derive bindings for Servant APIs in Reason -
servant-zeppelin-client
Server Side Loading JSON -
servant-kotlin
Automatically derive Kotlin functions to query servant webservices -
servant-http2-client
Generate http2-client from Servant APIs -
servant-ruby
Create a Ruby client from a Servant API using Net::HTTP. -
servant-match
Standalone implementation of servant’s dispatching mechanism -
servant-options
Provide responses to OPTIONS requests for Servant applications. -
servant-generate
Generate default implementations for servers in a flexible way (a.k.a servant-mock on steroids) -
servant-proto-lens
Servant Content-Type for proto-lens protobuf modules. -
servant-haxl-client
automatical derivation of querying functions for servant webservices -
servant-multipart
multipart/form-data (e.g file upload) support for servant -
servant-jsonrpc-client
Generate JSON-RPC servant clients
Access the most powerful time series database as a service
Do you think we are missing an alternative of servant-zeppelin or a related project?
README
servant-zeppelin 
Server Side Loading JSON
Overview
The point of servant-zeppelin is to enable server side loading of JSON data without having to write boilerplate.
Take the following Album
datatype for example, which is expanded in greater detail in the tests:
data Album =
Album { albumId :: AlbumId
, albumName :: String
, albumOwner :: PersonId
, albumPhotos :: [PhotoId]
}
It's often the case that we have such a datatype which carries foreign keys to other data, for example PersonId
and PhotoId
. The client application would probably not be able to do anything useful with the JSON response for Album
without making additional requests to the server to fetch more data about the album owner or photos. At the same time, it might not be worth the effort for the server to implement a new data type representing the join of Album
and Person
, or even worse all O(2n) possible combinations of dependencies. We introduce a new servant combinator to capture what we call Inflatable
data, meaning that there is a way to expand the data in some context. For example, if the above Album
is represented by a row in a postgres table, we probably already have functions laying around like
getPersonById :: PersonId -> PGMonad Person
getPersonById = ...
getPhotosByIds :: [PhotoId] -> PGMonad [Photo]
getPhotosByIds = ...
We can use these functions to implement our Inflatable
typeclass, e.g.
instance Inflatable PGMonad PersonId where
type Full PGMonad PersonId = Person
inflator = getPersonById
and similarly for [PhotoId]
. We can then indicate that Album
has dependencies on these datatypes like this:
instance HasDependencies Album '[PersonId, [PhotoId]] where
getDependencies album = albumOwner album &: albumPhotos album &: NilDeps
This gives us access to a new servant combinator SideLoad (deps :: [*])
which can be used at the end of a typed route in the following way:
...
:<|> Capture "album" AlbumId :> Get '[PlainText, JSON] Album :> SideLoad '[Person, [Photo]]
...
The semantics are similar to QueryFlag
-- the presence of the keyword sideload
in the query params, or the key value pair sideload=true
or sideload=1
, will trigger a response with the additional sideloaded data if the desired content type is application/json
. The absence of this flag returns the normal JSON
serialization. If the desired content type was PlainText
in this example, nothing out of the ordinary happens.
Here is an example of the different responses:
{
"albumId": 1,
"albumPhotos": [
1,
2
],
"albumName": "Vacations",
"albumOwner": 1
}
{
"data": {
"albumId": 1,
"albumPhotos": [
1,
2
],
"albumName": "Vacations",
"albumOwner": 1
},
"dependencies": {
"person": {
"personName": "Alice",
"personId": 1
},
"photos": [
{
"artistId": 1,
"photoCaption": "At the Beach.",
"photoId": 1
},
{
"artistId": 1,
"photoCaption": "At the Mountain.",
"photoId": 2
}
]
}
}
servant-zeppelin-server
Much of what was needed to understand the server component was explained above. In order to get the ToJSON
instances for your sideloaded data, it's sufficient to have ToJSON
instance for all the components and that the components of the dependencies are instances of a type family called NamedDependency
. More concretely, in the above example we would need
instance ToJSON Person
type instance NamedDependency = "person"
instance ToJSON [Photo]
type instance NamedDependency = "photos"
instance ToJSON Album
in order to derive the instance ToJSON (SideLoaded Album '[Person, [Photo]])
, which is sufficient to support the route.
The second component which was needed is a way to transfer the context of the inflation to servant's Handler
monad. Concretely, if our PGMonad
above was newtyped around something like ReaderT Connection (ExceptT QueryError IO)
, we need to provide a natural transformation of type PGMonad :~> Handler
to the Context
when we define our application. In principle it might happen that you use different contexts for different datatypes, for example if you were maintaining two seprate databases. This is ok as long as you provide both transformations to the Context
. You can see the tests for more details.
servant-zeppelin-swagger
In order to have the swagger docs generate for an endpoing using the ... a :> SideLoad deps
combinator, we need to have a ToSchema
instance for SideLoaded a deps
. The will be automatically derived for you with sensible choices proveded that you have a ToSchema
instance for both a
and every d
in deps
. With swagger, a picture is worth more than code, but you can see the tests for how to generate this:
servant-zeppelin-client
We also provide a HasClient
instance for the SideLoad deps
combinator, though it behaves a little bit differenty than most HasClient
instances you might have encountered so far. The problem is that a real HasClient
instance is dependently typed-- if you give me sideload=true
param, I exepect the sideloaded data of type SideLoaded a deps
, and if it's not there I expect something of type a
. In order to get around the type systems limitations, the HasClient
instance provides us with a dependently typed function which takes a singleton boolean to get the desired type.
Also, the client has a bias for using requesting JSON-- this seems fair to me because there is yet no reason to use a SideLoad
combinator on a route without JSON as a valid mime type. The necessary FromJSON
instances are supplied in the client lib as well, and as usual they can be automatically derived so long as the components all have instances.
The client library also exposes a typeclass ProjectDependency
implementing a single method projectDependency
. This has the same semantics as servant's HasContext
typeclass, and can be useful to get data out of a side loaded response.
Again, see the tests for examples.