Default to sending Accept and Content-Type headers for json

This commit is contained in:
David Kale 2020-02-04 14:19:46 -05:00
parent f545df6c21
commit e91a39a86b
6 changed files with 131 additions and 12 deletions

View File

@ -1,10 +1,13 @@
## Releases ## Releases
## 1.0.1 to 1.0.3 ## 1.0.6
Adds proxy support. Automatically sends Content-Type and Accept application/json headers for \<verb>Json() helper methods if not set in the client or parameters.
## 1.0.5
Adds \<verb>Json() helper methods for json over http scenarios.
## 1.0.4 ## 1.0.4
Started to add \<verb>Json() helper methods. Do not use this release for that. Use >= 1.0.5 since there was an issue with types. Started to add \<verb>Json() helper methods. Do not use this release for that. Use >= 1.0.5 since there was an issue with types.
## 1.0.5 ## 1.0.1 to 1.0.3
Adds \<verb>Json() helper methods for json over http scenarios. Adds proxy support.

View File

@ -9,6 +9,7 @@ interface HttpBinData {
url: string; url: string;
data: any; data: any;
json: any; json: any;
headers: any;
args?: any args?: any
} }
@ -206,6 +207,8 @@ describe('basics', () => {
expect(jsonObj.statusCode).toBe(200); expect(jsonObj.statusCode).toBe(200);
expect(jsonObj.result).toBeDefined(); expect(jsonObj.result).toBeDefined();
expect(jsonObj.result.url).toBe('https://httpbin.org/get'); expect(jsonObj.result.url).toBe('https://httpbin.org/get');
expect(jsonObj.result.headers["Accept"]).toBe(httpm.MediaTypes.ApplicationJson);
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson);
}); });
it('getting a non existent json object returns null', async() => { it('getting a non existent json object returns null', async() => {
@ -221,6 +224,9 @@ describe('basics', () => {
expect(restRes.result).toBeDefined(); expect(restRes.result).toBeDefined();
expect(restRes.result.url).toBe('https://httpbin.org/post'); expect(restRes.result.url).toBe('https://httpbin.org/post');
expect(restRes.result.json.name).toBe('foo'); expect(restRes.result.json.name).toBe('foo');
expect(restRes.result.headers["Accept"]).toBe(httpm.MediaTypes.ApplicationJson);
expect(restRes.result.headers["Content-Type"]).toBe(httpm.MediaTypes.ApplicationJson);
expect(restRes.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson);
}); });
it('puts a json object', async() => { it('puts a json object', async() => {
@ -230,6 +236,10 @@ describe('basics', () => {
expect(restRes.result).toBeDefined(); expect(restRes.result).toBeDefined();
expect(restRes.result.url).toBe('https://httpbin.org/put'); expect(restRes.result.url).toBe('https://httpbin.org/put');
expect(restRes.result.json.name).toBe('foo'); expect(restRes.result.json.name).toBe('foo');
expect(restRes.result.headers["Accept"]).toBe(httpm.MediaTypes.ApplicationJson);
expect(restRes.result.headers["Content-Type"]).toBe(httpm.MediaTypes.ApplicationJson);
expect(restRes.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson);
}); });
it('patch a json object', async() => { it('patch a json object', async() => {
@ -239,5 +249,8 @@ describe('basics', () => {
expect(restRes.result).toBeDefined(); expect(restRes.result).toBeDefined();
expect(restRes.result.url).toBe('https://httpbin.org/patch'); expect(restRes.result.url).toBe('https://httpbin.org/patch');
expect(restRes.result.json.name).toBe('foo'); expect(restRes.result.json.name).toBe('foo');
expect(restRes.result.headers["Accept"]).toBe(httpm.MediaTypes.ApplicationJson);
expect(restRes.result.headers["Content-Type"]).toBe(httpm.MediaTypes.ApplicationJson);
expect(restRes.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson);
}); });
}) });

79
__tests__/headers.test.ts Normal file
View File

@ -0,0 +1,79 @@
import * as httpm from '../_out';
import * as ifm from '../_out/interfaces'
describe('headers', () => {
let _http: httpm.HttpClient;
beforeEach(() => {
_http = new httpm.HttpClient('http-client-tests');
});
it('preserves existing headers on getJson', async() => {
let additionalHeaders = { [httpm.Headers.Accept]: "foo" };
let jsonObj: ifm.ITypedResponse<any> = await _http.getJson<any>('https://httpbin.org/get', additionalHeaders);
expect(jsonObj.result.headers["Accept"]).toBe("foo");
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson);
let httpWithHeaders = new httpm.HttpClient();
httpWithHeaders.requestOptions = {
headers: {
[httpm.Headers.Accept]: "baz"
}
};
jsonObj = await httpWithHeaders.getJson<any>('https://httpbin.org/get');
expect(jsonObj.result.headers["Accept"]).toBe("baz");
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson);
});
it('preserves existing headers on postJson', async() => {
let additionalHeaders = { [httpm.Headers.Accept]: "foo" };
let jsonObj: ifm.ITypedResponse<any> = await _http.postJson<any>('https://httpbin.org/post', {}, additionalHeaders);
expect(jsonObj.result.headers["Accept"]).toBe("foo");
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson);
let httpWithHeaders = new httpm.HttpClient();
httpWithHeaders.requestOptions = {
headers: {
[httpm.Headers.Accept]: "baz"
}
};
jsonObj = await httpWithHeaders.postJson<any>('https://httpbin.org/post', {});
expect(jsonObj.result.headers["Accept"]).toBe("baz");
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson);
});
it('preserves existing headers on putJson', async() => {
let additionalHeaders = { [httpm.Headers.Accept]: "foo" };
let jsonObj: ifm.ITypedResponse<any> = await _http.putJson<any>('https://httpbin.org/put', {}, additionalHeaders);
expect(jsonObj.result.headers["Accept"]).toBe("foo");
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson);
let httpWithHeaders = new httpm.HttpClient();
httpWithHeaders.requestOptions = {
headers: {
[httpm.Headers.Accept]: "baz"
}
};
jsonObj = await httpWithHeaders.putJson<any>('https://httpbin.org/put', {});
expect(jsonObj.result.headers["Accept"]).toBe("baz");
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson);
});
it('preserves existing headers on patchJson', async() => {
let additionalHeaders = { [httpm.Headers.Accept]: "foo" };
let jsonObj: ifm.ITypedResponse<any> = await _http.patchJson<any>('https://httpbin.org/patch', {}, additionalHeaders);
expect(jsonObj.result.headers["Accept"]).toBe("foo");
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson);
let httpWithHeaders = new httpm.HttpClient();
httpWithHeaders.requestOptions = {
headers: {
[httpm.Headers.Accept]: "baz"
}
};
jsonObj = await httpWithHeaders.patchJson<any>('https://httpbin.org/patch', {});
expect(jsonObj.result.headers["Accept"]).toBe("baz");
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson);
});
});

