or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

auth.mdbase-controller.mddecorators.mdindex.mdmiddleware.mdresults.mdserver.md
tile.json

results.mddocs/

0

# Action Results

1

2

Comprehensive set of action result classes for structured HTTP responses. Implements the action result pattern for type-safe response handling with content negotiation support and automatic HTTP response generation.

3

4

## Capabilities

5

6

### Core Result Interface

7

8

Base interface that all action results implement for consistent response handling.

9

10

```typescript { .api }

11

/**

12

* Interface for HTTP action results that can be executed to produce HTTP responses

13

*/

14

interface IHttpActionResult {

15

/** Executes the action result to produce an HTTP response message */

16

executeAsync(): Promise<HttpResponseMessage>;

17

}

18

```

19

20

### HTTP Response Message

21

22

Core response message class containing status, headers, and content.

23

24

```typescript { .api }

25

/**

26

* HTTP response message containing status code, headers, and content

27

*/

28

class HttpResponseMessage {

29

/** Response content */

30

content: HttpContent;

31

/** HTTP response headers */

32

headers: OutgoingHttpHeaders;

33

/** HTTP status code */

34

statusCode: number;

35

36

/**

37

* Creates a new HTTP response message

38

* @param statusCode - HTTP status code (defaults to 200)

39

*/

40

constructor(statusCode?: number);

41

}

42

```

43

44

### Success Result Classes

45

46

Action results for successful HTTP responses (2xx status codes).

47

48

```typescript { .api }

49

/**

50

* Returns a 200 OK response without content

51

*/

52

class OkResult implements IHttpActionResult {

53

executeAsync(): Promise<HttpResponseMessage>;

54

}

55

56

/**

57

* Returns a 200 OK response with negotiated content

58

*/

59

class OkNegotiatedContentResult<T> implements IHttpActionResult {

60

constructor(content: T);

61

executeAsync(): Promise<HttpResponseMessage>;

62

}

63

64

/**

65

* Returns a 201 Created response with location and content

66

*/

67

class CreatedNegotiatedContentResult<T> implements IHttpActionResult {

68

constructor(location: string | URL, content: T);

69

executeAsync(): Promise<HttpResponseMessage>;

70

}

71

72

/**

73

* Returns a JSON response with custom status code

74

*/

75

class JsonResult implements IHttpActionResult {

76

readonly json: unknown;

77

readonly statusCode: number;

78

79

constructor(json: unknown, statusCode: number);

80

executeAsync(): Promise<HttpResponseMessage>;

81

}

82

83

/**

84

* Returns a streaming response

85

*/

86

class StreamResult implements IHttpActionResult {

87

constructor(readableStream: Readable, contentType: string, statusCode?: number);

88

executeAsync(): Promise<HttpResponseMessage>;

89

}

90

```

91

92

### Error Result Classes

93

94

Action results for error HTTP responses (4xx and 5xx status codes).

95

96

```typescript { .api }

97

/**

98

* Returns a 400 Bad Request response

99

*/

100

class BadRequestResult implements IHttpActionResult {

101

executeAsync(): Promise<HttpResponseMessage>;

102

}

103

104

/**

105

* Returns a 400 Bad Request response with error message

106

*/

107

class BadRequestErrorMessageResult implements IHttpActionResult {

108

constructor(message: string);

109

executeAsync(): Promise<HttpResponseMessage>;

110

}

111

112

/**

113

* Returns a 404 Not Found response

114

*/

115

class NotFoundResult implements IHttpActionResult {

116

executeAsync(): Promise<HttpResponseMessage>;

117

}

118

119

/**

120

* Returns a 409 Conflict response

121

*/

122

class ConflictResult implements IHttpActionResult {

123

executeAsync(): Promise<HttpResponseMessage>;

124

}

125

126

/**

127

* Returns a 500 Internal Server Error response

128

*/

129

class InternalServerErrorResult implements IHttpActionResult {

130

executeAsync(): Promise<HttpResponseMessage>;

131

}

132

133

/**

134

* Returns a 500 Internal Server Error response with exception details

135

*/

136

class ExceptionResult implements IHttpActionResult {

137

constructor(error: Error);

138

executeAsync(): Promise<HttpResponseMessage>;

139

}

140

```

141

142

### Specialized Result Classes

143

144

Action results for specialized HTTP responses and redirects.

145

146

```typescript { .api }

147

/**

148

* Returns a redirect response (302 Found by default)

149

*/

150

class RedirectResult implements IHttpActionResult {

151

constructor(uri: string | URL);

152

executeAsync(): Promise<HttpResponseMessage>;

153

}

154

155

/**

156

* Returns a response with custom status code

157

*/

158

class StatusCodeResult implements IHttpActionResult {

159

constructor(statusCode: number);

160

executeAsync(): Promise<HttpResponseMessage>;

161

}

162

163

/**

164

* Returns a response using a custom HTTP response message

165

*/

166

class ResponseMessageResult implements IHttpActionResult {

167

constructor(message: HttpResponseMessage);

168

executeAsync(): Promise<HttpResponseMessage>;

169

}

170

```

