or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

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

response-generation.mddocs/

0

# Response Generation

1

2

Complete HTTP status code constants and response builders for creating well-formed HTTP responses. The DSL provides fluent APIs for all standard HTTP status codes with appropriate response body and header handling.

3

4

## Capabilities

5

6

### Response Generator Traits

7

8

Base traits for building HTTP responses with different characteristics.

9

10

```scala { .api }

11

/**

12

* Base trait for all response generators

13

*/

14

trait ResponseGenerator extends Any {

15

def status: Status

16

}

17

18

/**

19

* Generator for responses without body content

20

*/

21

trait EmptyResponseGenerator[F[_], G[_]] extends Any with 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

* Generator for responses with optional body content

28

*/

29

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

30

def liftG: FunctionK[G, F]

31

32

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

33

def apply[A](body: G[A])(implicit F: Monad[F], w: EntityEncoder[G, A]): F[Response[G]]

34

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

35

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

36

}

37

38

/**

39

* Generator for redirect responses requiring Location header

40

*/

41

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

42

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

43

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

44

}

45

46

/**

47

* Generator for 401 Unauthorized responses requiring WWW-Authenticate header

48

*/

49

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

50

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

51

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

52

}

53

54

/**

55

* Generator for 405 Method Not Allowed responses requiring Allow header

56

*/

57

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

58

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

59

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

60

}

61

```

62

63

### Success Responses (2xx)

64

65

Status codes indicating successful request processing.

66

67

```scala { .api }

68

// 2xx Success Status Codes

69

val Ok: Status.Ok.type // 200

70

val Created: Status.Created.type // 201

71

val Accepted: Status.Accepted.type // 202

72

val NonAuthoritativeInformation: Status.NonAuthoritativeInformation.type // 203

73

val NoContent: Status.NoContent.type // 204

74

val ResetContent: Status.ResetContent.type // 205

75

val PartialContent: Status.PartialContent.type // 206

76

val MultiStatus: Status.MultiStatus.type // 207

77

val AlreadyReported: Status.AlreadyReported.type // 208

78

val IMUsed: Status.IMUsed.type // 226

79

```

80

81

**Usage Examples:**

82

83

```scala

84

import org.http4s.dsl.io._

85

import cats.effect.IO

86

87

val routes = HttpRoutes.of[IO] {

88

// Simple OK response

89

case GET -> Root / "hello" =>

90

Ok("Hello, World!")

91

92

// Created with response body

93

case POST -> Root / "users" =>

94

Created("User created successfully")

95

96

// No content response

97

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

98

NoContent()

99

100

// Response with custom headers

101

case GET -> Root / "data" =>

102

Ok("Response data", Header("X-Custom", "value"))

103

104

// JSON response (with appropriate EntityEncoder)

105

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

106

val user = User(id, "John Doe")

107

Ok(user.asJson)

108

}

109

```

110

111

### Redirection Responses (3xx)

112

113

Status codes for URL redirection with automatic Location header handling.

114

115

```scala { .api }

116

// 3xx Redirection Status Codes

117

val MultipleChoices: Status.MultipleChoices.type // 300

118

val MovedPermanently: Status.MovedPermanently.type // 301

119

val Found: Status.Found.type // 302

120

val SeeOther: Status.SeeOther.type // 303

121

val NotModified: Status.NotModified.type // 304

122

val TemporaryRedirect: Status.TemporaryRedirect.type // 307

123

val PermanentRedirect: Status.PermanentRedirect.type // 308

124

```

125

126

**Usage Examples:**

127

128

```scala

129

import org.http4s.dsl.io._

130

import org.http4s.headers.Location

131

import org.http4s.Uri

132

133

val routes = HttpRoutes.of[IO] {

134

// Permanent redirect

135

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

136

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

137

138

// Temporary redirect with body

139

case GET -> Root / "temp" =>

140

Found(Location(Uri.unsafeFromString("/temporary-location")), "Redirecting...")

141

142

// Post-redirect-get pattern

143

case POST -> Root / "submit" =>

144

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

145

146

// Not modified (for caching)

147

case GET -> Root / "resource" if notModified =>

148

NotModified()

149

}

150

```

151

152

### Client Error Responses (4xx)

153

154

Status codes indicating client-side errors with specialized response generators.

155

156

```scala { .api }

157

// 4xx Client Error Status Codes

158

val BadRequest: Status.BadRequest.type // 400

159

val Unauthorized: Status.Unauthorized.type // 401

160

val PaymentRequired: Status.PaymentRequired.type // 402

161

val Forbidden: Status.Forbidden.type // 403

162

val NotFound: Status.NotFound.type // 404

163

val MethodNotAllowed: Status.MethodNotAllowed.type // 405

164

val NotAcceptable: Status.NotAcceptable.type // 406

165

val ProxyAuthenticationRequired: Status.ProxyAuthenticationRequired.type // 407

166

val RequestTimeout: Status.RequestTimeout.type // 408

167

val Conflict: Status.Conflict.type // 409

168

val Gone: Status.Gone.type // 410

169

val LengthRequired: Status.LengthRequired.type // 411

170

val PreconditionFailed: Status.PreconditionFailed.type // 412

171

val PayloadTooLarge: Status.PayloadTooLarge.type // 413

172

val UriTooLong: Status.UriTooLong.type // 414

173

val UnsupportedMediaType: Status.UnsupportedMediaType.type // 415

174

val RangeNotSatisfiable: Status.RangeNotSatisfiable.type // 416

175

val ExpectationFailed: Status.ExpectationFailed.type // 417

176

val MisdirectedRequest: Status.MisdirectedRequest.type // 421

177

val UnprocessableEntity: Status.UnprocessableEntity.type // 422

178

val Locked: Status.Locked.type // 423

179

val FailedDependency: Status.FailedDependency.type // 424

180

val TooEarly: Status.TooEarly.type // 425

181

val UpgradeRequired: Status.UpgradeRequired.type // 426

182

val PreconditionRequired: Status.PreconditionRequired.type // 428

183

val TooManyRequests: Status.TooManyRequests.type // 429

184

val RequestHeaderFieldsTooLarge: Status.RequestHeaderFieldsTooLarge.type // 431

185

val UnavailableForLegalReasons: Status.UnavailableForLegalReasons.type // 451

186

```

187

188

**Usage Examples:**

189

190

```scala

191

import org.http4s.dsl.io._

192

import org.http4s.headers.{`WWW-Authenticate`, Allow}

193

194

val routes = HttpRoutes.of[IO] {

195

// Bad request with validation errors

196

case POST -> Root / "users" =>

197

// Validation logic

198

if (invalidInput) {

199

BadRequest("Invalid user data provided")

200

} else {

201

Created("User created")

202

}

203

204

// Unauthorized with WWW-Authenticate header

205

case GET -> Root / "protected" =>

206

Unauthorized(`WWW-Authenticate`(Challenge("Bearer", "api")))

207

208

// Not found with helpful message

209

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

210

// Lookup user

211

userService.findById(id).flatMap {

212

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

213

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

214

}

215

216

// Method not allowed with Allow header

217

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

218

MethodNotAllowed(Allow(Set(GET, HEAD)))

219

220

// Conflict for duplicate resources

221

case POST -> Root / "users" =>

222

// Check for existing user

223

if (userExists) {

224

Conflict("User already exists")

225

} else {

226

Created("User created")

227

}

228

}

229

```

230

231

### Server Error Responses (5xx)

232

233

Status codes indicating server-side errors and service unavailability.

234

235

```scala { .api }

236

// 5xx Server Error Status Codes

237

val InternalServerError: Status.InternalServerError.type // 500

238

val NotImplemented: Status.NotImplemented.type // 501

239

val BadGateway: Status.BadGateway.type // 502

240

val ServiceUnavailable: Status.ServiceUnavailable.type // 503

241

val GatewayTimeout: Status.GatewayTimeout.type // 504

242

val HttpVersionNotSupported: Status.HttpVersionNotSupported.type // 505

243

val VariantAlsoNegotiates: Status.VariantAlsoNegotiates.type // 506

244

val InsufficientStorage: Status.InsufficientStorage.type // 507

245

val LoopDetected: Status.LoopDetected.type // 508

246

val NotExtended: Status.NotExtended.type // 510

247

val NetworkAuthenticationRequired: Status.NetworkAuthenticationRequired.type // 511

248

```

249

250

**Usage Examples:**

251

252

```scala

253

import org.http4s.dsl.io._

254

255

val routes = HttpRoutes.of[IO] {

256

// Handle application errors

257

case GET -> Root / "data" =>

258

dataService.fetchData().attempt.flatMap {

259

case Right(data) => Ok(data.asJson)

260

case Left(error) =>

261

logger.error("Data fetch failed", error)

262

InternalServerError("Unable to fetch data")

263

}

264

265

// Service temporarily unavailable

266

case GET -> Root / "maintenance" =>

267

ServiceUnavailable("Service under maintenance")

268

269

// Not implemented features

270

case PUT -> Root / "beta-feature" =>

271

NotImplemented("Feature not yet implemented")

272

}

273

```

274

275

### Informational Responses (1xx)

276

277

Status codes for informational responses (less commonly used).

278

279

```scala { .api }

280

// 1xx Informational Status Codes

281

val Continue: Status.Continue.type // 100

282

val SwitchingProtocols: Status.SwitchingProtocols.type // 101

283

val Processing: Status.Processing.type // 102

284

val EarlyHints: Status.EarlyHints.type // 103

285

```

286

287

288

### Content Type and Encoding

289

290

Response generators automatically handle content types and encoding based on the `EntityEncoder` instances.

291

292

```scala

293

import org.http4s.dsl.io._

294

import org.http4s.circe._

295

import io.circe.generic.auto._

296

297

val routes = HttpRoutes.of[IO] {

298

// JSON response (with circe EntityEncoder)

299

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

300

val users = List(User("Alice", 25), User("Bob", 30))

301

Ok(users.asJson) // Content-Type: application/json

302

303

// Plain text response

304

case GET -> Root / "health" =>

305

Ok("OK") // Content-Type: text/plain

306

307

// HTML response

308

case GET -> Root =>

309

Ok("<html><body><h1>Welcome</h1></body></html>")

310

.map(_.withContentType(`Content-Type`(MediaType.text.html)))

311

}

312

```

313

314

## Error Handling Best Practices

315

316

The DSL enables consistent error handling patterns:

317

318

```scala

319

import org.http4s.dsl.io._

320

321

val routes = HttpRoutes.of[IO] {

322

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

323

userService.findById(id).flatMap {

324

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

325

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

326

}.handleErrorWith { error =>

327

logger.error(s"Error fetching user $id", error)

328

InternalServerError("Internal server error")

329

}

330

}

331

```

332

333

## Type Safety

334

335

- All status constants are singleton types for compile-time safety

336

- Response generators preserve effect type `F[_]` and entity type information

337

- EntityEncoder instances ensure type-safe response body serialization

338

- Headers are type-safe through the http4s header system