Wildcard and concrete paths result in shadowed endpoints in Tapir, but are allowed in openapi spec

Hello, I have been trying to get some clarity surrounding tapir’s pattern matching when wildcards are in the mix, but i haven’t yet found a precise answer to this in tapir.

If i have one path like devices/{deviceId} (where deviceId is a UUID, or an int, or any type)
and then another like devices/networking

It will fail validations because devices/networking is shadowed by devices/{deviceId}. This makes sense, except that per openapi spec on “Path Templating Matching” (OpenAPI Specification - Version 3.0.3 | Swagger) it actually should work, and apparently match the concrete path first (devices/networking).

So my question becomes, is this expected behavior from Tapir?

Tapir’s server interpreters try to decode endpoints in the order in which they are given. So there’s no reordering, or checking which path is more specific.

So we don’t implement it the way that OpenAPI describes. Might be a candidate feature for 2.0 :slight_smile:

2 Likes

Ok cool! I just wanted to get a decisive answer on whether or not Tapir will allow such routes to work and whether or not the problem is my usage of Tapir vs Tapir Itself.

It’s not me! :smile:

Thanks so much!

I should clarify. I was able to modify the order of documentation endpoints to avoid the “shadow” validation-error which is mostly what my original question deals with.

However, i was not able to change the order of the tapir routes (at least in akka-http) so that my requests would be parsed as i intended with concrete vs wildcard endpoints. I’m trying to dig into the code and see exactly how tapir routes are translated into akka routes to better understand why this is… however it’s not trivial (for me anyways).

It should be enough to change the ordering of endpoints on the list that is being passed to the interpreter. E.g.:

val deviceIdEndpoint = ...
val networkingEndpoint = ...

AkkaHttpInterpreter().toRoutes(List(networkingEndpoint, deviceIdEndpoint))
1 Like

yeahhhhh, turns out I had some other stuff broken causing me to think this didn’t work. :unamused:

It does indeed work as you pointed out. Thanks!