or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

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

path-matching.mddocs/

0

# Path Matching and Extraction

1

2

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

3

4

## Capabilities

5

6

### Basic Path Extractors

7

8

Core path decomposition operators for building URL routing patterns.

9

10

```scala { .api }

11

/**

12

* Root path constant - represents the root "/" path

13

*/

14

val Root: Uri.Path.Root.type

15

16

/**

17

* Path segment extractor - separates path into parent and last segment

18

*/

19

object / {

20

def unapply(path: Path): Option[(Path, String)]

21

}

22

23

/**

24

* Path prefix extractor - extracts first segment and remaining path

25

*/

26

object /: {

27

def unapply(path: Path): Option[(String, Path)]

28

}

29

```

30

31

**Usage Examples:**

32

33

```scala

34

import org.http4s.dsl.io._

35

36

val routes = HttpRoutes.of[IO] {

37

// Root path

38

case GET -> Root =>

39

Ok("Home page")

40

41

// Single segment

42

case GET -> Root / "about" =>

43

Ok("About page")

44

45

// Multiple segments

46

case GET -> Root / "api" / "v1" / "users" =>

47

Ok("Users API v1")

48

49

// Path prefix matching

50

case GET -> ("api" /: rest) =>

51

Ok(s"API endpoint: $rest")

52

}

53

```

54

55

### Path Variables

56

57

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

58

59

```scala { .api }

60

/**

61

* Integer path variable extractor

62

*/

63

object IntVar extends PathVar[Int] {

64

def unapply(str: String): Option[Int]

65

}

66

67

/**

68

* Long path variable extractor

69

*/

70

object LongVar extends PathVar[Long] {

71

def unapply(str: String): Option[Long]

72

}

73

74

/**

75

* UUID path variable extractor

76

*/

77

object UUIDVar extends PathVar[UUID] {

78

def unapply(str: String): Option[UUID]

79

}

80

81

/**

82

* Base class for path variable extractors

83

*/

84

abstract class PathVar[A](cast: String => Try[A]) {

85

def unapply(str: String): Option[A]

86

}

87

```

88

89

**Usage Examples:**

90

91

```scala

92

import org.http4s.dsl.io._

93

import java.util.UUID

94

95

val routes = HttpRoutes.of[IO] {

96

// Integer path parameter

97

case GET -> Root / "users" / IntVar(userId) =>

98

Ok(s"User ID: $userId")

99

100

// Long path parameter

101

case GET -> Root / "orders" / LongVar(orderId) =>

102

Ok(s"Order ID: $orderId")

103

104

// UUID path parameter

105

case GET -> Root / "sessions" / UUIDVar(sessionId) =>

106

Ok(s"Session: $sessionId")

107

108

// Multiple path variables

109

case GET -> Root / "users" / IntVar(userId) / "orders" / LongVar(orderId) =>

110

Ok(s"User $userId, Order $orderId")

111

112

// Path variables with validation (returns None for invalid formats)

113

case GET -> Root / "products" / IntVar(productId) if productId > 0 =>

114

Ok(s"Valid product ID: $productId")

115

}

116

```

117

118

### File Extension Matching

119

120

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

121

122

```scala { .api }

123

/**

124

* File extension extractor for paths and filenames

125

*/

126

object ~ {

127

/** Extract extension from URI path */

128

def unapply(path: Path): Option[(Path, String)]

129

130

/** Extract extension from filename string */

131

def unapply(fileName: String): Option[(String, String)]

132

}

133

```

134

135

**Usage Examples:**

136

137

```scala

138

import org.http4s.dsl.io._

139

140

val routes = HttpRoutes.of[IO] {

141

// File extension from path

142

case GET -> Root / "documents" / (fileName ~ "pdf") =>

143

Ok(s"PDF document: $fileName")

144

145

// Multiple extension matching

146

case GET -> Root / "images" / (fileName ~ ext) =>

147

ext match {

148

case "jpg" | "png" | "gif" => Ok(s"Image: $fileName.$ext")

149

case "svg" => Ok(s"Vector image: $fileName.$ext")

150

case _ => BadRequest("Unsupported image format")

151

}

152

153

// Combined with path variables

154

case GET -> Root / "api" / "files" / IntVar(id) ~ "json" =>

155

Ok(s"JSON file for ID: $id")

156

}

157

```

