Skip to content

Commit 89e796d

Browse files
committed
feat(http-request): rename helpers and add default headers
- Rename httpGetJson → httpJson (supports all HTTP methods) - Rename httpGetText → httpText (supports all HTTP methods) - Add default headers for httpJson: - Accept: application/json (always) - Content-Type: application/json (when body present) - Add default headers for httpText: - Accept: text/plain (always) - Content-Type: text/plain (when body present) - User-provided headers override defaults - Add 8 new tests for default header behavior (67 total tests) BREAKING CHANGE: httpGetJson and httpGetText have been removed. Use httpJson and httpText instead.
1 parent c2e623d commit 89e796d

2 files changed

Lines changed: 341 additions & 43 deletions

File tree

src/http-request.ts

Lines changed: 99 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,8 +1034,12 @@ async function httpDownloadAttempt(
10341034
}
10351035

10361036
/**
1037-
* Perform a GET request and parse JSON response.
1038-
* Convenience wrapper around `httpRequest` for common JSON API calls.
1037+
* Perform an HTTP request and parse JSON response.
1038+
* Convenience wrapper around `httpRequest` for JSON API calls.
1039+
* Automatically sets appropriate headers for JSON requests:
1040+
* - `Accept: application/json` (always)
1041+
* - `Content-Type: application/json` (when body is present)
1042+
* User-provided headers override these defaults.
10391043
*
10401044
* @template T - Expected JSON response type (defaults to `unknown`)
10411045
* @param url - The URL to request (must start with http:// or https://)
@@ -1045,35 +1049,65 @@ async function httpDownloadAttempt(
10451049
*
10461050
* @example
10471051
* ```ts
1048-
* // Simple JSON GET
1049-
* const data = await httpGetJson('https://api.example.com/data')
1052+
* // Simple JSON GET (automatically sets Accept: application/json)
1053+
* const data = await httpJson('https://api.example.com/data')
10501054
* console.log(data)
10511055
*
10521056
* // With type safety
10531057
* interface User { id: number; name: string; email: string }
1054-
* const user = await httpGetJson<User>('https://api.example.com/user/123')
1058+
* const user = await httpJson<User>('https://api.example.com/user/123')
10551059
* console.log(user.name, user.email)
10561060
*
1057-
* // With custom headers
1058-
* const data = await httpGetJson('https://api.example.com/data', {
1059-
* headers: {
1060-
* 'Authorization': 'Bearer token123',
1061-
* 'Accept': 'application/json'
1062-
* }
1061+
* // POST with JSON body (automatically sets Content-Type: application/json)
1062+
* const result = await httpJson('https://api.example.com/users', {
1063+
* method: 'POST',
1064+
* body: JSON.stringify({ name: 'Alice', email: 'alice@example.com' })
10631065
* })
10641066
*
1065-
* // With retries
1066-
* const data = await httpGetJson('https://api.example.com/data', {
1067+
* // With custom headers and retries
1068+
* const data = await httpJson('https://api.example.com/data', {
1069+
* headers: {
1070+
* 'Authorization': 'Bearer token123'
1071+
* },
10671072
* retries: 3,
10681073
* retryDelay: 1000
10691074
* })
10701075
* ```
10711076
*/
1072-
export async function httpGetJson<T = unknown>(
1077+
export async function httpJson<T = unknown>(
10731078
url: string,
10741079
options?: HttpRequestOptions | undefined,
10751080
): Promise<T> {
1076-
const response = await httpRequest(url, { ...options, method: 'GET' })
1081+
const {
1082+
body,
1083+
headers = {},
1084+
...restOptions
1085+
} = {
1086+
__proto__: null,
1087+
...options,
1088+
} as HttpRequestOptions
1089+
1090+
// Set default headers for JSON requests
1091+
const defaultHeaders: Record<string, string> = {
1092+
Accept: 'application/json',
1093+
}
1094+
1095+
// Add Content-Type when body is present
1096+
if (body !== undefined) {
1097+
defaultHeaders['Content-Type'] = 'application/json'
1098+
}
1099+
1100+
// Merge headers: user headers override defaults
1101+
const mergedHeaders = {
1102+
...defaultHeaders,
1103+
...headers,
1104+
}
1105+
1106+
const response = await httpRequest(url, {
1107+
body,
1108+
headers: mergedHeaders,
1109+
...restOptions,
1110+
})
10771111

10781112
if (!response.ok) {
10791113
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
@@ -1087,8 +1121,12 @@ export async function httpGetJson<T = unknown>(
10871121
}
10881122

10891123
/**
1090-
* Perform a GET request and return text response.
1124+
* Perform an HTTP request and return text response.
10911125
* Convenience wrapper around `httpRequest` for fetching text content.
1126+
* Automatically sets appropriate headers for text requests:
1127+
* - `Accept: text/plain` (always)
1128+
* - `Content-Type: text/plain` (when body is present)
1129+
* User-provided headers override these defaults.
10921130
*
10931131
* @param url - The URL to request (must start with http:// or https://)
10941132
* @param options - Request configuration options
@@ -1097,32 +1135,68 @@ export async function httpGetJson<T = unknown>(
10971135
*
10981136
* @example
10991137
* ```ts
1100-
* // Fetch HTML
1101-
* const html = await httpGetText('https://example.com')
1138+
* // Fetch HTML (automatically sets Accept: text/plain)
1139+
* const html = await httpText('https://example.com')
11021140
* console.log(html.includes('<!DOCTYPE html>'))
11031141
*
11041142
* // Fetch plain text
1105-
* const text = await httpGetText('https://example.com/file.txt')
1143+
* const text = await httpText('https://example.com/file.txt')
11061144
* console.log(text)
11071145
*
1108-
* // With custom headers
1109-
* const text = await httpGetText('https://example.com/data.txt', {
1146+
* // POST with text body (automatically sets Content-Type: text/plain)
1147+
* const result = await httpText('https://example.com/api', {
1148+
* method: 'POST',
1149+
* body: 'raw text data'
1150+
* })
1151+
*
1152+
* // With custom headers (override defaults)
1153+
* const text = await httpText('https://example.com/data.txt', {
11101154
* headers: {
1111-
* 'Authorization': 'Bearer token123'
1155+
* 'Authorization': 'Bearer token123',
1156+
* 'Accept': 'text/html' // Override default Accept header
11121157
* }
11131158
* })
11141159
*
11151160
* // With timeout
1116-
* const text = await httpGetText('https://example.com/large-file.txt', {
1161+
* const text = await httpText('https://example.com/large-file.txt', {
11171162
* timeout: 60000 // 1 minute
11181163
* })
11191164
* ```
11201165
*/
1121-
export async function httpGetText(
1166+
export async function httpText(
11221167
url: string,
11231168
options?: HttpRequestOptions | undefined,
11241169
): Promise<string> {
1125-
const response = await httpRequest(url, { ...options, method: 'GET' })
1170+
const {
1171+
body,
1172+
headers = {},
1173+
...restOptions
1174+
} = {
1175+
__proto__: null,
1176+
...options,
1177+
} as HttpRequestOptions
1178+
1179+
// Set default headers for text requests
1180+
const defaultHeaders: Record<string, string> = {
1181+
Accept: 'text/plain',
1182+
}
1183+
1184+
// Add Content-Type when body is present
1185+
if (body !== undefined) {
1186+
defaultHeaders['Content-Type'] = 'text/plain'
1187+
}
1188+
1189+
// Merge headers: user headers override defaults
1190+
const mergedHeaders = {
1191+
...defaultHeaders,
1192+
...headers,
1193+
}
1194+
1195+
const response = await httpRequest(url, {
1196+
body,
1197+
headers: mergedHeaders,
1198+
...restOptions,
1199+
})
11261200

11271201
if (!response.ok) {
11281202
throw new Error(`HTTP ${response.status}: ${response.statusText}`)

0 commit comments

Comments
 (0)