conform casing and documentation

This commit is contained in:
Hayden 2022-09-04 16:55:52 -08:00
parent 572f0f6689
commit a9f271d8c1
9 changed files with 58 additions and 50 deletions

View file

@ -1,18 +1,18 @@
import { beforeAll, expect } from 'vitest'; import { beforeAll, expect } from 'vitest';
import { Requests } from '../../requests'; import { Requests } from '../../requests';
import { OverrideParts } from '../base/urls'; import { overrideParts } from '../base/urls';
import { PublicApi } from '../public'; import { PublicApi } from '../public';
import * as config from '../../../test/config'; import * as config from '../../../test/config';
import { UserApi } from '../user'; import { UserApi } from '../user';
export function client() { export function client() {
OverrideParts(config.BASE_URL, '/api/v1'); overrideParts(config.BASE_URL, '/api/v1');
const requests = new Requests(''); const requests = new Requests('');
return new PublicApi(requests); return new PublicApi(requests);
} }
export function userClient(token: string) { export function userClient(token: string) {
OverrideParts(config.BASE_URL, '/api/v1'); overrideParts(config.BASE_URL, '/api/v1');
const requests = new Requests('', token); const requests = new Requests('', token);
return new UserApi(requests); return new UserApi(requests);
} }

View file

@ -1,24 +1,24 @@
import { describe, expect, it } from 'vitest'; import { describe, expect, it } from 'vitest';
import { UrlBuilder } from '.'; import { route } from '.';
describe('UrlBuilder', () => { describe('UrlBuilder', () => {
it('basic query parameter', () => { it('basic query parameter', () => {
const result = UrlBuilder('/test', { a: 'b' }); const result = route('/test', { a: 'b' });
expect(result).toBe('/api/v1/test?a=b'); expect(result).toBe('/api/v1/test?a=b');
}); });
it('multiple query parameters', () => { it('multiple query parameters', () => {
const result = UrlBuilder('/test', { a: 'b', c: 'd' }); const result = route('/test', { a: 'b', c: 'd' });
expect(result).toBe('/api/v1/test?a=b&c=d'); expect(result).toBe('/api/v1/test?a=b&c=d');
}); });
it('no query parameters', () => { it('no query parameters', () => {
const result = UrlBuilder('/test'); const result = route('/test');
expect(result).toBe('/api/v1/test'); expect(result).toBe('/api/v1/test');
}); });
it('list-like query parameters', () => { it('list-like query parameters', () => {
const result = UrlBuilder('/test', { a: ['b', 'c'] }); const result = route('/test', { a: ['b', 'c'] });
expect(result).toBe('/api/v1/test?a=b&a=c'); expect(result).toBe('/api/v1/test?a=b&a=c');
}); });
}); });

View file

@ -1,2 +1,2 @@
export { BaseAPI } from './base-api'; export { BaseAPI } from './base-api';
export { UrlBuilder } from './urls'; export { route } from './urls';

View file

@ -3,14 +3,23 @@ const parts = {
prefix: '/api/v1', prefix: '/api/v1',
}; };
export function OverrideParts(host: string, prefix: string) { export function overrideParts(host: string, prefix: string) {
parts.host = host; parts.host = host;
parts.prefix = prefix; parts.prefix = prefix;
} }
export type QueryValue = string | string[] | number | number[] | boolean | null | undefined; export type QueryValue = string | string[] | number | number[] | boolean | null | undefined;
export function UrlBuilder(rest: string, params: Record<string, QueryValue> = {}): string { /**
* route is a the main URL builder for the API. It will use a predefined host and prefix (global)
* in the urls.ts file and then append the passed in path parameter uring the `URL` class from the
* browser. It will also append any query parameters passed in as the second parameter.
*
* The default host `http://localhost.com` is removed from the path if it is present. This allows us
* to bootstrap the API with different hosts as needed (like for testing) but still allows us to use
* relative URLs in pruduction because the API and client bundle are served from the same server/host.
*/
export function route(rest: string, params: Record<string, QueryValue> = {}): string {
const url = new URL(parts.prefix + rest, parts.host); const url = new URL(parts.prefix + rest, parts.host);
for (const [key, value] of Object.entries(params)) { for (const [key, value] of Object.entries(params)) {
@ -23,6 +32,5 @@ export function UrlBuilder(rest: string, params: Record<string, QueryValue> = {}
} }
} }
// we return the path only, without the base URL
return url.toString().replace('http://localhost.com', ''); return url.toString().replace('http://localhost.com', '');
} }

View file