158

159

### Query Parameter Extraction

160

161

Comprehensive query parameter handling with type safety and validation.

162

163

```scala { .api }

164

/**

165

* Query parameter extractor - extracts all query parameters

166

*/

167

object :? {

168

def unapply[F[_]](req: Request[F]): Some[(Request[F], Map[String, collection.Seq[String]])]

169

}

170

171

/**

172

* Multiple query parameter extractor - allows chaining parameter matchers

173

*/

174

object +& {

175

def unapply(

176

params: Map[String, collection.Seq[String]]

177

): Some[(Map[String, collection.Seq[String]], Map[String, collection.Seq[String]])]

178

}

179

```

180

181

**Usage Examples:**

182

183

```scala

184

import org.http4s.dsl.io._

185

186

// Define query parameter matchers

187

object NameParam extends QueryParamDecoderMatcher[String]("name")

188

object AgeParam extends OptionalQueryParamDecoderMatcher[Int]("age")

189

object ActiveParam extends FlagQueryParamMatcher("active")

190

191

val routes = HttpRoutes.of[IO] {

192

// Single query parameter

193

case GET -> Root / "search" :? NameParam(name) =>

194

Ok(s"Searching for: $name")

195

196

// Multiple query parameters

197

case GET -> Root / "users" :? NameParam(name) +& AgeParam(maybeAge) =>

198

val ageStr = maybeAge.map(_.toString).getOrElse("unknown")

199

Ok(s"User: $name, Age: $ageStr")

200

201

// Flag parameter (present/absent)

202

case GET -> Root / "items" :? ActiveParam(isActive) =>

203

Ok(s"Show active items: $isActive")

204

205

// Access raw query parameters

206

case GET -> Root / "debug" :? queryParams =>

207

Ok(s"Query params: $queryParams")

208

}

209

```

210

211

### Query Parameter Matchers

212

213

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

214

215

```scala { .api }

216

/**

217

* Basic query parameter matcher with decoder

218

*/

219

abstract class QueryParamDecoderMatcher[T: QueryParamDecoder](name: String) {

220

def unapply(params: Map[String, collection.Seq[String]]): Option[T]

221

def unapplySeq(params: Map[String, collection.Seq[String]]): Option[collection.Seq[T]]

222

}

223

224

/**

225

* Optional query parameter matcher

226

*/

227

abstract class OptionalQueryParamDecoderMatcher[T: QueryParamDecoder](name: String) {

228

def unapply(params: Map[String, collection.Seq[String]]): Option[Option[T]]

229

}

230

231

/**

232

* Query parameter matcher with default value

233

*/

234

abstract class QueryParamDecoderMatcherWithDefault[T: QueryParamDecoder](name: String, default: T) {

235

def unapply(params: Map[String, collection.Seq[String]]): Option[T]

236

}

237

238

/**

239

* Flag query parameter matcher (checks presence/absence)

240

*/

241

abstract class FlagQueryParamMatcher(name: String) {

242

def unapply(params: Map[String, collection.Seq[String]]): Option[Boolean]

243

}

244

245

/**

246

* Multi-value query parameter matcher

247

*/

248

abstract class OptionalMultiQueryParamDecoderMatcher[T: QueryParamDecoder](name: String) {

249

def unapply(

250

params: Map[String, collection.Seq[String]]

251

): Option[ValidatedNel[ParseFailure, List[T]]]

252

}

253

254

/**

255

* Validating query parameter matcher with detailed error reporting

256

*/

257

abstract class ValidatingQueryParamDecoderMatcher[T: QueryParamDecoder](name: String) {

258

def unapply(params: Map[String, collection.Seq[String]]): Option[ValidatedNel[ParseFailure, T]]

259

}

260

```

261

262

**Usage Examples:**

263

264

