Skip to content

Commit

Permalink
chore(types): Add support for typescript and add types to api module (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
jstoffan authored Dec 23, 2019
1 parent b3bc23f commit 0a4ed88
Show file tree
Hide file tree
Showing 9 changed files with 267 additions and 201 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module.exports = {
'class-methods-use-this': 0, // fixme
'import/no-cycle': 0, // fixme
'import/no-extraneous-dependencies': 0, // fixme
'import/no-unresolved': 'off', // fixme, allows JS files to import TS files
'no-underscore-dangle': 0, // fixme
'prefer-destructuring': ['error', { object: true, array: false }], // fixme
},
Expand Down
14 changes: 14 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,20 @@ module.exports = api => {
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-transform-object-assign',
],
overrides: [
{
test: ['./src/**/*.ts', './src/**/*.tsx'],
presets: [
[
'@babel/preset-typescript',
{
isTSX: true,
allExtensions: true,
},
],
],
},
],
env: {
production: {
plugins: [['react-remove-properties', { properties: ['data-testid'] }]],
Expand Down
3 changes: 2 additions & 1 deletion build/webpack.common.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ module.exports = language => {
module: {
rules: [
{
test: /\.js$/,
test: /\.(js|ts|tsx)$/,
loader: 'babel-loader',
include: [path.resolve('src/lib')],
},
Expand Down Expand Up @@ -66,6 +66,7 @@ module.exports = language => {
'box-elements-messages': path.resolve(`node_modules/box-ui-elements/i18n/${language}`),
'react-intl-locale-data': path.resolve(`node_modules/react-intl/locale-data/${locale}`),
},
extensions: ['.tsx', '.ts', '.js'],
},
stats: {
assets: true,
Expand Down
2 changes: 2 additions & 0 deletions lint-staged.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ module.exports = {
'*.html': ['prettier --write --parser=html', 'git add'],
'*.md': ['prettier --write --parser=markdown', 'git add'],
'*.scss': ['prettier --write --parser=scss', 'stylelint --syntax scss --fix', 'git add'],
'*.ts': ['eslint --ext=.ts --fix', 'git add'],
'*.tsx': ['eslint --ext=.tsx --fix', 'git add'],
};
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@
"@babel/plugin-transform-object-assign": "^7.2.0",
"@babel/preset-env": "^7.5.5",
"@babel/preset-react": "^7.0.0",
"@babel/preset-typescript": "^7.7.7",
"@box/frontend": "^6.0.0",
"@box/languages": "^1.0.0",
"@commitlint/cli": "^8.2.0",
"@commitlint/config-conventional": "^8.2.0",
"@commitlint/travis-cli": "^8.2.0",
"@types/lodash": "^4.14.149",
"@typescript-eslint/eslint-plugin": "^2.13.0",
"@typescript-eslint/parser": "^2.13.0",
"autoprefixer": "^9.6.1",
Expand Down Expand Up @@ -130,6 +132,7 @@
"lint": "npm-run-all lint:*",
"lint:css": "NODE_ENV=dev yarn stylelint 'src/lib/**/*.scss'",
"lint:js": "NODE_ENV=dev yarn eslint src/lib",
"lint:ts": "tsc && eslint --ext=.tsx,.ts --max-warnings=0 .",
"release": "yarn setup && yarn clean && yarn build:i18n && yarn lint && yarn test && yarn build:prod",
"release:major": "./build/release.sh -m",
"release:minor": "./build/release.sh -n",
Expand Down
200 changes: 0 additions & 200 deletions src/lib/api.js

This file was deleted.

104 changes: 104 additions & 0 deletions src/lib/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import axios, {
AxiosError,
AxiosInstance,
AxiosInterceptorManager,
AxiosPromise,
AxiosRequestConfig,
AxiosResponse,
ResponseType,
} from 'axios';
import pickBy from 'lodash/pickBy';
import DownloadReachability from './DownloadReachability';
import MetadataAPI from './metadataAPI';

export type APIGetConfig = { type?: ResponseType } & AxiosRequestConfig;
export type APIError = { response: AxiosResponse } & Error;
export type APIPromise = Promise<AxiosPromise | SyntaxError>;

const filterOptions = (options: AxiosRequestConfig = {}): AxiosRequestConfig => {
return pickBy(options, (value: keyof AxiosRequestConfig) => value !== undefined && value !== null);
};

const handleError = ({ response }: AxiosError): void => {
if (response) {
const error = new Error(response.statusText) as APIError;
error.response = response; // Need to pass response through so we can see what kind of HTTP error this was
throw error;
}
};
const parseResponse = (response: AxiosResponse): AxiosResponse | AxiosResponse['data'] => {
if (response.status === 204 || response.status === 202) {
return response;
}

return response.data;
};

const transformTextResponse = <D>(data: D): D => data;

export default class Api {
client: AxiosInstance;

interceptors: number[] = [];

metadata: MetadataAPI;

reachability: DownloadReachability;

constructor() {
this.client = axios.create();
this.metadata = new MetadataAPI(this);
this.reachability = new DownloadReachability(this);
}

addResponseInterceptor(responseInterceptor: AxiosInterceptorManager<AxiosResponse>): void {
if (typeof responseInterceptor === 'function') {
this.interceptors.push(this.client.interceptors.response.use(responseInterceptor));
}
}

addRequestInterceptor(requestInterceptor: AxiosInterceptorManager<AxiosRequestConfig>): void {
if (typeof requestInterceptor === 'function') {
this.interceptors.push(this.client.interceptors.request.use(requestInterceptor));
}
}

ejectInterceptors(): void {
this.interceptors.forEach(interceptorIndex => {
this.client.interceptors.request.eject(interceptorIndex);
this.client.interceptors.response.eject(interceptorIndex);
});
}

delete<D>(url: string, data: D, options: AxiosRequestConfig = {}): AxiosPromise {
return this.xhr(url, { method: 'delete', data, ...options });
}

get(url: string, { type: responseType = 'json', ...options }: APIGetConfig = {}): AxiosPromise {
return this.xhr(url, { method: 'get', responseType, ...options });
}

head(url: string, options: AxiosRequestConfig = {}): AxiosPromise {
return this.xhr(url, { method: 'head', ...options });
}

post<D>(url: string, data: D, options: AxiosRequestConfig = {}): AxiosPromise {
return this.xhr(url, { method: 'post', data, ...options });
}

put<D>(url: string, data: D, options: AxiosRequestConfig = {}): AxiosPromise {
return this.xhr(url, { method: 'put', data, ...options });
}

xhr(url: string, options: AxiosRequestConfig = {}): AxiosPromise {
let transformResponse;

if (options.responseType === 'text') {
transformResponse = transformTextResponse;
}

return this.client(url, filterOptions({ transformResponse, ...options }))
.then(parseResponse)
.catch(handleError);
}
}
5 changes: 5 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"extends": "@box/frontend/ts/tsconfig.json",
"include": ["./src/**/*"],
"exclude": ["node_modules", "dist"]
}
Loading

0 comments on commit 0a4ed88

Please sign in to comment.