1

I have simple rout-mapping function which using http4s:

import cats.syntax.all._
import org.http4s._
import org.http4s.circe._

def routeMapper: PartialFunction[Request[F], F[Response[F]]] = {
  case r @ POST -> Root => create
  case r @ PUT -> Root / id => update(id)
  case GET -> Root :? Published(published) => searchByPublishedDate(published)
  case GET -> Root                   =>
    println("show all called")
    showAll
  case GET -> Root / id              => searchById(id)
  case DELETE -> Root      => deleteAll
  case DELETE -> Root / id => delete(id)
}

object Published extends QueryParamDecoderMatcher[String]("published")

// I use this rout mapper to create HttpRoutes for HttpServer
def routes: HttpRoutes[F] = HttpRoutes.of[F](routeMapper)

For some reason when I try to pass GET request with some param which is not published to my server, I see result of showAll method.

For example, if I send get request on http://{host}:{port}/?foo=somevalue

I expect to see something like org.http4s.dsl.impl.Status.BadRequest or org.http4s.dsl.impl.Status.NotFound in Response but I see that it matches case GET -> Root actually.

Why it happens and how I can avoid this matching?

As I got partial functions are used for such cases when we want to define function only for some specified arguments (or types) but not for all possible inputs.

Tomer Shetah
  • 8,413
  • 7
  • 27
  • 35
Boris Azanov
  • 4,408
  • 1
  • 15
  • 28
  • 1
    I am not familiar with http4s, but it seems like you explicitly asked for it. It fall into the `case GET -> Root` path. Isn't it? Why would you expect it not to fall into that case? Because of the extra parameter? – Tomer Shetah Dec 02 '20 at 10:07
  • You'll find the same behaviour in akka routes. – Tomer Shetah Dec 02 '20 at 10:19
  • @TomerShetah I thought that defining some cases with parameters for example: `case GET -> Root :? Published(published)` will prevent situation with some unexpected parameter but it does not help. Now it is (`:? SomeParamWrapper(value)`) only needed for unapply parameter and get some value. Maybe it should be so, I'm just trying to clarify it. – Boris Azanov Dec 02 '20 at 11:15
  • It will catch all requests with the `published` parameter. Any get that dose not have it, will fall into the default. Actually I can't find how to get all query parameters, which is pretty easy with akka. If you can do that, you should check if the map is empty or not. – Tomer Shetah Dec 02 '20 at 11:18

1 Answers1

2

As already mentioned in comments, case case GET -> Root => will match all requests for the root path regardless of extra parameters.

To make this check stricter you could just reject that case if there's any parameter:

case request @ GET -> Root if request.params.isEmpty =>

it will match only if params map is empty.

Krzysztof Atłasik
  • 21,985
  • 6
  • 54
  • 76