or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

http-methods.mdindex.mdpath-matching.mdresponse-generation.md
tile.json

path-matching.mddocs/

Path Matching and Extraction

Comprehensive path decomposition and parameter extraction system for building REST APIs with type-safe URL routing, query parameter handling, and file extension matching.

Capabilities

Basic Path Extractors

Core path decomposition operators for building URL routing patterns.

/**
 * Root path constant - represents the root "/" path
 */
val Root: Uri.Path.Root.type

/**
 * Path segment extractor - separates path into parent and last segment
 */
object / {
  def unapply(path: Path): Option[(Path, String)]
}

/**
 * Path prefix extractor - extracts first segment and remaining path
 */
object /: {
  def unapply(path: Path): Option[(String, Path)]
}

Usage Examples:

import org.http4s.dsl.io._

val routes = HttpRoutes.of[IO] {
  // Root path
  case GET -> Root =>
    Ok("Home page")
    
  // Single segment
  case GET -> Root / "about" =>
    Ok("About page")
    
  // Multiple segments
  case GET -> Root / "api" / "v1" / "users" =>
    Ok("Users API v1")
    
  // Path prefix matching
  case GET -> ("api" /: rest) =>
    Ok(s"API endpoint: $rest")
}

Path Variables

Type-safe extraction of path parameters with automatic parsing and validation.

/**
 * Integer path variable extractor
 */
object IntVar extends PathVar[Int] {
  def unapply(str: String): Option[Int]
}

/**
 * Long path variable extractor  
 */
object LongVar extends PathVar[Long] {
  def unapply(str: String): Option[Long]
}

/**
 * UUID path variable extractor
 */
object UUIDVar extends PathVar[UUID] {
  def unapply(str: String): Option[UUID]
}

/**
 * Base class for path variable extractors
 */
abstract class PathVar[A](cast: String => Try[A]) {
  def unapply(str: String): Option[A]
}

Usage Examples:

import org.http4s.dsl.io._
import java.util.UUID

val routes = HttpRoutes.of[IO] {
  // Integer path parameter
  case GET -> Root / "users" / IntVar(userId) =>
    Ok(s"User ID: $userId")
    
  // Long path parameter  
  case GET -> Root / "orders" / LongVar(orderId) =>
    Ok(s"Order ID: $orderId")
    
  // UUID path parameter
  case GET -> Root / "sessions" / UUIDVar(sessionId) =>
    Ok(s"Session: $sessionId")
    
  // Multiple path variables
  case GET -> Root / "users" / IntVar(userId) / "orders" / LongVar(orderId) =>
    Ok(s"User $userId, Order $orderId")
    
  // Path variables with validation (returns None for invalid formats)
  case GET -> Root / "products" / IntVar(productId) if productId > 0 =>
    Ok(s"Valid product ID: $productId")
}

File Extension Matching

Extract file extensions from paths and filenames for content negotiation and file handling.

/**
 * File extension extractor for paths and filenames
 */
object ~ {
  /** Extract extension from URI path */
  def unapply(path: Path): Option[(Path, String)]
  
  /** Extract extension from filename string */
  def unapply(fileName: String): Option[(String, String)]
}

Usage Examples:

import org.http4s.dsl.io._

val routes = HttpRoutes.of[IO] {
  // File extension from path
  case GET -> Root / "documents" / (fileName ~ "pdf") =>
    Ok(s"PDF document: $fileName")
    
  // Multiple extension matching
  case GET -> Root / "images" / (fileName ~ ext) =>
    ext match {
      case "jpg" | "png" | "gif" => Ok(s"Image: $fileName.$ext")
      case "svg" => Ok(s"Vector image: $fileName.$ext") 
      case _ => BadRequest("Unsupported image format")
    }
    
  // Combined with path variables
  case GET -> Root / "api" / "files" / IntVar(id) ~ "json" =>
    Ok(s"JSON file for ID: $id")
}

Query Parameter Extraction

Comprehensive query parameter handling with type safety and validation.

/**
 * Query parameter extractor - extracts all query parameters
 */
object :? {
  def unapply[F[_]](req: Request[F]): Some[(Request[F], Map[String, collection.Seq[String]])]
}

/**
 * Multiple query parameter extractor - allows chaining parameter matchers
 */
object +& {
  def unapply(
    params: Map[String, collection.Seq[String]]
  ): Some[(Map[String, collection.Seq[String]], Map[String, collection.Seq[String]])]
}

Usage Examples:

import org.http4s.dsl.io._

// Define query parameter matchers
object NameParam extends QueryParamDecoderMatcher[String]("name")
object AgeParam extends OptionalQueryParamDecoderMatcher[Int]("age")
object ActiveParam extends FlagQueryParamMatcher("active")

val routes = HttpRoutes.of[IO] {
  // Single query parameter
  case GET -> Root / "search" :? NameParam(name) =>
    Ok(s"Searching for: $name")
    
  // Multiple query parameters  
  case GET -> Root / "users" :? NameParam(name) +& AgeParam(maybeAge) =>
    val ageStr = maybeAge.map(_.toString).getOrElse("unknown")
    Ok(s"User: $name, Age: $ageStr")
    
  // Flag parameter (present/absent)
  case GET -> Root / "items" :? ActiveParam(isActive) =>
    Ok(s"Show active items: $isActive")
    
  // Access raw query parameters
  case GET -> Root / "debug" :? queryParams =>
    Ok(s"Query params: $queryParams")
}

Query Parameter Matchers

Type-safe query parameter matchers with validation and error handling.

/**
 * Basic query parameter matcher with decoder
 */
