Skip to content

Commit c8f8140

Browse files
committed
add API generated from openapi schema of V2-API Preview
1 parent 9b8dc36 commit c8f8140

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+3494
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,7 @@ dist
102102

103103
# TernJS port file
104104
.tern-port
105+
106+
# intellij
107+
.idea
108+

.prettierignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
api
2+
node_modules
3+
*.json

.prettierrc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"singleQuote": true,
3+
"tabWidth": 2,
4+
"useTabs": false,
5+
"trailingComma": "all"
6+
}

DeveloperNotes.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Developer Notes
2+
3+
Major part of this sdk is generated from
4+
OpenAPI Spec obtained from the api docs.
5+
6+
#### Generation from Spec
7+
8+
Whenever there are new changes to APIs, the openapi
9+
spec available at `openapi.yaml` should be replaced
10+
and the `generate_spec` npm script should be run:
11+
12+
```bash
13+
npm run generate_spec
14+
```
15+
16+
#### Adding examples
17+
18+
Necessary examples can be added as new scripts to `examples` directory.

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Docupilot API - JS SDK
2+
3+
This SDK will help simplify interaction with Docupilot
4+
APIs from `nodejs` or `javascript` environments
5+
6+
#### Installation
7+
8+
`npm i docupilot-sdk`
9+
10+
#### Usage
11+
12+
Creating a docupilot client
13+
14+
```ts
15+
import Docupilot from 'docupilot-sdk';
16+
17+
const client = Docupilot.authorize('<your api token>');
18+
```
19+
20+
#### Trying out examples
21+
22+
To troy out the _basic_ example
23+
24+
```bash
25+
DOCUPILOT_TOKEN=<your-api-token> ts-node examples/basic
26+
```

api/core/ApiError.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/* istanbul ignore file */
2+
/* tslint:disable */
3+
/* eslint-disable */
4+
import type { ApiResult } from './ApiResult';
5+
6+
export class ApiError extends Error {
7+
public readonly url: string;
8+
public readonly status: number;
9+
public readonly statusText: string;
10+
public readonly body: any;
11+
12+
constructor(response: ApiResult, message: string) {
13+
super(message);
14+
15+
this.url = response.url;
16+
this.status = response.status;
17+
this.statusText = response.statusText;
18+
this.body = response.body;
19+
}
20+
}

api/core/ApiRequestOptions.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/* istanbul ignore file */
2+
/* tslint:disable */
3+
/* eslint-disable */
4+
export type ApiRequestOptions = {
5+
readonly method: 'GET' | 'PUT' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'PATCH';
6+
readonly path: string;
7+
readonly cookies?: Record<string, any>;
8+
readonly headers?: Record<string, any>;
9+
readonly query?: Record<string, any>;
10+
readonly formData?: Record<string, any>;
11+
readonly body?: any;
12+
readonly responseHeader?: string;
13+
readonly errors?: Record<number, string>;
14+
}

api/core/ApiResult.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/* istanbul ignore file */
2+
/* tslint:disable */
3+
/* eslint-disable */
4+
export type ApiResult = {
5+
readonly url: string;
6+
readonly ok: boolean;
7+
readonly status: number;
8+
readonly statusText: string;
9+
readonly body: any;
10+
}

api/core/OpenAPI.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/* istanbul ignore file */
2+
/* tslint:disable */
3+
/* eslint-disable */
4+
type Resolver<T> = () => Promise<T>;
5+
type Headers = Record<string, string>;
6+
7+
type Config = {
8+
BASE: string;
9+
VERSION: string;
10+
WITH_CREDENTIALS: boolean;
11+
TOKEN?: string | Resolver<string>;
12+
USERNAME?: string | Resolver<string>;
13+
PASSWORD?: string | Resolver<string>;
14+
HEADERS?: Headers | Resolver<Headers>;
15+
}
16+
17+
export const OpenAPI: Config = {
18+
BASE: '',
19+
VERSION: '2.0',
20+
WITH_CREDENTIALS: false,
21+
TOKEN: undefined,
22+
USERNAME: undefined,
23+
PASSWORD: undefined,
24+
HEADERS: undefined,
25+
};

