or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdhttp-methods-routing.mdindex.mdpath-matching.mdquery-parameters.mdstatus-codes-responses.md

status-codes-responses.mddocs/

0

# Status Codes and Response Generation

1

2

Complete set of HTTP status codes with fluent response generation API. Each status code provides type-safe methods for creating responses with or without bodies, headers, and proper content negotiation.

3

4

## Capabilities

5

6

### Response Generation Pattern

7

8

All HTTP status codes follow a consistent pattern for response generation:

9

10

```scala { .api }

11

/**

12

* Base response generator trait

13

*/

14

trait ResponseGenerator {

15

def status: Status

16

}

17

18

/**

19

* Response generator for responses without body content

20

*/

21

trait EmptyResponseGenerator[F[_], G[_]] extends ResponseGenerator {

22

def apply()(implicit F: Applicative[F]): F[Response[G]]

23

def headers(header: Header.ToRaw, headers: Header.ToRaw*)(implicit F: Applicative[F]): F[Response[G]]

24

}

25

26

/**

27

* Response generator for responses with optional body content

28

*/

29

trait EntityResponseGenerator[F[_], G[_]] extends ResponseGenerator {

30

def liftG: G ~> F

31

def apply()(implicit F: Applicative[F]): F[Response[G]]

32

def apply[A](body: A, headers: Header.ToRaw*)(implicit F: Applicative[F], w: EntityEncoder[G, A]): F[Response[G]]

33

def headers(header: Header.ToRaw, headers: Header.ToRaw*)(implicit F: Applicative[F]): F[Response[G]]

34

}

35

```

36

37

### 1xx Informational Responses

38

39

Informational status codes for ongoing request processing.

40

41

```scala { .api }

42

/**

43

* 100 Continue - Request headers received, client should send body

44

*/

45

val Continue: Status.Continue.type

46

47

/**

48

* 101 Switching Protocols - Server switching to different protocol

49

*/

50

val SwitchingProtocols: Status.SwitchingProtocols.type

51

52

/**

53

* 102 Processing - Server received request, still processing

54

*/

55

val Processing: Status.Processing.type

56

57

/**

58

* 103 Early Hints - Early metadata before final response

59

*/

60

val EarlyHints: Status.EarlyHints.type

61

```

62

63

**Usage Examples:**

64

65

```scala

66

val routes = HttpRoutes.of[IO] {

67

case GET -> Root / "status" =>

68

Continue()

69

70

case GET -> Root / "upgrade" =>

71

SwitchingProtocols()

72

}

73

```

74

75

### 2xx Success Responses

76

77

Success status codes indicating successful request processing.

78

79

```scala { .api }

80

/**

81

* 200 OK - Standard successful response

82

*/

83

val Ok: Status.Ok.type

84

85

/**

86

* 201 Created - Resource successfully created

87

*/

88

val Created: Status.Created.type

89

90

/**

91

* 202 Accepted - Request accepted for processing

92

*/

93

val Accepted: Status.Accepted.type

94

95

/**

96

* 203 Non-Authoritative Information - Successful but from cache/proxy

97

*/

98

val NonAuthoritativeInformation: Status.NonAuthoritativeInformation.type

99

100

/**

101

* 204 No Content - Successful request with no response body

102

*/

103

val NoContent: Status.NoContent.type

104

105

/**

106

* 205 Reset Content - Successful request, client should reset form

107

*/

108

val ResetContent: Status.ResetContent.type

109

110

/**

111

* 206 Partial Content - Partial resource delivered

112

*/

113

val PartialContent: Status.PartialContent.type

114

115

/**

116

* 207 Multi-Status - Multiple status codes for WebDAV

117

*/

118

val MultiStatus: Status.MultiStatus.type

119

120

/**

121

* 208 Already Reported - WebDAV already reported

122

*/

123

val AlreadyReported: Status.AlreadyReported.type

124

125

/**

126

* 226 IM Used - Instance manipulations applied

127

*/

128

val IMUsed: Status.IMUsed.type

129

```

130

131

**Usage Examples:**

132

133

