or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mderrors.mdhooks.mdhttp-methods.mdindex.mdinstances.mdresponses.mdretry.md
tile.json

responses.mddocs/

0

# Response Handling

1

2

Enhanced response promises with body method shortcuts and automatic error handling for non-2xx status codes. Ky extends the standard Response object with convenient methods for accessing response data.

3

4

## Capabilities

5

6

### Response Promise Interface

7

8

The ResponsePromise extends the standard Promise with body method shortcuts that automatically set appropriate Accept headers.

9

10

```typescript { .api }

11

interface ResponsePromise<T = unknown> extends Promise<KyResponse<T>> {

12

/** Get response body as ArrayBuffer */

13

arrayBuffer(): Promise<ArrayBuffer>;

14

/** Get response body as Blob */

15

blob(): Promise<Blob>;

16

/** Get response body as FormData */

17

formData(): Promise<FormData>;

18

/** Get response body as raw bytes (when supported by runtime) */

19

bytes(): Promise<Uint8Array>;

20

/** Get response body as JSON with type safety */

21

json<J = T>(): Promise<J>;

22

/** Get response body as text string */

23

text(): Promise<string>;

24

}

25

```

26

27

**Usage Examples:**

28

29

```typescript

30

import ky from "ky";

31

32

// JSON response with automatic type inference

33

interface User {

34

id: number;

35

name: string;

36

email: string;

37

}

38

39

const user = await ky.get("https://api.example.com/user/123").json<User>();

40

console.log(user.name); // TypeScript knows this is a string

41

42

// Text response

43

const csvData = await ky.get("https://api.example.com/data.csv").text();

44

console.log(csvData);

45

46

// Binary data as ArrayBuffer

47

const fileBuffer = await ky.get("https://api.example.com/file.pdf").arrayBuffer();

48

const uint8Array = new Uint8Array(fileBuffer);

49

50

// Blob for file handling

51

const imageBlob = await ky.get("https://api.example.com/image.jpg").blob();

52

const imageUrl = URL.createObjectURL(imageBlob);

53

54

// FormData response

55

const formResponse = await ky.get("https://api.example.com/form-data").formData();

56

console.log(formResponse.get("field-name"));

57

58

// Raw bytes (when supported)

59

if (typeof Response.prototype.bytes === "function") {

60

const rawBytes = await ky.get("https://api.example.com/binary").bytes();

61

console.log(rawBytes instanceof Uint8Array); // true

62

}

63

```

64

65

### Enhanced Response Object

66

67

Ky responses extend the standard Response with enhanced JSON methods.

68

69

```typescript { .api }

70

interface KyResponse<T = unknown> extends Response {

71

/** Enhanced JSON method with type safety */

72

json<J = T>(): Promise<J>;

73

}

74

```

75

76

**Usage Examples:**

77

78

```typescript

79

import ky from "ky";

80

81

// Access full response object

82

const response = await ky.get("https://api.example.com/data");

83

84

// Check response properties

85

console.log("Status:", response.status);

86

console.log("Status Text:", response.statusText);

87

console.log("Headers:", Object.fromEntries(response.headers));

88

console.log("OK:", response.ok);

89

90

// Process response based on content type

91

const contentType = response.headers.get("content-type");

92

93

if (contentType?.includes("application/json")) {

94

const data = await response.json();

95

console.log("JSON data:", data);

96

} else if (contentType?.includes("text/")) {

97

const text = await response.text();

98

console.log("Text data:", text);

99

} else {

100

const buffer = await response.arrayBuffer();

101

console.log("Binary data:", buffer.byteLength, "bytes");

102

}

103

```

104

105

### Automatic Header Handling

106

107

Response body methods automatically set appropriate Accept headers for content negotiation.

108

109

**Usage Examples:**

110

111

```typescript

112

import ky from "ky";

113

114

// Automatically sets Accept: application/json

115

const jsonData = await ky.get("https://api.example.com/data").json();

116

117

// Automatically sets Accept: text/*

118

const textData = await ky.get("https://api.example.com/text").text();

119

120

// Automatically sets Accept: multipart/form-data

121

const formData = await ky.get("https://api.example.com/form").formData();

122

123

// Automatically sets Accept: */*

124

const binaryData = await ky.get("https://api.example.com/binary").arrayBuffer();

125

const blobData = await ky.get("https://api.example.com/file").blob();

126

127

// Manual Accept header override

128

const customData = await ky.get("https://api.example.com/custom", {

129

headers: { "Accept": "application/vnd.api+json" }

130

}).json();

131

```