View File

@ -35,6 +35,15 @@ export enum HttpCodes {
GatewayTimeout = 504, GatewayTimeout = 504,
} }
export enum Headers {
Accept = "accept",
ContentType = "content-type"
}
export enum MediaTypes {
ApplicationJson = "application/json"
}
/** /**
* Returns the proxy URL, depending upon the supplied url and proxy environment variables. * Returns the proxy URL, depending upon the supplied url and proxy environment variables.
* @param serverUrl The server URL where the request will be sent. For example, https://api.github.com * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
@ -166,25 +175,32 @@ export class HttpClient {
* Gets a typed object from an endpoint * Gets a typed object from an endpoint
* Be aware that not found returns a null. Other errors (4xx, 5xx) reject the promise * Be aware that not found returns a null. Other errors (4xx, 5xx) reject the promise
*/ */
public async getJson<T>(requestUrl: string, additionalHeaders?: ifm.IHeaders): Promise<ifm.ITypedResponse<T>> { public async getJson<T>(requestUrl: string, additionalHeaders: ifm.IHeaders = {}): Promise<ifm.ITypedResponse<T>> {
additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson)
let res: ifm.IHttpClientResponse = await this.get(requestUrl, additionalHeaders); let res: ifm.IHttpClientResponse = await this.get(requestUrl, additionalHeaders);
return this._processResponse<T>(res, this.requestOptions); return this._processResponse<T>(res, this.requestOptions);
} }
public async postJson<T>(requestUrl: string, obj: any, additionalHeaders?: ifm.IHeaders): Promise<ifm.ITypedResponse<T>> { public async postJson<T>(requestUrl: string, obj: any, additionalHeaders: ifm.IHeaders = {}): Promise<ifm.ITypedResponse<T>> {
let data: string = JSON.stringify(obj, null, 2); let data: string = JSON.stringify(obj, null, 2);
additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson)
additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
let res: ifm.IHttpClientResponse = await this.post(requestUrl, data, additionalHeaders); let res: ifm.IHttpClientResponse = await this.post(requestUrl, data, additionalHeaders);
return this._processResponse<T>(res, this.requestOptions); return this._processResponse<T>(res, this.requestOptions);
} }
public async putJson<T>(requestUrl: string, obj: any, additionalHeaders?: ifm.IHeaders): Promise<ifm.ITypedResponse<T>> { public async putJson<T>(requestUrl: string, obj: any, additionalHeaders: ifm.IHeaders = {}): Promise<ifm.ITypedResponse<T>> {
let data: string = JSON.stringify(obj, null, 2); let data: string = JSON.stringify(obj, null, 2);
additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson)
additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
let res: ifm.IHttpClientResponse = await this.put(requestUrl, data, additionalHeaders); let res: ifm.IHttpClientResponse = await this.put(requestUrl, data, additionalHeaders);
return this._processResponse<T>(res, this.requestOptions); return this._processResponse<T>(res, this.requestOptions);
} }
public async patchJson<T>(requestUrl: string, obj: any, additionalHeaders?: ifm.IHeaders): Promise<ifm.ITypedResponse<T>> { public async patchJson<T>(requestUrl: string, obj: any, additionalHeaders: ifm.IHeaders = {}): Promise<ifm.ITypedResponse<T>> {
let data: string = JSON.stringify(obj, null, 2); let data: string = JSON.stringify(obj, null, 2);
additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson)
additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
let res: ifm.IHttpClientResponse = await this.patch(requestUrl, data, additionalHeaders); let res: ifm.IHttpClientResponse = await this.patch(requestUrl, data, additionalHeaders);
return this._processResponse<T>(res, this.requestOptions); return this._processResponse<T>(res, this.requestOptions);
} }
@ -416,6 +432,14 @@ export class HttpClient {
return lowercaseKeys(headers || {}); return lowercaseKeys(headers || {});
} }
private _getExistingOrDefaultHeader(additionalHeaders: ifm.IHeaders, header: string, _default: string) {
let clientHeader: string;
if(this.requestOptions && this.requestOptions.headers) {
clientHeader = this.requestOptions.headers[header];
}
return additionalHeaders[header] || clientHeader || _default;
}
private _getAgent(parsedUrl: url.Url): http.Agent { private _getAgent(parsedUrl: url.Url): http.Agent {
let agent; let agent;
let proxyUrl: url.Url = pm.getProxyUrl(parsedUrl); let proxyUrl: url.Url = pm.getProxyUrl(parsedUrl);

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "@actions/http-client", "name": "@actions/http-client",
"version": "1.0.5", "version": "1.0.6",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View File

@ -1,6 +1,6 @@
{ {
"name": "@actions/http-client", "name": "@actions/http-client",
"version": "1.0.5", "version": "1.0.6",
"description": "Actions Http Client", "description": "Actions Http Client",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {