Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display capture hints in router layout #1556

Merged
merged 3 commits into from
Mar 25, 2022

Conversation

nbacquey
Copy link
Contributor

@nbacquey nbacquey commented Mar 8, 2022

This PR introduces a CaptureHint type, which is passed as an extra argument to the CaptureRouter and CaptureAllRouter constructors for the Router' type.
CaptureHint values are then used in routerLayout, to display the name and type of captured values, instead of just <capture> previously.

N.B.:
Because the choice smart constructor for routers can aggregate Capture combinators with different capture hints, the Capture*Router constructors actually take a list of CaptureHint, instead of a single one.

This PR also introduces Spec tests for the routerLayout function.

Warning:
This change is potentially breaking, because it adds the constraint Typeable a to all types that are to be captured. Because all types are typeable since GHC 7.10, this is not as bad as it sounds ; it only break expressions where a is quantified in an expression with Capture a.
In those cases, the fix is easy: it suffices to add Typeable a to the left-hand side of the quantification constraint.

@nbacquey nbacquey changed the title Router layout captures Display capture hints in router layout Mar 8, 2022
@arianvp
Copy link
Member

arianvp commented Mar 9, 2022

Interesting. Could this be used as a replacement for https://hackage.haskell.org/package/servant-ekg-0.3.1/docs/src/Servant.Ekg.html#HasEndpoint e.g. to implement prometheus metrics directly in servant-server (haskell-servant/servant-ekg#30 ) ?

@nbacquey
Copy link
Contributor Author

nbacquey commented Mar 9, 2022

It's a step in the right direction, but there's still some work to do before it can replace HasEndpoint in your usecase.
Some of my motivations for this work can be found in #1553; implementing prometheus metrics in servant-server seems closely related to what prompted this work in the first place.

@nbacquey
Copy link
Contributor Author

Note: due to the discussion above, I removed the dependence to Typeable in the HasServer instance.
Although this change was technically breaking, I think the breaking cases are both very rare (there needs to be a universally quantified a in a type containing Capture "foo" a and easy to fix (just add the Typeable a constraint).

I would appreciate your opinions on whether this dependence could be added back, given the additional feature it brings (being able to tell the type of captured variables)

This decision would also affect #1561

@gdeest
Copy link
Contributor

gdeest commented Mar 18, 2022

After giving it some thoughts, I am in favor of re-introducing the Typeable constraint. While it is indeed a breaking change,

  • It should indeed affect a relatively small number of users.
  • It should always be possible (and trivial) to fix the error.
  • This can be documented thoroughly in a changelog / migration guide.
  • It makes router layout output much more useful (and allows nice features such as New combinator to return routed path in response headers #1561 to also include type information for debugging and monitoring purposes).

It is possible that carrying Typeable dictionaries around somehow slows down routing a bit — I don't think this should be significant, but may be worth mentioning.

@nbacquey
Copy link
Contributor Author

nbacquey commented Mar 21, 2022

After giving it some thoughts, I am in favor of re-introducing the Typeable constraint. While it is indeed a breaking change,

* It should indeed affect a relatively small number of users.

* It should always be possible (and trivial) to fix the error.

* This can be documented thoroughly in a changelog / migration guide.

* It makes router layout output much more useful (and allows nice features such as [New combinator to return routed path in response headers #1561](https://github.com/haskell-servant/servant/pull/1561) to also include type information for debugging and monitoring purposes).

It is possible that carrying Typeable dictionaries around somehow slows down routing a bit — I don't think this should be significant, but may be worth mentioning.

I've reinstated the Typeable constraint, and also added a spec test to check that CaptureAll "foos" Int produces
"<foos::[Int]>"

changelog.d/1556 Outdated Show resolved Hide resolved
changelog.d/1556 Outdated Show resolved Hide resolved
This commit introduces a `CaptureHint` type, which is passed as an extra
argument to the `CaptureRouter` and `CaptureAllRouter` constructors for
the `Router'` type.
`CaptureHint` values are then used in `routerLayout`, to display the
name and "type" of captured values (single or list), instead of just
"<capture>" previously.

N.B.:
Because the `choice` smart constructor for routers can aggregate
`Capture` combinators with different capture hints, the `Capture*Router`
constructors actually take a *list* of `CaptureHint`, instead of a
single one.
@nbacquey nbacquey force-pushed the router_layout_captures branch 2 times, most recently from a9531a6 to 38df6ad Compare March 23, 2022 15:04
Copy link
Contributor

@gdeest gdeest left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just another minor nitpick on the changelog, otherwise this is good to go for me. 👍

changelog.d/1556 Show resolved Hide resolved
@gdeest gdeest merged commit 65de6f7 into haskell-servant:master Mar 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants