implicitly support same encoders as decoders for `PathCodec` and `SegmentCodec`
Is your feature request related to a problem? Please describe.
Not exactly a problem, but when creating RoutePatterns, you can do something like the following:
val pattern: RoutePattern[(Int, Long, String, UUID, Boolean)] =
Method.GET / int("someInt") / long("someLong") / string("someString") / uuid("someUuid") / boolean("someBoolean")
To create a similar route with some of those parameters bound, you can do something like:
def createPattern(someLong: Long, someUuid: UUID) = {
// literal strings such as `someUuid.toString` are encoded via `implicit PathCodec.path`
Method.GET / int("someInt") / PathCodec.literal(someLong.toString) / string("someString") / someUuid.toString / boolean("someBoolean")
}
note that for non-string literal values, you need to either
- provide implicit
PathCodec - use
PathCodec.literalwith a string value - convert your value to a string first and then let it be converted to a
PathCodecvia the implicitPathCodec.path
Describe the solution you'd like
it feels like for every type that has Codecs available for binding (via int, long, uuid, boolean), it'd be nice if there was a matching literal encoder, for example
object PathCodec {
implicit def literalInt(value: Int) = literal(value.toString)
implicit def literalLong(value: Long) = literal(value.toString)
implicit def literalBoolean(value: Boolean) = literal(value.toString)
implicit def literalUuid(value: UUID) = literal(value.toString)
}
then the createPattern method above could look like:
def createPattern(someLong: Long, someUuid: UUID) = {
Method.GET / int("someInt") / someLong / string("someString") / someUuid / boolean("someBoolean")
}
Describe alternatives you've considered Not sure.
Additional context I think it's also fine as is, but to me seems strange that it's not symmetrical.
I get the idea, but I wonder what is your use case for
def createPattern(someLong: Long, someUuid: UUID) = {
// literal strings such as `someUuid.toString` are encoded via `implicit PathCodec.path`
Method.GET / int("someInt") / PathCodec.literal(someLong.toString) / string("someString") / someUuid.toString / boolean("someBoolean")
}
I am happy to find a solution, if your use case seems valid.
I'm using it to build RoutePatterns as well as getting paths for a URI for redirects!
I have three projects - a project (library) that contains a shared route, a project (application) that handles the route, and another project (application) that redirects users to that route.
the shared project looks something like this:
// `ServiceProvider` is an `enumeratum` enum, and I created a custom `PathCodec` for it since we use it all the time
def serviceProvider(name: String): PathCodec[ServiceProvider] =
string(name).transform(ServiceProvider.withName)(_.entryName)
object SharedRoutes {
val route: RoutePattern[(ServiceProvider, UUID)] =
Method.POST / serviceProvider("serviceProvider") / uuid("integrationId")
}
One project/application serves that route:
class ShopifyRoutes {
val routes = Routes(
// I'd love to use `SharedRoutes.route` here, but currently I have a separate handler for each ServiceProvider
// SharedRoutes.route -> Handler.fromFunctionZIO[(ServiceProvider, UUID, Request)] {
Method.POST / ServiceProvider.Slack / uuid("integrationId") -> Handler.fromFunctionZIO[(UUID, Request)] {
???
}
)
}
I have a different application that provides redirect URLs to the first application. I build such a URL via:
def getResourcePath(serviceProvider: ServiceProvider, resourceId: UUID): String = {
SharedRoutes.route.encode(serviceProvider, resourceId).encode
// or,
// val path = PathCodec.empty / serviceProvider / resourceId
// path.render
}
hopefully that makes sense. both ShopifyRoutes.routes and getResourcePath could use implicits like
implicit def path(serviceProvider: ServiceProvider): PathCodec[Unit] = PathCodec.literal(serviceProvider.entryName)
implicit def path(uuid: UUID): PathCodec[Unit] = PathCodec.literal(uuid.toString)
to encode values into a route
We will consider this concern in the design decision that will be made for the 4.0 release