Skip to content

Commit

Permalink
refactor: separate API configs (#584)
Browse files Browse the repository at this point in the history
  • Loading branch information
hamidzr authored Jun 1, 2020
1 parent 4050020 commit 6dcfde7
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 121 deletions.
5 changes: 3 additions & 2 deletions webui/react/src/pages/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import Users from 'contexts/Users';
import usePolling from 'hooks/usePolling';
import { useRestApiSimple } from 'hooks/useRestApi';
import useStorage from 'hooks/useStorage';
import { ExperimentsParams, getExperiments } from 'services/api';
import { getExperimentSummaries } from 'services/api';
import { ExperimentsParams } from 'services/types';
import { ShirtSize } from 'themes';
import {
Command, CommandState, Experiment, RecentTask, ResourceType, RunState, TaskType,
Expand Down Expand Up @@ -59,7 +60,7 @@ const Dashboard: React.FC = () => {
const shells = Shells.useStateContext();
const tensorboards = Tensorboards.useStateContext();
const [ experimentsResponse, requestExperiments ] =
useRestApiSimple<ExperimentsParams, Experiment[]>(getExperiments, {});
useRestApiSimple<ExperimentsParams, Experiment[]>(getExperimentSummaries, {});
const storage = useStorage('dashboard/tasks');
const initFilters = storage.getWithDefault('filters',
{ ...defaultFilters, username: (auth.user || {}).username });
Expand Down
5 changes: 3 additions & 2 deletions webui/react/src/pages/Determined.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import usePolling from 'hooks/usePolling';
import useRestApi, { useRestApiSimple } from 'hooks/useRestApi';
import { ioAgents, ioGenericCommands, ioUsers } from 'ioTypes';
import { detRoutes } from 'routes';
import { ExperimentsParams, getExperiments } from 'services/api';
import { getExperimentSummaries } from 'services/api';
import {
jsonToAgents, jsonToCommands, jsonToNotebooks,
jsonToShells, jsonToTensorboards, jsonToUsers,
} from 'services/decoder';
import { ExperimentsParams } from 'services/types';
import { Agent, Command, Experiment, RunState, User } from 'types';

import css from './Determined.module.scss';
Expand Down Expand Up @@ -43,7 +44,7 @@ const Determined: React.FC = () => {
const [ commandsResponse, requestCommands ] =
useRestApi<Command[]>(ioGenericCommands, { mappers: jsonToCommands });
const [ experimentsResponse, requestExperiments ] =
useRestApiSimple<ExperimentsParams, Experiment[]>(getExperiments, {});
useRestApiSimple<ExperimentsParams, Experiment[]>(getExperimentSummaries, {});
const [ notebooksResponse, requestNotebooks ] =
useRestApi<Command[]>(ioGenericCommands, { mappers: jsonToNotebooks });
const [ shellsResponse, requestShells ] =
Expand Down
129 changes: 12 additions & 117 deletions webui/react/src/services/api.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
import { CancelToken } from 'axios';
import { sha512 } from 'js-sha512';

import { decode, ioTypeUser, ioUser } from 'ioTypes';
import { Api, generateApi } from 'services/apiBuilder';
import { jsonToExperiments } from 'services/decoder';
import { generateApi } from 'services/apiBuilder';
import * as Config from 'services/apiConfig';
import { ExperimentsParams, KillCommandParams, KillExpParams,
PatchExperimentParams } from 'services/types';
import { CommandType, Credentials, Experiment, RecentTask, TaskType, User } from 'types';

const commandToEndpoint: Record<CommandType, string> = {
[CommandType.Command]: '/commands',
[CommandType.Notebook]: '/notebooks',
[CommandType.Tensorboard]: '/tensorboard',
[CommandType.Shell]: '/shells',
};

/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
export const isAuthFailure = (e: any): boolean => {
return e.response && e.response.status && e.response.status === 401;
Expand All @@ -24,93 +17,16 @@ export const isLoginFailure = (e: any): boolean => {
return e.response && e.response.status && e.response.status === 403;
};

const saltAndHashPassword = (password?: string): string => {
if (!password) return '';
const passwordSalt = 'GubPEmmotfiK9TMD6Zdw';
return sha512(passwordSalt + password);
};

const userApi: Api<{}, User> = {
httpOptions: () => { return { url: '/users/me' }; },
name: 'user',
postProcess: (response) => {
const result = decode<ioTypeUser>(ioUser, response.data);
return {
id: result.id,
isActive: result.active,
isAdmin: result.admin,
username: result.username,
};
},
};

export const getCurrentUser = generateApi<{}, User>(userApi);

export interface ExperimentsParams {
states?: string[];
}

const experimentsApi: Api<ExperimentsParams, Experiment[]> = {
httpOptions: (params) => ({
url: '/experiment-summaries' + (params.states ? '?states='+params.states.join(',') : ''),
}),
name: 'getExperiments',
postProcess: (response) => jsonToExperiments(response.data),
};

export const getExperiments = generateApi<ExperimentsParams, Experiment[]>(experimentsApi);

interface KillExpParams {
experimentId: number;
}

const killExperimentApi: Api<KillExpParams, void> = {
httpOptions: (params) => {
return {
method: 'POST',
url: `/experiments/${params.experimentId.toString()}/kill`,
};
},
name: 'killExperiment',
};

export const killExperiment = generateApi<KillExpParams, void>(killExperimentApi);
export const getCurrentUser = generateApi<{}, User>(Config.getCurrentUser);

interface KillCommandParams {
commandId: string;
commandType: CommandType;
}
export const getExperimentSummaries =
generateApi<ExperimentsParams, Experiment[]>(Config.getExperimentSummaries);

const killCommandApi: Api<KillCommandParams, void> = {
httpOptions: (params) => {
return {
method: 'DELETE',
url: `${commandToEndpoint[params.commandType]}/${params.commandId}`,
};
},
name: 'killCommand',
};

export const killCommand = generateApi<KillCommandParams, void>(killCommandApi);
export const killExperiment = generateApi<KillExpParams, void>(Config.killExperiment);

interface PatchExperimentParams {
experimentId: number;
body: Record<keyof unknown, unknown> | string;
}
export const killCommand = generateApi<KillCommandParams, void>(Config.killCommand);

const patchExperimentApi: Api<PatchExperimentParams, void> = {
httpOptions: (params) => {
return {
body: params.body,
headers: { 'content-type': 'application/merge-patch+json', 'withCredentials': true },
method: 'PATCH',
url: `/experiments/${params.experimentId.toString()}`,
};
},
name: 'patchExperiment',
};

export const patchExperiment = generateApi<PatchExperimentParams, void>(patchExperimentApi);
export const patchExperiment = generateApi<PatchExperimentParams, void>(Config.patchExperiment);

export const killTask =
async (task: RecentTask, cancelToken?: CancelToken): Promise<void> => {
Expand All @@ -129,27 +45,6 @@ export const archiveExperiment =
return patchExperiment({ body: { archived: isArchived }, cancelToken, experimentId });
};

const loginApi: Api<Credentials, void> = {
httpOptions: ({ password, username }) => {
return {
body: { password: saltAndHashPassword(password), username },
method: 'POST',
url: '/login?cookie=true',
};
},
name: 'login',
};

export const login = generateApi<Credentials, void>(loginApi);

const logoutApi: Api<{}, void> = {
httpOptions: () => {
return {
method: 'POST',
url: '/logout',
};
},
name: 'logout',
};
export const login = generateApi<Credentials, void>(Config.login);

export const logout = generateApi<{}, void>(logoutApi);
export const logout = generateApi<{}, void>(Config.logout);
104 changes: 104 additions & 0 deletions webui/react/src/services/apiConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { sha512 } from 'js-sha512';

import { decode, ioTypeUser, ioUser } from 'ioTypes';
import { Api } from 'services/apiBuilder';
import { jsonToExperiments } from 'services/decoder';
import { ExperimentsParams, KillCommandParams, KillExpParams,
PatchExperimentParams } from 'services/types';
import { CommandType, Credentials, Experiment, User } from 'types';

/* Helpers */

const saltAndHashPassword = (password?: string): string => {
if (!password) return '';
const passwordSalt = 'GubPEmmotfiK9TMD6Zdw';
return sha512(passwordSalt + password);
};

const commandToEndpoint: Record<CommandType, string> = {
[CommandType.Command]: '/commands',
[CommandType.Notebook]: '/notebooks',
[CommandType.Tensorboard]: '/tensorboard',
[CommandType.Shell]: '/shells',
};

/* Authentication */

export const getCurrentUser: Api<{}, User> = {
httpOptions: () => ({ url: '/users/me' }),
name: 'getCurrentUser',
postProcess: (response) => {
const result = decode<ioTypeUser>(ioUser, response.data);
return {
id: result.id,
isActive: result.active,
isAdmin: result.admin,
username: result.username,
};
},
};

export const login: Api<Credentials, void> = {
httpOptions: ({ password, username }) => {
return {
body: { password: saltAndHashPassword(password), username },
method: 'POST',
url: '/login?cookie=true',
};
},
name: 'login',
};

export const logout: Api<{}, void> = {
httpOptions: () => {
return {
method: 'POST',
url: '/logout',
};
},
name: 'logout',
};

/* Commands */

export const killCommand: Api<KillCommandParams, void> = {
httpOptions: (params) => {
return {
method: 'DELETE',
url: `${commandToEndpoint[params.commandType]}/${params.commandId}`,
};
},
name: 'killCommand',
};

/* Experiment */

export const patchExperiment: Api<PatchExperimentParams, void> = {
httpOptions: (params) => {
return {
body: params.body,
headers: { 'content-type': 'application/merge-patch+json', 'withCredentials': true },
method: 'PATCH',
url: `/experiments/${params.experimentId.toString()}`,
};
},
name: 'patchExperiment',
};

export const killExperiment: Api<KillExpParams, void> = {
httpOptions: (params) => {
return {
method: 'POST',
url: `/experiments/${params.experimentId.toString()}/kill`,
};
},
name: 'killExperiment',
};

export const getExperimentSummaries: Api<ExperimentsParams, Experiment[]> = {
httpOptions: (params) => ({
url: '/experiment-summaries' + (params.states ? '?states='+params.states.join(',') : ''),
}),
name: 'getExperimentSummaries',
postProcess: (response) => jsonToExperiments(response.data),
};
19 changes: 19 additions & 0 deletions webui/react/src/services/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { CommandType } from 'types';

export interface ExperimentsParams {
states?: string[];
}

export interface KillExpParams {
experimentId: number;
}

export interface KillCommandParams {
commandId: string;
commandType: CommandType;
}

export interface PatchExperimentParams {
experimentId: number;
body: Record<keyof unknown, unknown> | string;
}

0 comments on commit 6dcfde7

Please sign in to comment.