api/core/request.ts

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
/* istanbul ignore file */
2+
/* tslint:disable */
3+
/* eslint-disable */
4+
import FormData from 'form-data';
5+
import fetch, { BodyInit, Headers, RequestInit, Response } from 'node-fetch';
6+
import { types } from 'util';
7+
8+
import { ApiError } from './ApiError';
9+
import type { ApiRequestOptions } from './ApiRequestOptions';
10+
import type { ApiResult } from './ApiResult';
11+
import { OpenAPI } from './OpenAPI';
12+
13+
function isDefined<T>(value: T | null | undefined): value is Exclude<T, null | undefined> {
14+
return value !== undefined && value !== null;
15+
}
16+
17+
function isString(value: any): value is string {
18+
return typeof value === 'string';
19+
}
20+
21+
function isStringWithValue(value: any): value is string {
22+
return isString(value) && value !== '';
23+
}
24+
25+
function isBinary(value: any): value is Buffer | ArrayBuffer | ArrayBufferView {
26+
const isBuffer = Buffer.isBuffer(value);
27+
const isArrayBuffer = types.isArrayBuffer(value);
28+
const isArrayBufferView = types.isArrayBufferView(value);
29+
return isBuffer || isArrayBuffer || isArrayBufferView;
30+
}
31+
32+
function getQueryString(params: Record<string, any>): string {
33+
const qs: string[] = [];
34+
Object.keys(params).forEach(key => {
35+
const value = params[key];
36+
if (isDefined(value)) {
37+
if (Array.isArray(value)) {
38+
value.forEach(value => {
39+
qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
40+
});
41+
} else {
42+
qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
43+
}
44+
}
45+
});
46+
if (qs.length > 0) {
47+
return `?${qs.join('&')}`;
48+
}
49+
return '';
50+
}
51+
52+
function getUrl(options: ApiRequestOptions): string {
53+
const path = options.path.replace(/[:]/g, '_');
54+
const url = `${OpenAPI.BASE}${path}`;
55+
56+
if (options.query) {
57+
return `${url}${getQueryString(options.query)}`;
58+
}
59+
return url;
60+
}
61+
62+
function getFormData(params: Record<string, any>): FormData {
63+
const formData = new FormData();
64+
Object.keys(params).forEach(key => {
65+
const value = params[key];
66+
if (isDefined(value)) {
67+
formData.append(key, value);
68+
}
69+
});
70+
return formData;
71+
}
72+
73+
type Resolver<T> = () => Promise<T>;
74+
75+
async function resolve<T>(resolver?: T | Resolver<T>): Promise<T | undefined> {
76+
if (typeof resolver === 'function') {
77+
return (resolver as Resolver<T>)();
78+
}
79+
return resolver;
80+
}
81+
82+
async function getHeaders(options: ApiRequestOptions): Promise<Headers> {
83+
const headers = new Headers({
84+
Accept: 'application/json',
85+
...OpenAPI.HEADERS,
86+
...options.headers,
87+
});
88+
89+
const token = await resolve(OpenAPI.TOKEN);
90+
const username = await resolve(OpenAPI.USERNAME);
91+
const password = await resolve(OpenAPI.PASSWORD);
92+
93+
if (isStringWithValue(token)) {
94+
headers.append('Authorization', `Bearer ${token}`);
95+
}
96+
97+
if (isStringWithValue(username) && isStringWithValue(password)) {
98+
const credentials = Buffer.from(`${username}:${password}`).toString('base64');
99+
headers.append('Authorization', `Basic ${credentials}`);
100+
}
101+
102+
if (options.body) {
103+
if (isBinary(options.body)) {
104+
headers.append('Content-Type', 'application/octet-stream');
105+
} else if (isString(options.body)) {
106+
headers.append('Content-Type', 'text/plain');
107+
} else {
108+
headers.append('Content-Type', 'application/json');
109+
}
110+
}
111+
return headers;
112+
}
113+
114+
function getRequestBody(options: ApiRequestOptions): BodyInit | undefined {
115+
if (options.formData) {
116+
return getFormData(options.formData);
117+
}
118+
if (options.body) {
119+
if (isString(options.body) || isBinary(options.body)) {
120+
return options.body;
121+
} else {
122+
return JSON.stringify(options.body);
123+
}
124+
}
125+
return undefined;
126+
}
127+
128+
async function sendRequest(options: ApiRequestOptions, url: string): Promise<Response> {
129+
const request: RequestInit = {
130+
method: options.method,
131+
headers: await getHeaders(options),
132+
body: getRequestBody(options),
133+
};
134+
return await fetch(url, request);
135+
}
136+
137+
function getResponseHeader(response: Response, responseHeader?: string): string | null {
138+
if (responseHeader) {
139+
const content = response.headers.get(responseHeader);
140+
if (isString(content)) {
141+
return content;
142+
}
143+
}
144+
return null;
145+
}
146+
147+
async function getResponseBody(response: Response): Promise<any> {
148+
try {
149+
const contentType = response.headers.get('Content-Type');
150+
if (contentType) {
151+
const isJSON = contentType.toLowerCase().startsWith('application/json');
152+
if (isJSON) {
153+
return await response.json();
154+
} else {
155+
return await response.text();
156+
}
157+
}
158+
} catch (error) {
159+
console.error(error);
160+
}
161+
return null;
162+
}
163+
164+
function catchErrors(options: ApiRequestOptions, result: ApiResult): void {
165+
const errors: Record<number, string> = {
166+
400: 'Bad Request',
167+
401: 'Unauthorized',
168+
403: 'Forbidden',
169+
404: 'Not Found',
170+
500: 'Internal Server Error',
171+
502: 'Bad Gateway',
172+
503: 'Service Unavailable',
173+
...options.errors,
174+
}
175+
176+
const error = errors[result.status];
177+
if (error) {
178+
throw new ApiError(result, error);
179+
}
180+
181+
if (!result.ok) {
182+
throw new ApiError(result, 'Generic Error');
183+
}
184+
}
185+
186+
/**
187+
* Request using node-fetch client
188+
* @param options The request options from the the service
189+
* @returns ApiResult
190+
* @throws ApiError
191+
*/
192+
export async function request(options: ApiRequestOptions): Promise<ApiResult> {
193+
const url = getUrl(options);
194+
const response = await sendRequest(options, url);
195+
const responseBody = await getResponseBody(response);
196+
const responseHeader = getResponseHeader(response, options.responseHeader);
197+
198+
const result: ApiResult = {
199+
url,
200+
ok: response.ok,
201+
status: response.status,
202+
statusText: response.statusText,
203+
body: responseHeader || responseBody,
204+
};
205+
206+
catchErrors(options, result);
207+
return result;
208+
}

0 commit comments

Comments
 (0)