Skip to content

Commit

Permalink
Merge branch 'master' into bugfix/json-improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
gfortaine committed Sep 6, 2021
2 parents fea1383 + 90205f8 commit f6ae669
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 31 deletions.
10 changes: 9 additions & 1 deletion README.md
Expand Up @@ -456,7 +456,15 @@ These are the available config options for making requests. Only the `url` is re
// automatically. If set to `true` will also remove the 'content-encoding' header
// from the responses objects of all decompressed responses
// - Node only (XHR cannot turn off decompression)
decompress: true, // default
decompress: true // default

// `insecureHTTPParser` boolean.
// Indicates where to use an insecure HTTP parser that accepts invalid HTTP headers.
// This may allow interoperability with non-conformant HTTP implementations.
// Using the insecure parser should be avoided.
// see options https://nodejs.org/dist/latest-v12.x/docs/api/http.html#http_http_request_url_options_callback
// see also https://nodejs.org/en/blog/vulnerability/february-2020-security-releases/#strict-http-header-parsing-none
insecureHTTPParser: undefined // default

// transitional options for backward compatibility that may be removed in the newer versions
transitional: {
Expand Down
34 changes: 17 additions & 17 deletions index.d.ts
@@ -1,5 +1,5 @@
export interface AxiosTransformer {
(data: any, headers?: any): any;
(data: any, headers?: Record<string, string>): any;
}

export interface AxiosAdapter {
Expand Down Expand Up @@ -47,16 +47,16 @@ export interface TransitionalOptions{
clarifyTimeoutError: boolean;
}

export interface AxiosRequestConfig {
export interface AxiosRequestConfig<T = any> {
url?: string;
method?: Method;
baseURL?: string;
transformRequest?: AxiosTransformer | AxiosTransformer[];
transformResponse?: AxiosTransformer | AxiosTransformer[];
headers?: any;
headers?: Record<string, string>;
params?: any;
paramsSerializer?: (params: any) => string;
data?: any;
data?: T;
timeout?: number;
timeoutErrorMessage?: string;
withCredentials?: boolean;
Expand All @@ -80,16 +80,16 @@ export interface AxiosRequestConfig {
transitional?: TransitionalOptions
}

export interface AxiosResponse<T = any> {
export interface AxiosResponse<T = never> {
data: T;
status: number;
statusText: string;
headers: any;
config: AxiosRequestConfig;
headers: Record<string, string>;
config: AxiosRequestConfig<T>;
request?: any;
}

export interface AxiosError<T = any> extends Error {
export interface AxiosError<T = never> extends Error {
config: AxiosRequestConfig;
code?: string;
request?: any;
Expand All @@ -98,7 +98,7 @@ export interface AxiosError<T = any> extends Error {
toJSON: () => object;
}

export interface AxiosPromise<T = any> extends Promise<AxiosResponse<T>> {
export interface AxiosPromise<T = never> extends Promise<AxiosResponse<T>> {
}

export interface CancelStatic {
Expand Down Expand Up @@ -142,14 +142,14 @@ export class Axios {
response: AxiosInterceptorManager<AxiosResponse>;
};
getUri(config?: AxiosRequestConfig): string;
request<T = any, R = AxiosResponse<T>> (config: AxiosRequestConfig): Promise<R>;
get<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
delete<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
head<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
options<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
post<T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>;
put<T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>;
patch<T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>;
request<T = never, R = AxiosResponse<T>> (config: AxiosRequestConfig<T>): Promise<R>;
get<T = never, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig<T>): Promise<R>;
delete<T = never, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig<T>): Promise<R>;
head<T = never, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig<T>): Promise<R>;
options<T = never, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig<T>): Promise<R>;
post<T = never, R = AxiosResponse<T>>(url: string, data?: T, config?: AxiosRequestConfig<T>): Promise<R>;
put<T = never, R = AxiosResponse<T>>(url: string, data?: T, config?: AxiosRequestConfig<T>): Promise<R>;
patch<T = never, R = AxiosResponse<T>>(url: string, data?: T, config?: AxiosRequestConfig<T>): Promise<R>;
}

export interface AxiosInstance extends Axios {
Expand Down
4 changes: 4 additions & 0 deletions lib/adapters/http.js
Expand Up @@ -198,6 +198,10 @@ module.exports = function httpAdapter(config) {
options.maxBodyLength = config.maxBodyLength;
}

if (config.insecureHTTPParser) {
options.insecureHTTPParser = config.insecureHTTPParser;
}

// Create the request
var req = transport.request(options, function handleResponse(res) {
if (req.aborted) return;
Expand Down
3 changes: 2 additions & 1 deletion lib/core/enhanceError.js
Expand Up @@ -35,7 +35,8 @@ module.exports = function enhanceError(error, config, code, request, response) {
stack: this.stack,
// Axios
config: this.config,
code: this.code
code: this.code,
status: this.response && this.response.status ? this.response.status : null
};
};
return error;
Expand Down
10 changes: 9 additions & 1 deletion sandbox/client.html
Expand Up @@ -5,7 +5,6 @@
<link rel="stylesheet" type="text/css" href="//maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"/>
<style type="text/css">
pre {
max-height: 200px;
min-height: 39px;
overflow: auto;
}
Expand Down Expand Up @@ -58,6 +57,11 @@ <h3>Response</h3>
<pre id="response">No Data</pre>
</div>

<div class="well">
<h3>Error</h3>
<pre id="error">None</pre>
</div>

<script src="/axios.js"></script>
<script>
(function () {
Expand All @@ -81,6 +85,7 @@ <h3>Response</h3>
var submit = document.getElementById('submit');
var request = document.getElementById('request');
var response = document.getElementById('response');
var error = document.getElementById('error');

function acceptsData(method) {
return ['PATCH', 'POST', 'PUT'].indexOf(method) > -1;
Expand Down Expand Up @@ -138,8 +143,11 @@ <h3>Response</h3>
axios(options)
.then(function (res) {
response.innerHTML = JSON.stringify(res.data, null, 2);
error.innerHTML = "None";
})
.catch(function (res) {
error.innerHTML = JSON.stringify(res.toJSON(), null, 2)
console.error('Axios caught an error from request', res.toJSON());
response.innerHTML = JSON.stringify(res.data, null, 2);
});
};
Expand Down
1 change: 1 addition & 0 deletions test/specs/core/createError.spec.js
Expand Up @@ -23,6 +23,7 @@ describe('core::createError', function() {
expect(json.message).toBe('Boom!');
expect(json.config).toEqual({ foo: 'bar' });
expect(json.code).toBe('ESOMETHING');
expect(json.status).toBe(200);
expect(json.request).toBe(undefined);
expect(json.response).toBe(undefined);
});
Expand Down
12 changes: 11 additions & 1 deletion test/specs/core/enhanceError.spec.js
@@ -1,7 +1,7 @@
var enhanceError = require('../../../lib/core/enhanceError');

describe('core::enhanceError', function() {
it('should add config, config, request and response to error', function() {
it('should add config, code, request, response, and toJSON function to error', function() {
var error = new Error('Boom!');
var request = { path: '/foo' };
var response = { status: 200, data: { foo: 'bar' } };
Expand All @@ -11,9 +11,19 @@ describe('core::enhanceError', function() {
expect(error.code).toBe('ESOMETHING');
expect(error.request).toBe(request);
expect(error.response).toBe(response);
expect(typeof error.toJSON).toBe('function');
expect(error.isAxiosError).toBe(true);
});

it('should serialize to JSON with a status of null when there is no response', function() {
var error = new Error('Boom!');
var request = { path: '/foo' };
var response = undefined;

var errorAsJson = enhanceError(error, { foo: 'bar' }, 'ESOMETHING', request, response).toJSON();
expect(errorAsJson.status).toEqual(null);
});

it('should return error', function() {
var error = new Error('Boom!');
expect(enhanceError(error, { foo: 'bar' }, 'ESOMETHING')).toBe(error);
Expand Down
24 changes: 14 additions & 10 deletions test/typescript/axios.ts
Expand Up @@ -111,6 +111,10 @@ axios.patch('/user', { foo: 'bar' })
.catch(handleError);

// Typed methods
interface UserCreationDef {
name: string;
}

interface User {
id: number;
name: string;
Expand Down Expand Up @@ -138,7 +142,7 @@ axios.get<User>('/user', { params: { id: 12345 } })
axios.head<User>('/user')
.then(handleUserResponse)
.catch(handleError);

axios.options<User>('/user')
.then(handleUserResponse)
.catch(handleError);
Expand All @@ -147,19 +151,19 @@ axios.delete<User>('/user')
.then(handleUserResponse)
.catch(handleError);

axios.post<User>('/user', { foo: 'bar' })
axios.post<User>('/user', { name: 'foo', id: 1 })
.then(handleUserResponse)
.catch(handleError);

axios.post<User>('/user', { foo: 'bar' }, { headers: { 'X-FOO': 'bar' } })
axios.post<User>('/user', { name: 'foo', id: 1 }, { headers: { 'X-FOO': 'bar' } })
.then(handleUserResponse)
.catch(handleError);

axios.put<User>('/user', { foo: 'bar' })
axios.put<User>('/user', { name: 'foo', id: 1 })
.then(handleUserResponse)
.catch(handleError);

axios.patch<User>('/user', { foo: 'bar' })
axios.patch<User>('/user', { name: 'foo', id: 1 })
.then(handleUserResponse)
.catch(handleError);

Expand Down Expand Up @@ -189,19 +193,19 @@ axios.delete<User, string>('/user')
.then(handleStringResponse)
.catch(handleError);

axios.post<User, string>('/user', { foo: 'bar' })
axios.post<Partial<UserCreationDef>, string>('/user', { name: 'foo' })
.then(handleStringResponse)
.catch(handleError);

axios.post<User, string>('/user', { foo: 'bar' }, { headers: { 'X-FOO': 'bar' } })
axios.post<Partial<UserCreationDef>, string>('/user', { name: 'foo' }, { headers: { 'X-FOO': 'bar' } })
.then(handleStringResponse)
.catch(handleError);

axios.put<User, string>('/user', { foo: 'bar' })
axios.put<Partial<UserCreationDef>, string>('/user', { name: 'foo' })
.then(handleStringResponse)
.catch(handleError);

axios.patch<User, string>('/user', { foo: 'bar' })
axios.patch<Partial<UserCreationDef>, string>('/user', { name: 'foo' })
.then(handleStringResponse)
.catch(handleError);

Expand Down Expand Up @@ -292,7 +296,7 @@ axios.interceptors.response.use((response: AxiosResponse) => Promise.resolve(res
// Adapters

const adapter: AxiosAdapter = (config: AxiosRequestConfig) => {
const response: AxiosResponse = {
const response: AxiosResponse<any> = {
data: { foo: 'bar' },
status: 200,
statusText: 'OK',
Expand Down

0 comments on commit f6ae669

Please sign in to comment.