haskell-servant / haskell-servant/servant

Overriding server handlers with efficient Raw implementations

Open
#1,021 6 comments 1 reaction 0 assignees View on GitHub
Dominant language
Haskell
Stars
2k
Forks
427
Avg merge
2d 23h
Merged PRs (30d)
5

Description

At work I faced the need to abandon nice Servant API types in favour of `Raw` for some critical endpoints to enhance handler performance by avoiding "unnecessary" JSON (de)serialisation.
However I also wanted to retain Haskell client functions and Swagger documentation, which I lose if I go with just `Raw`.

I think I've come up with a solution with is lightweight and allows me to override any endpoint whenever there's a need to and without sacrificing client functions or Swagger documentation:

```haskell
-- | A value that can be overriden with a value of a different type.
data OverridableAs raw api
= Overriding raw
| Overridable api

type SampleAPI
= "send" :> OverridableAs Raw SendItem
-- ^ we want to be able to provide a more efficient
-- Raw implementation for this endpoint
-- specifically to avoid unnecessary ToJSON/FromJSON
-- conversions and validations
-- but we want client functions and Swagger documentation
-- to still be derived from SendItem API
:<|> "list" :> ListItems
```

The full gist is available at https://gist.github.com/fizruk/59c54f849941306b1bd50dd276debb64

I believe this is a usable, but still raw idea that can probably be improved upon:

- In `route` I am relying on `RawRouter` and `serveWithContext`. I think it can be done better, but should introduce little-to-no overhead for `Raw` (which is the case I'm most interested in).
- There might be other uses for this. For instance `OverridableAs NotImplemented` where `NotImplemented` has some trivial implementation.
- `OverridableAs` is essentially `Either` which is just a sum type operator in disguise. A natural theoretical question to ask is does ever makes sense to "sum" more than two values? How about zero?

@phadej @alpmestan I would appreciate your comments on this one!

Contributor guide

Open the contributing guide

Research direction

Start with the linked gist and the issue's discussion of OverridableAs, then inspect the route implementation using RawRouter and serveWithContext. Clarify the intended API and whether the approach should preserve generated client functions and Swagger documentation while avoiding Raw handler serialization overhead. Done would require an agreed design and implementation scope, which the issue does not currently specify.

Written by the indexing model from the issue text.

Assessment

Tech stack
haskell
Domain
api
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.