```scala

134

val routes = HttpRoutes.of[IO] {

135

// Simple responses

136

case GET -> Root / "hello" =>

137

Ok("Hello, World!")

138

139

case POST -> Root / "users" =>

140

Created("User created successfully")

141

142

// With custom headers

143

case GET -> Root / "data" =>

144

Ok("response body", Header.Raw(ci"X-Custom-Header", "custom-value"))

145

146

// Empty responses

147

case DELETE -> Root / "users" / IntVar(id) =>

148

NoContent()

149

150

// JSON responses

151

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

152

Ok(User(id, "John Doe").asJson)

153

}

154

```

155

156

### 3xx Redirection Responses

157

158

Redirection status codes requiring additional client action.

159

160

```scala { .api }

161

/**

162

* 300 Multiple Choices - Multiple representation options

163

*/

164

val MultipleChoices: Status.MultipleChoices.type

165

166

/**

167

* 301 Moved Permanently - Resource permanently moved

168

*/

169

val MovedPermanently: Status.MovedPermanently.type

170

171

/**

172

* 302 Found - Resource temporarily moved

173

*/

174

val Found: Status.Found.type

175

176

/**

177

* 303 See Other - Response available at different URI

178

*/

179

val SeeOther: Status.SeeOther.type

180

181

/**

182

* 304 Not Modified - Resource not modified since last request

183

*/

184

val NotModified: Status.NotModified.type

185

186

/**

187

* 307 Temporary Redirect - Temporary redirect preserving method

188

*/

189

val TemporaryRedirect: Status.TemporaryRedirect.type

190

191

/**

192

* 308 Permanent Redirect - Permanent redirect preserving method

193

*/

194

val PermanentRedirect: Status.PermanentRedirect.type

195

```

196

197

**Usage Examples:**

198

199

```scala

200

import org.http4s.headers.Location

201

import org.http4s.Uri

202

203

val routes = HttpRoutes.of[IO] {

204

// Redirects with Location header

205

case GET -> Root / "old-path" =>

206

MovedPermanently(Location(Uri.unsafeFromString("/new-path")))

207

208

case POST -> Root / "login" =>

209

SeeOther(Location(Uri.unsafeFromString("/dashboard")))

210

211

// Conditional responses

212

case req @ GET -> Root / "resource" =>

213

req.headers.get[`If-Modified-Since`] match {

214

case Some(since) if !isModifiedSince(since) => NotModified()

215

case _ => Ok("Resource content")

216

}

217

}

218

```

219

220

### 4xx Client Error Responses

221

222

Client error status codes indicating issues with client requests.

223

224