abstract class QueryParamDecoderMatcher[T: QueryParamDecoder](name: String) {
  def unapply(params: Map[String, collection.Seq[String]]): Option[T]
  def unapplySeq(params: Map[String, collection.Seq[String]]): Option[collection.Seq[T]]
}

/**
 * Optional query parameter matcher
 */
abstract class OptionalQueryParamDecoderMatcher[T: QueryParamDecoder](name: String) {
  def unapply(params: Map[String, collection.Seq[String]]): Option[Option[T]]
}

/**
 * Query parameter matcher with default value
 */
abstract class QueryParamDecoderMatcherWithDefault[T: QueryParamDecoder](name: String, default: T) {
  def unapply(params: Map[String, collection.Seq[String]]): Option[T]
}

/**
 * Flag query parameter matcher (checks presence/absence)
 */
abstract class FlagQueryParamMatcher(name: String) {
  def unapply(params: Map[String, collection.Seq[String]]): Option[Boolean]
}

/**
 * Multi-value query parameter matcher
 */
abstract class OptionalMultiQueryParamDecoderMatcher[T: QueryParamDecoder](name: String) {
  def unapply(
    params: Map[String, collection.Seq[String]]
  ): Option[ValidatedNel[ParseFailure, List[T]]]
}

/**
 * Validating query parameter matcher with detailed error reporting
 */
abstract class ValidatingQueryParamDecoderMatcher[T: QueryParamDecoder](name: String) {
  def unapply(params: Map[String, collection.Seq[String]]): Option[ValidatedNel[ParseFailure, T]]
}

Usage Examples:

import org.http4s.dsl.io._
import cats.data.Validated

// Custom query parameter matchers
object LimitParam extends QueryParamDecoderMatcherWithDefault[Int]("limit", 10)
object TagsParam extends OptionalMultiQueryParamDecoderMatcher[String]("tags")
object SortParam extends ValidatingQueryParamDecoderMatcher[String]("sort")

val routes = HttpRoutes.of[IO] {
  // Parameter with default value
  case GET -> Root / "items" :? LimitParam(limit) =>
    Ok(s"Limit: $limit items")
    
  // Multi-value parameters
  case GET -> Root / "posts" :? TagsParam(Validated.Valid(tags)) =>
    Ok(s"Tags: ${tags.mkString(", ")}")
    
  case GET -> Root / "posts" :? TagsParam(Validated.Invalid(errors)) =>
    BadRequest(s"Invalid tags: ${errors.toList.mkString(", ")}")
    
  // Validating parameters with error handling
  case GET -> Root / "data" :? SortParam(Validated.Valid(sortBy)) =>
    Ok(s"Sorting by: $sortBy")
    
  case GET -> Root / "data" :? SortParam(Validated.Invalid(errors)) =>
    BadRequest(s"Invalid sort parameter: ${errors.head.sanitized}")
}

Matrix Parameters

Advanced URI matrix parameter extraction for multi-dimensional resource addressing.

/**
 * Matrix parameter extractor for multi-dimensional resource identification
 */
abstract class MatrixVar[F[_]: Foldable](name: String, domain: F[String]) {
  def unapplySeq(str: String): Option[Seq[String]]
}

Usage Examples:

import org.http4s.dsl.io._

// Define matrix parameter extractor
object BoardVar extends MatrixVar("square", List("x", "y"))

val routes = HttpRoutes.of[IO] {
  // Matrix parameters: /board/square;x=5;y=3
  case GET -> Root / "board" / BoardVar(IntVar(x), IntVar(y)) =>
    Ok(s"Board position: ($x, $y)")
}

Advanced Pattern Matching

Complex pattern matching combinations using the conjunction operator.

/**
 * Conjunction extractor for combining multiple patterns
 */
object & {
  def unapply[A](a: A): Some[(A, A)]
}

Usage Examples:

import org.http4s.dsl.io._

// Define custom extractors
object EvenNumber { def unapply(i: Int): Boolean = i % 2 == 0 }
object PositiveNumber { def unapply(i: Int): Boolean = i > 0 }

val routes = HttpRoutes.of[IO] {
  // Conjunction matching
  case GET -> Root / "numbers" / IntVar(EvenNumber() & PositiveNumber()) =>
    Ok("Even and positive number")
    
  case GET -> Root / "numbers" / IntVar(n) =>
    Ok(s"Number: $n")
}

Authentication Support

Extract authentication context from authenticated requests using the as extractor.

/**
 * Authentication extractor for AuthedRequest
 */
trait Auth {
  object as {
    def unapply[F[_], A](ar: AuthedRequest[F, A]): Option[(Request[F], A)]
  }
}

Usage Examples:

import org.http4s.dsl.io._
import org.http4s.AuthedRequest

// Assuming you have authentication middleware that produces AuthedRequest[IO, User]
val authedRoutes = AuthedRoutes.of[User, IO] {
  case GET -> Root / "profile" as user =>
    Ok(s"Profile for user: ${user.name}")
    
  case POST -> Root / "posts" as user =>
    // Create post for authenticated user
    Ok(s"Post created by ${user.name}")
    
  case authedReq @ GET -> Root / "admin" as user if user.isAdmin =>
    Ok("Admin panel")
}

Error Handling

Path matching provides automatic error handling for common scenarios:

  • Invalid path variables: Return None from extractors, causing route to not match
  • Query parameter parsing errors: Captured in ValidatedNel for detailed error reporting
  • Missing required parameters: Handled through pattern match failure

Type Safety

  • All path extractors preserve type information through Scala's type system
  • Path variables automatically validate and convert string segments to target types
  • Query parameter matchers provide compile-time type safety with runtime validation
  • Pattern matching ensures exhaustive handling of route scenarios