```scala

265

import org.http4s.dsl.io._

266

import cats.data.Validated

267

268

// Custom query parameter matchers

269

object LimitParam extends QueryParamDecoderMatcherWithDefault[Int]("limit", 10)

270

object TagsParam extends OptionalMultiQueryParamDecoderMatcher[String]("tags")

271

object SortParam extends ValidatingQueryParamDecoderMatcher[String]("sort")

272

273

val routes = HttpRoutes.of[IO] {

274

// Parameter with default value

275

case GET -> Root / "items" :? LimitParam(limit) =>

276

Ok(s"Limit: $limit items")

277

278

// Multi-value parameters

279

case GET -> Root / "posts" :? TagsParam(Validated.Valid(tags)) =>

280

Ok(s"Tags: ${tags.mkString(", ")}")

281

282

case GET -> Root / "posts" :? TagsParam(Validated.Invalid(errors)) =>

283

BadRequest(s"Invalid tags: ${errors.toList.mkString(", ")}")

284

285

// Validating parameters with error handling

286

case GET -> Root / "data" :? SortParam(Validated.Valid(sortBy)) =>

287

Ok(s"Sorting by: $sortBy")

288

289

case GET -> Root / "data" :? SortParam(Validated.Invalid(errors)) =>

290

BadRequest(s"Invalid sort parameter: ${errors.head.sanitized}")

291

}

292

```

293

294

### Matrix Parameters

295

296

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

297

298

```scala { .api }

299

/**

300

* Matrix parameter extractor for multi-dimensional resource identification

301

*/

302

abstract class MatrixVar[F[_]: Foldable](name: String, domain: F[String]) {

303

def unapplySeq(str: String): Option[Seq[String]]

304

}

305

```

306

307

**Usage Examples:**

308

309

```scala

310

import org.http4s.dsl.io._

311

312

// Define matrix parameter extractor

313

object BoardVar extends MatrixVar("square", List("x", "y"))

314

315

val routes = HttpRoutes.of[IO] {

316

// Matrix parameters: /board/square;x=5;y=3

317

case GET -> Root / "board" / BoardVar(IntVar(x), IntVar(y)) =>

318

Ok(s"Board position: ($x, $y)")

319

}

320

```

321

322

### Advanced Pattern Matching

323

324

Complex pattern matching combinations using the conjunction operator.

325

326

```scala { .api }

327

/**

328

* Conjunction extractor for combining multiple patterns

329

*/

330

object & {

331

def unapply[A](a: A): Some[(A, A)]

332

}

333

```

334

335

**Usage Examples:**

336

337

```scala

338

import org.http4s.dsl.io._

339

340

// Define custom extractors

341

object EvenNumber { def unapply(i: Int): Boolean = i % 2 == 0 }

342

object PositiveNumber { def unapply(i: Int): Boolean = i > 0 }

343

344

val routes = HttpRoutes.of[IO] {

345

// Conjunction matching

346

case GET -> Root / "numbers" / IntVar(EvenNumber() & PositiveNumber()) =>

347

Ok("Even and positive number")

348

349

case GET -> Root / "numbers" / IntVar(n) =>

350

Ok(s"Number: $n")

351

}

352

```

353

354

### Authentication Support

355

356

Extract authentication context from authenticated requests using the `as` extractor.

357

358

```scala { .api }

359

/**

360

* Authentication extractor for AuthedRequest

361

*/

362

trait Auth {

363

object as {

364

def unapply[F[_], A](ar: AuthedRequest[F, A]): Option[(Request[F], A)]

365

}

366

}

367

```

368

369

**Usage Examples:**

370

371

```scala

372

import org.http4s.dsl.io._

373

import org.http4s.AuthedRequest

374

375

// Assuming you have authentication middleware that produces AuthedRequest[IO, User]

376

val authedRoutes = AuthedRoutes.of[User, IO] {

377

case GET -> Root / "profile" as user =>

378

Ok(s"Profile for user: ${user.name}")

379

380

case POST -> Root / "posts" as user =>

381

// Create post for authenticated user

382

Ok(s"Post created by ${user.name}")

383

384

case authedReq @ GET -> Root / "admin" as user if user.isAdmin =>

385

Ok("Admin panel")

386

}

387

```

388

389

## Error Handling

390

391

Path matching provides automatic error handling for common scenarios:

392

393

- **Invalid path variables**: Return `None` from extractors, causing route to not match

394

- **Query parameter parsing errors**: Captured in `ValidatedNel` for detailed error reporting

395

- **Missing required parameters**: Handled through pattern match failure

396

397

## Type Safety

398

399

- All path extractors preserve type information through Scala's type system

400

- Path variables automatically validate and convert string segments to target types

401

- Query parameter matchers provide compile-time type safety with runtime validation

402

- Pattern matching ensures exhaustive handling of route scenarios