171

172

**Usage Examples:**

173

174

```typescript

175

import { controller, httpGet, httpPost, BaseHttpController } from "inversify-express-utils";

176

import {

177

JsonResult,

178

RedirectResult,

179

StreamResult,

180

BadRequestErrorMessageResult

181

} from "inversify-express-utils";

182

183

@controller("/files")

184

class FileController extends BaseHttpController {

185

@httpGet("/:id/download")

186

async downloadFile(@requestParam("id") id: string) {

187

const file = await this.fileService.getFile(id);

188

189

if (!file) {

190

return new NotFoundResult();

191

}

192

193

const stream = this.fileService.createReadStream(file.path);

194

return new StreamResult(stream, file.mimeType, 200);

195

}

196

197

@httpPost("/upload")

198

async uploadFile(@requestBody() fileData: any) {

199

if (!fileData || !fileData.name) {

200

return new BadRequestErrorMessageResult("File name is required");

201

}

202

203

try {

204

const uploadedFile = await this.fileService.upload(fileData);

205

const location = `/files/${uploadedFile.id}`;

206

return new CreatedNegotiatedContentResult(location, uploadedFile);

207

} catch (error) {

208

return new ExceptionResult(error);

209

}

210

}

211

212

@httpGet("/stats")

213

async getStats(@queryParam("format") format: string) {

214

const stats = await this.fileService.getStats();

215

216

if (format === "json") {

217

return new JsonResult(stats, 200);

218

}

219

220

return new OkNegotiatedContentResult(stats);

221

}

222

223

@httpGet("/:id/redirect-to-cdn")

224

async redirectToCdn(@requestParam("id") id: string) {

225

const file = await this.fileService.getFile(id);

226

227

if (!file) {

228

return new NotFoundResult();

229

}

230

231

const cdnUrl = `https://cdn.example.com/files/${file.hash}`;

232

return new RedirectResult(cdnUrl);

233

}

234

235

@httpPost("/custom-response")

236

async customResponse() {

237

// Create custom HTTP response message

238

const response = new HttpResponseMessage(202);

239

response.headers["X-Processing-Id"] = "12345";

240

response.headers["Retry-After"] = "30";

241

response.content = new JsonContent({

242

message: "File processing started",

243

status: "queued"

244

});

245

246

return new ResponseMessageResult(response);

247

}

248

}

249

```

250

251

### Content Classes

252

253

HTTP content classes used by action results for response content handling.

254

255

```typescript { .api }

256

/**

257

* Abstract base class for HTTP content

258

*/

259

abstract class HttpContent {

260

/** Content headers */

261

readonly headers: OutgoingHttpHeaders;

262

263

/** Reads the content asynchronously */

264

abstract readAsync(): Promise<unknown>;

265

}

266

267

/**

268

* JSON content implementation

269

*/

270

class JsonContent extends HttpContent {

271

constructor(json: unknown);

272

readAsync(): Promise<string>;

273

}

274

275

/**

276

* String content implementation

277

*/

278

class StringContent extends HttpContent {

279

constructor(content: string);

280

readAsync(): Promise<string>;

281

}

282

283

/**

284

* Stream content implementation

285

*/

286

class StreamContent extends HttpContent {

287

constructor(stream: Readable, mediaType: string);

288

readAsync(): Promise<Readable>;

289

}

290

```

291

292

**Usage Examples:**

293

294

```typescript

295

import { HttpResponseMessage, JsonContent, StringContent } from "inversify-express-utils";

296

297

@controller("/content")

298

class ContentController extends BaseHttpController {

299

@httpGet("/custom-json")

300

async customJson() {

301

const response = new HttpResponseMessage(200);

302

response.content = new JsonContent({

303

data: "custom data",

304

timestamp: Date.now()

305

});

306

response.headers["Cache-Control"] = "no-cache";

307

308

return this.responseMessage(response);

309

}

310

311

@httpGet("/custom-text")

312

async customText() {

313

const response = new HttpResponseMessage(200);

314

response.content = new StringContent(

315

"Custom plain text response",

316

"text/plain; charset=utf-8"

317

);

318

319

return this.responseMessage(response);

320

}

321

322

@httpGet("/xml-data")

323

async xmlData() {

324

const xmlData = "<root><item>data</item></root>";

325

const response = new HttpResponseMessage(200);

326

response.content = new StringContent(xmlData, "application/xml");

327

328

return this.responseMessage(response);

329

}

330

}

331

```

332

333

### Status Codes

334

335

The library uses standard HTTP status codes from the `http-status-codes` package for consistency.

336

337

```typescript { .api }

338

// Common status codes used by action results

339

const StatusCodes = {

340

OK: 200,

341

CREATED: 201,

342

ACCEPTED: 202,

343

NO_CONTENT: 204,

344

FOUND: 302,

345

BAD_REQUEST: 400,

346

UNAUTHORIZED: 401,

347

FORBIDDEN: 403,

348

NOT_FOUND: 404,

349

CONFLICT: 409,

350

INTERNAL_SERVER_ERROR: 500

351

};

352

```