@ -1,4 +1,4 @@
import { BaseAPI, UrlBuilder } from '../base'; import { BaseAPI, route } from '../base';
import { Label } from './labels'; import { Label } from './labels';
import { Location } from './locations'; import { Location } from './locations';
import { Results } from './types'; import { Results } from './types';
@ -33,22 +33,22 @@ export interface Item {
export class ItemsApi extends BaseAPI { export class ItemsApi extends BaseAPI {
async getAll() { async getAll() {
return this.http.get<Results<Item>>(UrlBuilder('/items')); return this.http.get<Results<Item>>(route('/items'));
} }
async create(item: ItemCreate) { async create(item: ItemCreate) {
return this.http.post<ItemCreate, Item>(UrlBuilder('/items'), item); return this.http.post<ItemCreate, Item>(route('/items'), item);
} }
async get(id: string) { async get(id: string) {
return this.http.get<Item>(UrlBuilder(`/items/${id}`)); return this.http.get<Item>(route(`/items/${id}`));
} }
async delete(id: string) { async delete(id: string) {
return this.http.delete<void>(UrlBuilder(`/items/${id}`)); return this.http.delete<void>(route(`/items/${id}`));
} }
async update(id: string, item: ItemCreate) { async update(id: string, item: ItemCreate) {
return this.http.put<ItemCreate, Item>(UrlBuilder(`/items/${id}`), item); return this.http.put<ItemCreate, Item>(route(`/items/${id}`), item);
} }
} }

View file

@ -1,4 +1,4 @@
import { BaseAPI, UrlBuilder } from '../base'; import { BaseAPI, route } from '../base';
import { Details, OutType, Results } from './types'; import { Details, OutType, Results } from './types';
export type LabelCreate = Details & { export type LabelCreate = Details & {
@ -14,22 +14,22 @@ export type Label = LabelCreate &
export class LabelsApi extends BaseAPI { export class LabelsApi extends BaseAPI {
async getAll() { async getAll() {
return this.http.get<Results<Label>>(UrlBuilder('/labels')); return this.http.get<Results<Label>>(route('/labels'));
} }
async create(label: LabelCreate) { async create(label: LabelCreate) {
return this.http.post<LabelCreate, Label>(UrlBuilder('/labels'), label); return this.http.post<LabelCreate, Label>(route('/labels'), label);
} }
async get(id: string) { async get(id: string) {
return this.http.get<Label>(UrlBuilder(`/labels/${id}`)); return this.http.get<Label>(route(`/labels/${id}`));
} }
async delete(id: string) { async delete(id: string) {
return this.http.delete<void>(UrlBuilder(`/labels/${id}`)); return this.http.delete<void>(route(`/labels/${id}`));
} }
async update(id: string, label: LabelUpdate) { async update(id: string, label: LabelUpdate) {
return this.http.put<LabelUpdate, Label>(UrlBuilder(`/labels/${id}`), label); return this.http.put<LabelUpdate, Label>(route(`/labels/${id}`), label);
} }
} }

View file

@ -1,4 +1,4 @@
import { BaseAPI, UrlBuilder } from '../base'; import { BaseAPI, route } from '../base';
import { Item } from './items'; import { Item } from './items';
import { Details, OutType, Results } from './types'; import { Details, OutType, Results } from './types';
@ -15,21 +15,21 @@ export type LocationUpdate = LocationCreate;
export class LocationsApi extends BaseAPI { export class LocationsApi extends BaseAPI {
async getAll() { async getAll() {
return this.http.get<Results<Location>>(UrlBuilder('/locations')); return this.http.get<Results<Location>>(route('/locations'));
} }
async create(location: LocationCreate) { async create(location: LocationCreate) {
return this.http.post<LocationCreate, Location>(UrlBuilder('/locations'), location); return this.http.post<LocationCreate, Location>(route('/locations'), location);
} }
async get(id: string) { async get(id: string) {
return this.http.get<Location>(UrlBuilder(`/locations/${id}`)); return this.http.get<Location>(route(`/locations/${id}`));
} }
async delete(id: string) { async delete(id: string) {
return this.http.delete<void>(UrlBuilder(`/locations/${id}`)); return this.http.delete<void>(route(`/locations/${id}`));
} }
async update(id: string, location: LocationUpdate) { async update(id: string, location: LocationUpdate) {
return this.http.put<LocationUpdate, Location>(UrlBuilder(`/locations/${id}`), location); return this.http.put<LocationUpdate, Location>(route(`/locations/${id}`), location);
} }
} }

View file

@ -1,4 +1,4 @@
import { BaseAPI, UrlBuilder } from './base'; import { BaseAPI, route } from './base';
export type LoginResult = { export type LoginResult = {
token: string; token: string;
@ -28,17 +28,17 @@ export type StatusResult = {
export class PublicApi extends BaseAPI { export class PublicApi extends BaseAPI {
public status() { public status() {
return this.http.get<StatusResult>(UrlBuilder('/status')); return this.http.get<StatusResult>(route('/status'));
} }
public login(username: string, password: string) { public login(username: string, password: string) {
return this.http.post<LoginPayload, LoginResult>(UrlBuilder('/users/login'), { return this.http.post<LoginPayload, LoginResult>(route('/users/login'), {
username, username,
password, password,
}); });
} }
public register(payload: RegisterPayload) { public register(payload: RegisterPayload) {
return this.http.post<RegisterPayload, LoginResult>(UrlBuilder('/users/register'), payload); return this.http.post<RegisterPayload, LoginResult>(route('/users/register'), payload);
} }
} }

View file

@ -1,5 +1,5 @@
import { Requests } from '~~/lib/requests'; import { Requests } from '~~/lib/requests';
import { BaseAPI, UrlBuilder } from './base'; import { BaseAPI, route } from './base';
import { ItemsApi } from './classes/items'; import { ItemsApi } from './classes/items';
import { LabelsApi } from './classes/labels'; import { LabelsApi } from './classes/labels';
import { LocationsApi } from './classes/locations'; import { LocationsApi } from './classes/locations';
@ -30,14 +30,14 @@ export class UserApi extends BaseAPI {
} }
public self() { public self() {
return this.http.get<Result<User>>(UrlBuilder('/users/self')); return this.http.get<Result<User>>(route('/users/self'));
} }
public logout() { public logout() {
return this.http.post<object, void>(UrlBuilder('/users/logout'), {}); return this.http.post<object, void>(route('/users/logout'), {});
} }
public deleteAccount() { public deleteAccount() {
return this.http.delete<void>(UrlBuilder('/users/self')); return this.http.delete<void>(route('/users/self'));
} }
} }