132

133

### JSON Response Special Cases

134

135

Ky handles JSON responses with special behaviors for edge cases.

136

137

**Usage Examples:**

138

139

```typescript

140

import ky from "ky";

141

142

// Empty response (status 204) returns empty string

143

const noContent = await ky.delete("https://api.example.com/resource/123").json();

144

console.log(noContent); // ""

145

146

// Empty body returns empty string instead of throwing parse error

147

const emptyResponse = await ky.get("https://api.example.com/empty").json();

148

console.log(emptyResponse); // ""

149

150

// Custom JSON parsing with error handling

151

const safeClient = ky.create({

152

parseJson: (text) => {

153

if (!text.trim()) {

154

return null;

155

}

156

try {

157

return JSON.parse(text);

158

} catch (error) {

159

console.warn("JSON parse error:", error);

160

return { error: "Invalid JSON", originalText: text };

161

}

162

}

163

});

164

165

const safeData = await safeClient.get("https://api.example.com/maybe-json").json();

166

```

167

168

### Response with TypeScript Generics

169

170

Leverage TypeScript generics for type-safe response handling.

171

172

**Usage Examples:**

173

174

```typescript

175

import ky from "ky";

176

177

// Generic at call site

178

interface ApiResponse<T> {

179

data: T;

180

status: string;

181

timestamp: string;

182

}

183

184

interface Product {

185

id: number;

186

name: string;

187

price: number;

188

}

189

190

// Type the entire response

191

const productResponse = await ky.get("https://api.example.com/products/123")

192

.json<ApiResponse<Product>>();

193

194

console.log(productResponse.data.name); // TypeScript knows this is string

195

console.log(productResponse.data.price); // TypeScript knows this is number

196

197

// Generic at instance level

198

const typedClient = ky.create({ prefixUrl: "https://api.example.com" });

199

200

const users = await typedClient.get("users").json<User[]>();

201

const user = await typedClient.get("users/123").json<User>();

202

const stats = await typedClient.get("stats").json<{ count: number; average: number }>();

203

204

// Conditional response types

205

type ApiResult<T> = {

206

success: true;

207

data: T;

208

} | {

209

success: false;

210

error: string;

211

};

212

213

const result = await ky.post("https://api.example.com/process", {

214

json: { input: "data" }

215

}).json<ApiResult<{ output: string }>>();

216

217

if (result.success) {

218

console.log(result.data.output); // TypeScript knows this exists

219

} else {

220

console.error(result.error); // TypeScript knows this exists

221

}

222

```

223

224

### Response Streaming

225

226

Handle streaming responses with progress tracking.

227

228

**Usage Examples:**

229

230

```typescript

231

import ky from "ky";

232

233

// Stream large file with progress

234

const downloadLargeFile = async () => {

235

const response = await ky.get("https://api.example.com/large-file.zip", {

236

onDownloadProgress: (progress, chunk) => {

237

console.log(`Downloaded: ${Math.round(progress.percent * 100)}%`);

238

console.log(`Chunk size: ${chunk.length} bytes`);

239

}

240

});

241

242

return response.arrayBuffer();

243

};

244

245

// Process streaming JSON responses

246

const processStreamingData = async () => {

247

const response = await ky.get("https://api.example.com/streaming-data");

248

249

const reader = response.body?.getReader();

250

const decoder = new TextDecoder();

251

252

if (reader) {

253

while (true) {

254

const { done, value } = await reader.read();

255

if (done) break;

256

257

const chunk = decoder.decode(value, { stream: true });

258

console.log("Received chunk:", chunk);

259

}

260

}

261

};

262

```

263

264

## Types

265

266

```typescript { .api }

267

interface ResponsePromise<T = unknown> extends Promise<KyResponse<T>> {

268

arrayBuffer(): Promise<ArrayBuffer>;

269

blob(): Promise<Blob>;

270

formData(): Promise<FormData>;

271

bytes(): Promise<Uint8Array>;

272

json<J = T>(): Promise<J>;

273

text(): Promise<string>;

274

}

275

276

interface KyResponse<T = unknown> extends Response {

277

json<J = T>(): Promise<J>;

278

}

279

280

interface KyRequest<T = unknown> extends Request {

281

json<J = T>(): Promise<J>;

282

}

283

```