Skip to content

Commit

Permalink
Simplified code and release lighter version 4.
Browse files Browse the repository at this point in the history
  • Loading branch information
antoninbouchal committed Feb 6, 2019
1 parent 15af32f commit 3006077
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 136 deletions.
35 changes: 21 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const apiRequest = new JsonRequest('https://jsonplaceholder.typicode.com');
const printData = async () => {
const result = await apiRequest.get('/posts/1');

console.log(result);
console.log(result.body);
};

printData();
Expand Down Expand Up @@ -59,7 +59,7 @@ const apiRequest = new JsonRequest('https://jsonplaceholder.typicode.com', {
});

const result = apiRequest
.options({
.wrap({
headers: {
'authorization': 'Bearer XYZ'
}
Expand All @@ -69,22 +69,29 @@ const result = apiRequest

All options are deep merged together.

### Returning full response object
### Typescript

Sometimes you need return full response object for check status code or returned headers.
If you know schema which return in body, you can use generic types for better suggestions.

For it you can set third parameter of JsonRequest to true.

```javascript
```typescript
import JsonRequest from 'async-json-request';

const apiRequest = new JsonRequest('https://jsonplaceholder.typicode.com', {}, true);
interface IPost {
userId: number;
id: number;
title: string;
body: string;
}

const printStatusCode = async () => {
const result = await apiRequest.get('/posts/1');

console.log(result.statusCode, result.body);
};
const apiRequest = new JsonRequest('https://jsonplaceholder.typicode.com');

const printFirstPostTitle = async (): Promise<void> => {
const response = await apiRequest.get<IPost>('/posts/1');

const responseBody = response.body; // Now body will be suggest you IPost interface.

console.log(`Title of first post is: ${responseBody.title}`);
}

printStatusCode();
printFirstPostTitle();
```
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "async-json-request",
"version": "3.1.0",
"version": "4.0.0",
"description": "Base request methods based on promises for async/await ussage",
"main": "./dist/index.js",
"scripts": {
Expand Down
232 changes: 150 additions & 82 deletions src/JsonRequest.ts
Original file line number Diff line number Diff line change
@@ -1,92 +1,55 @@
import * as request from "request";
import * as deepmerge from "deepmerge";
import {Response} from "request";
import * as allowedMethods from "methods";

interface IPromiseMethod {
(path: string, parameters?: object|null, body?: object|null): Promise<any>;
}

interface IOptionsMethod {
(extraOptions: object): IJsonRequestAPI
import {CoreOptions} from "request";
import {Request} from "request";
import {ResponseAsJSON} from "request";
import {IncomingMessage} from "http";
import {Caseless} from "caseless";


interface Response<T = any> extends IncomingMessage {
statusCode: number;
statusMessage: string;
request: Request;
body: T; // Buffer, string, stream.Readable, or a plain object if `json` was truthy
caseless: Caseless; // case-insensitive access to headers
toJSON(): ResponseAsJSON;

timingStart?: number;
elapsedTime?: number;
timings?: {
socket: number;
lookup: number;
connect: number;
response: number;
end: number;
};
timingPhases?: {
wait: number;
dns: number;
tcp: number;
firstByte: number;
download: number;
total: number;
};
}

export type IJsonRequestAPI = {
[key: string]: IPromiseMethod;
} & {
options: IOptionsMethod;
}

class JsonRequestDeclaration {
class JsonRequest {
protected readonly baseUrl: string;

protected readonly defaultRequestOptions: object;

protected readonly fullResponse: boolean;

constructor(baseUrl: string, defaultRequestOptions: object = {}, fullResponse: boolean = false) {
constructor(baseUrl: string, defaultRequestOptions: object = {}) {
this.baseUrl = baseUrl;
this.defaultRequestOptions = defaultRequestOptions;
this.fullResponse = fullResponse;
}

public getProxy(extraOptions: object = {}): IJsonRequestAPI {
return new Proxy(this, {
get: (target: any, name: string) => {
if (name === 'options') {
return target.getOptionsMethod();
}

if (allowedMethods.indexOf(name.toString().toLowerCase()) === -1) {
return undefined;
}

return target.getMethod(name, extraOptions);
}
});
}

protected getOptionsMethod(): Function {
const self = this;

return function (extraOptions: object) {
return self.getProxy(extraOptions)
};
}


protected getMethod(method: string, extraOptions: object = {}) {
const self = this;

const reqOptions = deepmerge(this.defaultRequestOptions, extraOptions);

return function (path: string, parameters?: object, body?: object) {
return self.runRequest(
method.toUpperCase(),
reqOptions,
path,
parameters,
body
)
}
}


/**
*
* @param method
* @param reqOptions
* @param path
* @param body
* @param parameters
* @return {Promise}
* @private
*/
protected runRequest(method: string, reqOptions: object, path: string, parameters?: object, body?: object) {
protected runRequest(method: string, path: string, parameters?: object | null, body?: object | null): Promise<Response> {
const url = this.baseUrl + path;

const options: any = {
...reqOptions,
...this.defaultRequestOptions,
url,
method
};
Expand All @@ -108,20 +71,125 @@ class JsonRequestDeclaration {
return reject(err)
}

resolve(this.fullResponse ? res : data);
resolve(res);
});
});
}
}

interface IJsonRequest {
new(baseUrl: string, defaultRequestOptions?: object, fullResponse?: boolean): IJsonRequestAPI;
public get<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('get', path, parameters, body);
}

(baseUrl: string, defaultRequestOptions?: object, fullResponse?: boolean): IJsonRequestAPI;
}
public post<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('post', path, parameters, body);
}

public put<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('put', path, parameters, body);
}

public head<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('head', path, parameters, body);
}

public delete<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('delete', path, parameters, body);
}

public options<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('options', path, parameters, body);
}

public trace<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('trace', path, parameters, body);
}

public copy<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('copy', path, parameters, body);
}

const JsonRequest: IJsonRequest = function (baseUrl: string, defaultRequestOptions: object = {}, fullResponse: boolean = false): IJsonRequestAPI {
return new JsonRequestDeclaration(baseUrl, defaultRequestOptions, fullResponse).getProxy();
} as IJsonRequest;
public lock<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('lock', path, parameters, body);
}

public mkcol<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('mkcol', path, parameters, body);
}

public move<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('move', path, parameters, body);
}

public purge<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('purge', path, parameters, body);
}

public propfind<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('propfind', path, parameters, body);
}

public proppatch<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('proppatch', path, parameters, body);
}

public unlock<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('unlock', path, parameters, body);
}

public report<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('report', path, parameters, body);
}

public mkactivity<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('mkactivity', path, parameters, body);
}

public checkout<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('checkout', path, parameters, body);
}

public merge<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('merge', path, parameters, body);
}

public 'm-search'<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('m-search', path, parameters, body);
}

public notify<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('notify', path, parameters, body);
}

public subscribe<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('subscribe', path, parameters, body);
}

public unsubscribe<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('unsubscribe', path, parameters, body);
}

public patch<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('patch', path, parameters, body);
}

public search<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('search', path, parameters, body);
}

public connect<T = any>(path: string, parameters?: object | null, body?: object | null): Promise<Response<T>> {
return this.runRequest('connect', path, parameters, body);
}

/**
* Create and return new instance of JsonRequest with merged options.
*
* @param extraOptions
*/
public wrap(extraOptions: CoreOptions): JsonRequest {
const mergedOptions = deepmerge(this.defaultRequestOptions, extraOptions);

return new JsonRequest(this.baseUrl, mergedOptions);
}
}

export default JsonRequest;
Loading

0 comments on commit 3006077

Please sign in to comment.