```scala { .api }

225

/**

226

* 400 Bad Request - Invalid request syntax

227

*/

228

val BadRequest: Status.BadRequest.type

229

230

/**

231

* 401 Unauthorized - Authentication required

232

*/

233

val Unauthorized: Status.Unauthorized.type

234

235

/**

236

* 402 Payment Required - Payment required (reserved)

237

*/

238

val PaymentRequired: Status.PaymentRequired.type

239

240

/**

241

* 403 Forbidden - Access denied

242

*/

243

val Forbidden: Status.Forbidden.type

244

245

/**

246

* 404 Not Found - Resource not found

247

*/

248

val NotFound: Status.NotFound.type

249

250

/**

251

* 405 Method Not Allowed - HTTP method not supported

252

*/

253

val MethodNotAllowed: Status.MethodNotAllowed.type

254

255

/**

256

* 406 Not Acceptable - Response format not acceptable

257

*/

258

val NotAcceptable: Status.NotAcceptable.type

259

260

/**

261

* 407 Proxy Authentication Required - Proxy authentication needed

262

*/

263

val ProxyAuthenticationRequired: Status.ProxyAuthenticationRequired.type

264

265

/**

266

* 408 Request Timeout - Request timeout

267

*/

268

val RequestTimeout: Status.RequestTimeout.type

269

270

/**

271

* 409 Conflict - Request conflicts with current state

272

*/

273

val Conflict: Status.Conflict.type

274

275

/**

276

* 410 Gone - Resource permanently gone

277

*/

278

val Gone: Status.Gone.type

279

280

/**

281

* 411 Length Required - Content-Length header required

282

*/

283

val LengthRequired: Status.LengthRequired.type

284

285

/**

286

* 412 Precondition Failed - Precondition in headers failed

287

*/

288

val PreconditionFailed: Status.PreconditionFailed.type

289

290

/**

291

* 413 Payload Too Large - Request entity too large

292

*/

293

val PayloadTooLarge: Status.PayloadTooLarge.type

294

295

/**

296

* 414 URI Too Long - Request URI too long

297

*/

298

val UriTooLong: Status.UriTooLong.type

299

300

/**

301

* 415 Unsupported Media Type - Media type not supported

302

*/

303

val UnsupportedMediaType: Status.UnsupportedMediaType.type

304

305

/**

306

* 416 Range Not Satisfiable - Range header cannot be satisfied

307

*/

308

val RangeNotSatisfiable: Status.RangeNotSatisfiable.type

309

310

/**

311

* 417 Expectation Failed - Expect header cannot be satisfied

312

*/

313

val ExpectationFailed: Status.ExpectationFailed.type

314

315

/**

316

* 421 Misdirected Request - Request directed to wrong server

317

*/

318

val MisdirectedRequest: Status.MisdirectedRequest.type

319

320

/**

321

* 422 Unprocessable Entity - Request syntactically correct but semantically invalid

322

*/

323

val UnprocessableEntity: Status.UnprocessableEntity.type

324

325

/**

326

* 423 Locked - Resource locked

327

*/

328

val Locked: Status.Locked.type

329

330

/**

331

* 424 Failed Dependency - Request failed due to dependency failure

332

*/

333

val FailedDependency: Status.FailedDependency.type

334

335

/**

336

* 425 Too Early - Request sent too early

337

*/

338

val TooEarly: Status.TooEarly.type

339

340

/**

341

* 426 Upgrade Required - Client must upgrade protocol

342

*/

343

val UpgradeRequired: Status.UpgradeRequired.type

344

345

/**

346

* 428 Precondition Required - Precondition header required

347

*/

348

val PreconditionRequired: Status.PreconditionRequired.type

349

350

/**

351

* 429 Too Many Requests - Rate limit exceeded

352

*/

353

val TooManyRequests: Status.TooManyRequests.type

354

355

/**

356

* 431 Request Header Fields Too Large - Headers too large

357

*/

358

val RequestHeaderFieldsTooLarge: Status.RequestHeaderFieldsTooLarge.type

359

360

/**

361

* 451 Unavailable For Legal Reasons - Content blocked for legal reasons

362

*/

363

val UnavailableForLegalReasons: Status.UnavailableForLegalReasons.type

364

```

365

366

**Usage Examples:**

367

368

```scala

369

val routes = HttpRoutes.of[IO] {

370

// Error responses with messages

371

case POST -> Root / "users" =>

372

for {

373

user <- req.as[User].handleErrorWith(_ => BadRequest("Invalid user data").pure)

374

result <- createUser(user).handleErrorWith(_ => Conflict("User already exists").pure)

375

} yield result

376

377

// Authentication errors

378

case GET -> Root / "protected" =>

379

Unauthorized("""WWW-Authenticate: Bearer realm="api"""")

380

381

// Not found

382

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

383

findUser(id).flatMap {

384

case Some(user) => Ok(user.asJson)

385

case None => NotFound(s"User $id not found")

386

}

387

388

// Validation errors

389

case req @ POST -> Root / "validate" =>

390

req.as[Data].attempt.flatMap {

391

case Right(data) => Ok("Valid data")

392

case Left(_) => UnprocessableEntity("Invalid data format")

393

}

394

}

395

```

396

397

### 5xx Server Error Responses

398

399

Server error status codes indicating server-side issues.

400

401

```scala { .api }

402

/**

403

* 500 Internal Server Error - Generic server error

404

*/

405

val InternalServerError: Status.InternalServerError.type

406

407

/**

408

* 501 Not Implemented - Server doesn't support functionality

409

*/

410

val NotImplemented: Status.NotImplemented.type

411

412

/**

413

* 502 Bad Gateway - Invalid response from upstream server

414

*/

415

val BadGateway: Status.BadGateway.type

416

417

/**

418

* 503 Service Unavailable - Server temporarily unavailable

419

*/

420

val ServiceUnavailable: Status.ServiceUnavailable.type

421

422

/**

423

* 504 Gateway Timeout - Upstream server timeout

424

*/

425

val GatewayTimeout: Status.GatewayTimeout.type

426

427

/**

428

* 505 HTTP Version Not Supported - HTTP version not supported

429

*/

430

val HttpVersionNotSupported: Status.HttpVersionNotSupported.type

431

432

/**

433

* 506 Variant Also Negotiates - Content negotiation error

434

*/

435

val VariantAlsoNegotiates: Status.VariantAlsoNegotiates.type

436

437

/**

438

* 507 Insufficient Storage - Server out of storage

439

*/

440

val InsufficientStorage: Status.InsufficientStorage.type

441

442

/**

443

* 508 Loop Detected - Infinite loop detected

444

*/

445

val LoopDetected: Status.LoopDetected.type

446

447

/**

448

* 510 Not Extended - Further extensions required

449

*/

450

val NotExtended: Status.NotExtended.type

451

452

/**

453

* 511 Network Authentication Required - Network authentication required

454

*/

455

val NetworkAuthenticationRequired: Status.NetworkAuthenticationRequired.type

456

```

457

458

**Usage Examples:**

459

460

```scala

461

val routes = HttpRoutes.of[IO] {

462

case GET -> Root / "data" =>

463

fetchData().handleErrorWith { error =>

464

error match {

465

case _: DatabaseConnectionException => ServiceUnavailable("Database temporarily unavailable")

466

case _: TimeoutException => GatewayTimeout("Request timeout")

467

case _ => InternalServerError("An unexpected error occurred")

468

}

469

}

470

471

case GET -> Root / "unsupported" =>

472

NotImplemented("This endpoint is not yet implemented")

473

}

474

```

475

476

### Specialized Response Generators

477

478

Some status codes have specialized response generators with additional requirements:

479

480

#### WWW-Authenticate Response Generator (401)

481

482

```scala { .api }

483

/**

484

* 401 responses must include WWW-Authenticate header

485

*/

486

trait WwwAuthenticateResponseGenerator[F[_], G[_]] extends ResponseGenerator {

487

def apply(authenticate: `WWW-Authenticate`, headers: Header.ToRaw*)(implicit F: Applicative[F]): F[Response[G]]

488

def apply[A](authenticate: `WWW-Authenticate`, body: A, headers: Header.ToRaw*)(implicit F: Applicative[F], w: EntityEncoder[G, A]): F[Response[G]]

489

}

490

```

491

492

#### Allow Response Generator (405)

493

494

```scala { .api }

495

/**

496

* 405 responses must include Allow header

497

*/

498

trait AllowResponseGenerator[F[_], G[_]] extends ResponseGenerator {

499

def apply(allow: Allow, headers: Header.ToRaw*)(implicit F: Applicative[F]): F[Response[G]]

500

def apply[A](allow: Allow, body: A, headers: Header.ToRaw*)(implicit F: Applicative[F], w: EntityEncoder[G, A]): F[Response[G]]

501

}

502

```

503

504

#### Proxy-Authenticate Response Generator (407)

505

506

```scala { .api }

507

/**

508

* 407 responses must include Proxy-Authenticate header

509

*/

510

trait ProxyAuthenticateResponseGenerator[F[_], G[_]] extends ResponseGenerator {

511

def apply(authenticate: `Proxy-Authenticate`, headers: Header.ToRaw*)(implicit F: Applicative[F]): F[Response[G]]

512

def apply[A](authenticate: `Proxy-Authenticate`, body: A, headers: Header.ToRaw*)(implicit F: Applicative[F], w: EntityEncoder[G, A]): F[Response[G]]

513

}

514

```

515

516

#### Location Response Generator (3xx)

517

518

```scala { .api }

519

/**

520

* Redirect responses should include Location header

521

*/

522

trait LocationResponseGenerator[F[_], G[_]] extends EntityResponseGenerator[F, G] {

523

def apply(location: Location)(implicit F: Applicative[F]): F[Response[G]]

524

def apply[A](location: Location, body: A, headers: Header.ToRaw*)(implicit F: Applicative[F], w: EntityEncoder[G, A]): F[Response[G]]

525

}

526

```