Skip to content

Commit 8217304

Browse files
committed
fix: header parsing correctly
1 parent 26d22df commit 8217304

File tree

5 files changed

+160
-21
lines changed

5 files changed

+160
-21
lines changed

projects/openapi-fetch-angular/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "openapi-fetch-angular",
33
"description": "Fast, typesafe fetch client for your OpenAPI schema. Works with Angular HTTPClient API.",
4-
"version": "0.1.1",
4+
"version": "0.1.2",
55
"license": "MIT",
66
"author": "Luna Simons <[email protected]> (https://bddvlpr.com)",
77
"contributors": [

projects/openapi-fetch-angular/src/lib/openapi-client.service.spec.ts

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,131 @@ describe('OpenAPIClientService', () => {
103103
expect(httpMock.expectOne('/query-params?string=10')).toBeDefined();
104104
});
105105
});
106+
107+
describe('headers', () => {
108+
it('should correctly type the headers', () => {
109+
service
110+
// @ts-expect-error - missing required parameter
111+
.get('/header-params')
112+
.subscribe(({ response }) => expect(response).toBeDefined());
113+
let req = httpMock.expectOne('/header-params');
114+
expect(req).toBeDefined();
115+
116+
service
117+
.get('/header-params', {
118+
// @ts-expect-error - empty object
119+
params: {},
120+
})
121+
.subscribe(({ response }) => expect(response).toBeDefined());
122+
req = httpMock.expectOne('/header-params');
123+
expect(req).toBeDefined();
124+
125+
service
126+
.get('/header-params', {
127+
params: {
128+
header: {
129+
// @ts-expect-error - wrong type
130+
'x-required-header': 123,
131+
},
132+
},
133+
})
134+
.subscribe(({ response }) => expect(response).toBeDefined());
135+
req = httpMock.expectOne('/header-params');
136+
expect(req).toBeDefined();
137+
138+
service
139+
.get('/header-params', {
140+
params: {
141+
header: {
142+
'x-required-header': '123',
143+
},
144+
},
145+
})
146+
.subscribe(({ response }) => expect(response).toBeDefined());
147+
req = httpMock.expectOne('/header-params');
148+
expect(req).toBeDefined();
149+
});
150+
151+
it('should correctly send headers', () => {
152+
service
153+
.get('/header-params', {
154+
params: {
155+
header: {
156+
'x-required-header': '123',
157+
},
158+
},
159+
})
160+
.subscribe(({ response }) =>
161+
expect(response.headers.get('x-required-header-server')).toEqual(
162+
'123',
163+
),
164+
);
165+
const req = httpMock.expectOne('/header-params');
166+
167+
expect(req.request.headers.get('Content-Type')).toEqual(
168+
'application/json',
169+
);
170+
expect(req.request.headers.get('x-required-header')).toEqual('123');
171+
172+
req.flush(null, { headers: { 'x-required-header-server': '123' } });
173+
});
174+
});
175+
176+
describe('headers (promise)', () => {
177+
it('should correctly type the headers', () => {
178+
// @ts-expect-error - missing required parameter
179+
service.getPromise('/header-params');
180+
expect(httpMock.expectOne('/header-params')).toBeDefined();
181+
182+
service.getPromise('/header-params', {
183+
// @ts-expect-error - empty object
184+
params: {},
185+
});
186+
expect(httpMock.expectOne('/header-params')).toBeDefined();
187+
188+
service.getPromise('/header-params', {
189+
params: {
190+
header: {
191+
// @ts-expect-error - wrong type
192+
'x-required-header': 123,
193+
},
194+
},
195+
});
196+
expect(httpMock.expectOne('/header-params')).toBeDefined();
197+
198+
service.getPromise('/header-params', {
199+
params: {
200+
header: {
201+
'x-required-header': '123',
202+
},
203+
},
204+
});
205+
expect(httpMock.expectOne('/header-params')).toBeDefined();
206+
});
207+
208+
it('should correctly send headers', () => {
209+
service
210+
.getPromise('/header-params', {
211+
params: {
212+
header: {
213+
'x-required-header': '123',
214+
},
215+
},
216+
})
217+
.then(({ response }) =>
218+
expect(response.headers.get('x-required-header-server')).toEqual(
219+
'123',
220+
),
221+
);
222+
const req = httpMock.expectOne('/header-params');
223+
224+
expect(req.request.headers.get('Content-Type')).toEqual(
225+
'application/json',
226+
);
227+
expect(req.request.headers.get('x-required-header')).toEqual('123');
228+
req.flush(null, { headers: { 'x-required-header-server': '123' } });
229+
});
230+
});
106231
});
107232

108233
describe('body', () => {

projects/openapi-fetch-angular/src/lib/openapi-client.service.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import {
22
HttpClient,
33
HttpErrorResponse,
4-
HttpHeaders,
54
HttpRequest,
65
HttpResponse,
76
} from '@angular/common/http';
@@ -13,15 +12,16 @@ import {
1312
FetchOptions,
1413
} from './openapi-client.types';
1514
import {
15+
convertHeaders,
1616
createFinalURL,
1717
createQuerySerializer,
1818
mergeHeaders,
1919
} from './openapi-serializer';
2020
import { catchError, filter, lastValueFrom, map, of } from 'rxjs';
2121

22-
export const DEFAULT_HEADERS = new HttpHeaders({
22+
export const DEFAULT_HEADERS = {
2323
'Content-Type': 'application/json',
24-
});
24+
};
2525

2626
@Injectable({
2727
providedIn: 'root',
@@ -92,7 +92,9 @@ export abstract class OpenAPIClientService<Paths extends {}> {
9292
const requestInit = {
9393
...baseOptions,
9494
...init,
95-
headers: mergeHeaders(baseHeaders, headers, params.headers),
95+
headers: convertHeaders(
96+
mergeHeaders(baseHeaders, headers, params.header),
97+
),
9698
};
9799

98100
const request = new HttpRequest(
@@ -160,7 +162,9 @@ export abstract class OpenAPIClientService<Paths extends {}> {
160162
const requestInit = {
161163
...baseOptions,
162164
...init,
163-
headers: mergeHeaders(baseHeaders, headers, params.headers),
165+
headers: convertHeaders(
166+
mergeHeaders(baseHeaders, headers, params.header),
167+
),
164168
};
165169

166170
const request = new HttpRequest(

projects/openapi-fetch-angular/src/lib/openapi-client.types.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { HttpHeaders, HttpRequest, HttpResponse } from '@angular/common/http';
1+
import { HttpRequest, HttpResponse } from '@angular/common/http';
22
import {
33
ErrorResponse,
44
FilterKeys,
@@ -35,7 +35,10 @@ export interface ClientOptions
3535
headers?: HeadersOptions;
3636
}
3737

38-
export type HeadersOptions = HttpHeaders;
38+
export type HeadersOptions = Record<
39+
string,
40+
string | number | boolean | (string | number | boolean)[] | null | undefined
41+
>;
3942

4043
export type ParamsOption<T> = T extends {
4144
parameters: any;
@@ -67,7 +70,7 @@ export type RequestBodyOption<T> =
6770
export type RequestOptions<T> = ParamsOption<T> &
6871
RequestBodyOption<T> & {
6972
querySerializer?: QuerySerializer<T> | QuerySerializerOptions;
70-
headers?: HttpHeaders;
73+
headers?: HeadersOptions;
7174
};
7275

7376
export type FetchOptions<T> = RequestOptions<T> &

projects/openapi-fetch-angular/src/lib/openapi-serializer.ts

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { HttpHeaders } from '@angular/common/http';
22
import {
3+
HeadersOptions,
34
QuerySerializer,
45
QuerySerializerOptions,
56
} from './openapi-client.types';
@@ -201,20 +202,26 @@ export const serializeObjectParam = (
201202
};
202203

203204
export const mergeHeaders = (
204-
...allHeaders: (HttpHeaders | undefined)[]
205-
): HttpHeaders => {
206-
let headers = new HttpHeaders();
207-
for (const h of allHeaders) {
208-
if (h) {
209-
for (const key of h.keys()) {
210-
const v = h.get(key);
211-
if (v) {
212-
headers = headers.append(key, v);
213-
}
214-
}
205+
...allHeaders: (HeadersOptions | undefined)[]
206+
): HeadersOptions => {
207+
return allHeaders.reduce<HeadersOptions>((acc, headers) => {
208+
if (!headers) {
209+
return acc;
210+
}
211+
for (const key in headers) {
212+
acc[key] = headers[key];
215213
}
214+
return acc;
215+
}, {});
216+
};
217+
218+
export const convertHeaders = (headers?: HeadersOptions): HttpHeaders => {
219+
let httpHeaders = new HttpHeaders();
220+
for (const key in headers) {
221+
if (!headers[key]) continue;
222+
httpHeaders = httpHeaders.set(key, headers[key] as string);
216223
}
217-
return headers;
224+
return httpHeaders;
218225
};
219226

220227
export const defaultPathSerializer = (

0 commit comments

Comments
 (0)