Git Product home page Git Product logo

servant's Introduction

servant - A Type-Level Web DSL

servant

Getting Started

We have a tutorial that introduces the core features of servant. After this article, you should be able to write your first servant webservices, learning the rest from the haddocks' examples.

The core documentation can be found here. Other blog posts, videos and slides can be found on the website.

If you need help, drop by the IRC channel (#haskell-servant on libera.chat) or mailing list.

Contributing

See CONTRIBUTING.md

Release process outline (by phadej)

  • Update changelog and bump versions in master
    • git log --oneline v0.12.. | grep 'Merge pull request' is a good starting point (use correct previous release tag)
  • Create a release branch, e.g. release-0.13
    • Release branch is useful for backporting fixes from master
  • Smoke test in servant-universe
    • git submodule foreach git checkout master and git submodule foreach git pull to get newest of everything.
    • cabal new-build --enable-tests all to verify that everything builds, and cabal new-test all to run tests
      • It's a good idea to separate these steps, as tests often pass, if they compile :)
    • See cabal.project to selectively allow-newer
    • If some packages are broken, on your discretisation there are two options:
      • Fix them and make PRs: it's a good idea to test against older servant version too.
      • Temporarily comment out broken package
    • If you make a commit for servant-universe, you can use it as submodule in private projects to test even more
  • When ripples are cleared out:
    • git tag -s the release
    • git push --tags
    • cabal sdist and cabal upload

TechEmpower framework benchmarks

We develop and maintain the servant TFB entry in https://github.com/haskell-servant/FrameworkBenchmarks/

To verify (i.e. compile and test that it works)

./tfb --mode verify --test servant servant-beam servant-psql-simple --type json plaintext db fortune

To compare with warp

./tfb --mode benchmark --test warp servant servant-beam servant-psql-simple --type json plaintext db fortune

To compare with reitit (Clojure framework)

./tfb --mode benchmark --test reitit reitit-async reitit-jdbc servant servant-beam servant-psql-simple --type json plaintext db fortune

You can see the visualised results at https://www.techempower.com/benchmarks/#section=test

Nix

A developer shell.nix file is provided in the nix directory

See nix/README.md

servant's People

Contributors

akhesacaro avatar alpmestan avatar arianvp avatar christian-marie avatar codedmart avatar davecturner avatar declension avatar dependabot[bot] avatar dlarsson avatar domenkozar avatar dredozubov avatar erewok avatar felixonmars avatar fisx avatar fizruk avatar freezeboy avatar gbaz avatar ivan-m avatar jkarni avatar jml avatar kosmikus avatar maksbotan avatar mangoiv avatar maxow avatar mbg avatar phadej avatar soenkehahn avatar tchoutri avatar thsutton avatar ysangkok avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

servant's Issues

Parsing request body mulitple times behaves oddly.

Consider the routing table:

type Routes =
  ...
  :<|> ReqBody User :> Post UserID
  :<|> Capture "userid" UserID :> ReqBody User :> Put ()
  ...

The first route fails for Put requests, but the second will find that
the request body has already been parsed, and will complain about ""
not being a parseable json representation of User.

The work-around is simple:

type Routes =
  ...
  :<|> Capture "userid" UserID :> ReqBody User :> Put ()
  :<|> ReqBody User :> Post UserID
  ...

But I'm not sure it is that simple in all cases, or that obvious to
understand the situation once you've stumbled into this trap.

We have some (limited) resources to work on a solution, but we would
like to hear what you think first.

Servant is AWwesome, btw. Thanks for writing it! (:

Bidirectionalization

A lot of the lower-level functionality that is used to construct HasServer and HasClient instances (at least) are strongly related (often functions come in inverses). For example, getting a header and adding a header, or reading a body and returning a body. Writing functions for both is tedious and error-prone - not just for library maintainers, but also for users who might want to write a new combinator. This seems like a good candidate for availing ourselves of the bidirectionalization literature.

Ideally, we should be able to write an instance of a single class, and HasServer and HasClient come for free from that instance.

Please add any thoughts or ideas as a comment.

Overlapping names

From @seanhess on April 16, 2015 17:44

Servant is using the same name getsources for both GET /sources and GET /sources/:id. Is there some way it could figure out to call the second one getsource?

type Api = "sources" :> Get [Source] :<|> "sources" :> Capture "id" Text :> Get (Source)

Copied from original issue: haskell-servant/servant-jquery#13

Cookie Combinator

I'm using JWTs for auth. I'm implementing the logic by hand, which is fine for now, but it is slightly more convenient to have a Cookie combinator so I don't have to parse the header by hand.

Here's an example. It works exactly like Header, doesn't assume anything about authentication, it just provides a cookie value to your code.

https://gist.github.com/seanhess/f4cf71ea58e4483d8ee4

Is there a place for a low-level Cookie combinator like this? I think it could live side-by-side with higher-level authentication code. If so I'd be happy to clean this up and issue a PR.

Sporadic test failures

Looks like some of the fromByteString/toByteString and Text tests sometimes fail (empty input, and very very small floats).

serveDocumentation should be exported if it's mentioned.

From @christian-marie on April 4, 2015 2:32

serveDocumentation is mentioned in the documentation for the Raw combinator, but the link goes nowhere. Some commented-out code can be found in Docs.hs, but that code doesn't seem to work (as far as I remember, due to targeting an old WAI version). The ToHTML is function it provides is a little silly too.

This works well: https://hackage.haskell.org/package/markdown

If we don't want to wear the dependencies of that package in servant-docs, perhaps it's time for a servant-extras package? It'd be nice to ship batteries included and export a function for such a useful use case.

Alternately we can just fix the docs to provide an up-to-date example in-line with Raw (the fact that it links to non-existent documentation is the most confusing..

Copied from original issue: haskell-servant/servant-server#36

Instrument other monads

From @jkarni on April 19, 2015 10:45

https://gist.github.com/rschatz/3c0ebd3cbf319c8061a6 shows how we could do this, though I think we could come up with a variation of HandlerT that takes a variable number of arguments (not just one) and thus make e.g. enter-ing from Either (Int,String) a not require a dummy () argument, and things that require multiple arguments not have to be curried.

This also would include the appropriate instances for common mtl/tranformers monads.

Copied from original issue: haskell-servant/servant-server#43

Authentication

Hi everyone!

I thought I'd open up an issue to act as a container for authentication-related discussion. The issue will be considered closed when the first iteration of authentication has been implemented, at which point further improvements will have their own issues.

Authentication

We want to support various types of authentication for http servers and clients:

Further, we want to account for the following (not a total list):

  • maintain type-safety as per servant's design goals, but also allow for flexibility of various authentication methods and protocols (both standardized and not standardized).
  • per-realm authentication
  • per-endpoint or site-wide authentication

Out of scope for this iteration (but worth thinking about):

  • role-based authentication

References:

I welcome any thoughts, ideas, or suggestions! I will be creating an auth branch to feature work and will let everyone know when that's done.

Test suite missing modules

Resolving dependencies...
Configuring servant-client-0.4.0...
Building servant-client-0.4.0...
Preprocessing library servant-client-0.4.0...
[1 of 3] Compiling Servant.Common.BaseUrl ( src/Servant/Common/BaseUrl.hs, dist/build/Servant/Common/BaseUrl.o )
[2 of 3] Compiling Servant.Common.Req ( src/Servant/Common/Req.hs, dist/build/Servant/Common/Req.o )
[3 of 3] Compiling Servant.Client   ( src/Servant/Client.hs, dist/build/Servant/Client.o )
In-place registering servant-client-0.4.0...
Preprocessing test suite 'spec' for servant-client-0.4.0...

test/Spec.hs:1:8:
    Could not find module ‘Servant.ClientSpec’
    Perhaps you meant
      Servant.Client (needs flag -package-key servant-client-0.4.0@serva_JSTqdDtJ1hWEvU0Dj4ZDIR)
      Servant.Client (from servant-client-0.4.0@serva_6VXrsrfyUXEJrNxZS1Cd6A)
    Use -v to see a list of the files searched for.

Allow failures in arbitrary order

This is something we've discussed quite a bit before, but I just realized there's no ticket for it. We're stuck in this position where failures (from failWith) happen without trying matches further down the :> chain, resulting in some bad error messages (e.g. Bad Request instead of Method Not Found), hard to implement authentication ( #70 ), and inefficiency (it's better not to try decoding a body if there's no matching route anyhow).

This relates to #48. It also likely relates to improved routing.

Design issues

Do we want only the leaves of the tree (the methods) to be able to adjudicate error messages? Or do we want combinator instances to be allowed (but not required) to adjudicate between failure and continuation as well? I think the former would be sufficient to conform to the behaviour of most frameworks, but the second may also allow for room for interesting possibilities (what comes to mind immediately is auth-protecting a set of endpoints without even allowing non-authenticated clients to figure out what the endpoints being protected are - not a crucial feature, but also almost certainly not the only one).

Implementation ideas

?

Include Request Combinator?

From @davidsd on April 4, 2015 0:46

Occasionally, I need access the underlying WAI Request in a handler. It might make sense to include a combinator FullRequest that gives access to this information. For instance, if I need remoteAddr, then instead of making a specialized RemoteAddr combinator (and another combinator for everything else I need), I can just get it from the Request. One might argue that this slightly breaks servant's abstraction, but having it seems like a useful middle ground between a servant handler and a full WAI Application. A possible implementation is

data FullRequest

instance HasServer a => HasServer (FullRequest :> a) where
  type Server (FullRequest :> a) = Request -> Server a
  route Proxy subserver request respond =
      route (Proxy :: Proxy a) (subserver request) request respond

Copied from original issue: haskell-servant/servant-server#35

Question: Add table of contents?

From @paf31 on January 22, 2015 18:47

Would you accept a PR to add a table of contents to the generated markdown?

I'm using servant for a medium sized project, and it would be nice if I could group docs into categories based on the tree of routes. I expect I would probably include a change in this PR to introduce a tree as an intermediate data structure.

Maybe we could even structure the markdown as a tree using nested lists, so that related routes appear in the same list. This would also allow me (later) to add a documentation string to every branch (subroute) in the tree.

Thanks.

Copied from original issue: haskell-servant/servant-docs#8

Validation of request body

At the time of writing the payload of the ReqBody a type needs to have an instance of FromJSON. As I want to perform possibly complex validation (with database accesses etc.) so no invalid data can be constructed. My validation function has the form MonadIO m => Value -> m (Either Object a). Is it possible to build such a combinator?

Versioning 0.4 vs. 0.4.0

Hei, is there a reason that servant-docs is 0.4, while servant-server and servnat are 0.4.0?

0.4! I'm so excited... (-:

Handlers can return an error response body

From @thsutton on February 20, 2015 0:14

Currently the (Int, String) values represent an HTTP status only (i.e. the status code and reason phrase used in the HTTP response status line). It would be nice if servant handlers could supply a body to send to the client when they use throwError.

Alternatively, we could allow handlers to specify an HTTP status code and reason when they succeed, as well as fail.

This would make it possible to implement APIs like, for example, OAuth2 which issues 400 Bad Request responses which include a JSON document describing the specific error.

Copied from original issue: haskell-servant/servant-server#27

API Blueprint

From @AndrewRademacher on March 25, 2015 14:44

Has there been any consideration for writing servant docs output in API Blueprint format 1A?

Copied from original issue: haskell-servant/servant-docs#17

servant-server-0.4.0 broken by API change in system-filepath

Citing from http://hydra.cryp.to/build/841883/nixlog/1/raw:

src/Servant/Utils/StaticFiles.hs:36:41:
    Couldn't match type ‘system-filepath-0.4.13.4:Filesystem.Path.Internal.FilePath’
                   with ‘[Char]’
    Expected type: FilePath
      Actual type: system-filepath-0.4.13.4:Filesystem.Path.Internal.FilePath
    In the first argument of ‘defaultFileServerSettings’, namely
      ‘(decodeString (documentRoot ++ "/"))’
    In the first argument of ‘staticApp’, namely
      ‘(defaultFileServerSettings (decodeString (documentRoot ++ "/")))’

Make Canonicalize optional

As Andres noted, Canonicalize breaks modularity. It shouldn't be the default behaviour. Moreover, we should add something like Unit to prevent it from traversing into specific types.

Canonicalize should also be named something else (maybe Distribute) since now it's no longer the canonical form (there isn't one), and it really just applies one transformation.

Defining function rendering settings

From @rtrvrtg on January 22, 2015 1:2

I was wondering if there are any plans to change the way that servant-jquery's Javascript wrapper functions get rendered. Currently, they're all rendered like so:

function getsomething(onSuccess, onError) {

However, I was wondering if we could customise the generateJS method to support alternative rendering methods, such as functions as variables, the Javascript Module Pattern, CommonJS (which is the same as the current one but with the addition of an exports declaration), and Purescript-ready methods (which require a bunch of nested functions, one for each parameter).

The outcome is that we might be able to invoke, say,

generateJS' (ModulePatternOutput "Foo.MySubmodule") getSomethingAjaxReq

and get

Foo.MySubmodule.getsomething = function(onSuccess, onError){
...

I'm happy to undertake investigation into this and put together a PR for it, but I was wondering what your thoughts were on this.

Copied from original issue: haskell-servant/servant-jquery#7

Add a quasi quoter for servant route definition.

The version on hackage still has it, but it seems to have been taken out of the repository in commit 5470297. Having the routes defined in a quasi quoter makes the route definition look much more natural, while still giving you the advantages of servant.

Also, it would be cool if the new incarnation of the quasi quoter could also generate the routing function and not just the routing type, by providing it the name of haskell functions to use. I would imagine you might be able to use that to automatically derive the types of the routes as well, which would be cool.

DELETE doesn't allow for response body

From @Fuuzetsu on March 25, 2015 0:16

I have an API here that I DELETE to and which returns 200 (so we get Left "HTTP DELETE request failed with status: 200 - OK", another issue) and some body which we can not process because unlike Put or Post, we can't parametrise the Delete.

Copied from original issue: haskell-servant/servant-client#19

Vote: Naming convention for content-type-aware combinators

Hi folks,

There's been a decent amount of work on all the servant libraries since the 0.2 release, among which is a clean and extensible support for content-types.

Most of the discussion so far about this resides here.

We're basically wondering what you, users and fellow servant developers, would prefer:

  1. Keep Get, Post and friends as the names for the JSON-only endpoints, and have the combinators that take the list of supported content types be named with a final prime ('), as in Get', Post', etc. This would probably have the benefit of not breaking any existing code.
  2. The reverse: have Get, Post and friends be the combinators that take a type level list of supported content types, and have Get', Post' etc be the simple JSON-only versions.
  3. Some other naming convention..?

The discussion linked above contains "sample code" to give you an idea of what each would look like.

Please express your vote in a comment to this issue here, and within a week or two we'll see what naming convention is preferred and we'll just go with that one.

Thanks in advance folks.

Permit zero content types for empty response

The instances for HasClient match on the type-level cons eg.

instance HasClient (Delete (ct ': cts) ())

For empty responses, there isn't a need for any content types; in fact, ct and cts aren't used in the instance body.

Custom error responses

It would be useful if servant supported custom HTTP error responses in addition to NotFound, WrongMethod, and InvalidBody.

I'd be happy to add such support, but would like confirmation this feature would actually be merged before spending the time. Is this a contribution you would accept in servant?

ExceptT

Now that the world is moving towards ExceptT (cf. the errors package), we probably should too.

Custom handler monads and partial handlers.

I am trying to implement authentication and got stuck with errors that
I think could more sustainably be fixed in the 'HasServer' class.
This is a recount of what happened, with a concrete question at the
end.

Relevant code is here: liqd/thentos@93016c1 (branch: liqd/thentos#81).

Very similar things are going on over at #70, but thentos writes the
credentials into the custom handler monad instead of passing them to
the handlers as an extra argument. My mind is a bit boggled right
now, but I think this is what's going on:

  1. At the point in the route where the ThentosAuth link is found, a
    "partial server" in the custom handler monad with result type ()
    is constructed: Just look up the credentials in the request, write
    them into the custom monad's state, and return ().
  2. This partial server cannot be executed here, because we are still
    collecting the handler's function arguments from the routes. Actions
    can be constructed half-way through the route, but they can't be
    executed before the entire route has been parsed successfully.
  3. So instead, I push the action down the routes to where I can
    sequence it into the route's "proper" action. (@jkarni has showed me
    how to implement an earlier version of this trick.)

Now as you can see in module Thentos.Backend.Api.Auth if you
uncomment the code in lines 51, 54, HasServer wants sub-routes to
live in the standard servant monad.

I guess my question is, what would happen if the 'HasServer' class
looked like this?:

class HasServer layout (m :: * -> *) where
  type ServerT layout :: *
  route :: Proxy layout -> ServerT layout -> RoutingApplication

Also, is there a work-around?

Thanks! (-:

Fix `BaseUrl`

From @jkarni on April 15, 2015 15:17

BaseUrl should either be just be an argument to client, or the first argument to every function. (The former is, I think, preferable).

Copied from original issue: haskell-servant/servant-client#24

ReqBody-like GET param parsing

ReqBody is great, it captures the whole POST body and make it available in a type. I wonder if it's intended that the same thing isn't available with GET. It would be nice if I can have a GET param that is a URL encoded JSON string converted into a type just like that. I would have used POST, but that has a vague effect on caching. Any thoughts?

Add tests

From @jkarni on February 20, 2015 17:24

Copied from original issue: haskell-servant/servant-docs#13

Access to full Response body

From @tvh on March 13, 2015 6:14

Sometimes it is necessary to inspect more about a response than just the body. Some services will return important information in the header. It would be nice to have a mechanism to do this.

One option would be to change the instance for Raw, such that it returns the Full response instead of just parts of it. This would also be in symmetry to the server, where you have full access to wai.

Copied from original issue: haskell-servant/servant-client#16

Use `HTTP.Status.Types.Status` instead of `(Int, String)` for errors

From @davidsd on April 4, 2015 18:4

Might it be simpler/safer to return a Status instead of (Int, String) in the case of a handler error? That way, we could re-use already-defined statuses like ok200 or forbidden403. If we want custom error messages, we could just use mkStatus on our own.

Copied from original issue: haskell-servant/servant-server#37

Parse error: POST route with String in request body

Hello,
when I try to build a root that expects a simple String in the request body (rather than a Haskell data instance) like so:

type Api =
...
:<|> "item" :> "create" :> ReqBody (String) :> Post ()

I always get the rather generic error response

Invalid JSON in request body: Failed reading: satisfy

This is regardless of what I tried:

"asdf"
asdf
\"asdf\"

It never made it through the servant Json parsing to my actual handler (where "asdf" would likely cause another runtime error).

Am I missing something?

(The idea behind the String in the request body is, btw, to use digestive functors for validation. If anyone else has input on how to combine servant with digestive-functors, I'm all ears!)

Servant with persistent/IO

Hello,

I can't figure out based on the example code, how to use servant with persistent. Instead of returning something like Greet (s. example), I have an IO action (because I access a database). Has someone done something like that? Is there an example? All help is appreciated!

Incomplete example for servant-docs

There are a few problems with the example on hackage for servant-docs.

  1. Missing Control.Lens import
  2. MimeRender has no method toByteString. It should be mimeRender.
  3. No instance for (HasLink Delete), it is missing some parameters.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.