mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-19 17:59:11 -06:00
implement generic api request function
This commit is contained in:
parent
f7c1bc71d9
commit
82ef6f8ac5
7
netbox/project-static/src/global.d.ts
vendored
7
netbox/project-static/src/global.d.ts
vendored
@ -2,6 +2,8 @@ type Primitives = string | number | boolean | undefined | null;
|
|||||||
|
|
||||||
type JSONAble = Primitives | Primitives[] | { [k: string]: JSONAble } | JSONAble[];
|
type JSONAble = Primitives | Primitives[] | { [k: string]: JSONAble } | JSONAble[];
|
||||||
|
|
||||||
|
type Dict<T extends unknown = unknown> = Record<string, T>;
|
||||||
|
|
||||||
type Nullable<T> = T | null;
|
type Nullable<T> = T | null;
|
||||||
|
|
||||||
type APIAnswer<T> = {
|
type APIAnswer<T> = {
|
||||||
@ -91,6 +93,11 @@ type APIJobResult = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type APIUserConfig = {
|
||||||
|
tables: { [k: string]: { columns: string[]; available_columns: string[] } };
|
||||||
|
[k: string]: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
interface ObjectWithGroup extends APIObjectBase {
|
interface ObjectWithGroup extends APIObjectBase {
|
||||||
group: Nullable<APIReference>;
|
group: Nullable<APIReference>;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
import Cookie from 'cookie';
|
import Cookie from 'cookie';
|
||||||
|
|
||||||
|
type APIRes<T> = T | ErrorBase | APIError;
|
||||||
|
type Method = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
|
||||||
|
type ReqData = URLSearchParams | Dict | undefined | unknown;
|
||||||
|
type SelectedOption = { name: string; options: string[] };
|
||||||
|
|
||||||
export function isApiError(data: Record<string, unknown>): data is APIError {
|
export function isApiError(data: Record<string, unknown>): data is APIError {
|
||||||
return 'error' in data && 'exception' in data;
|
return 'error' in data && 'exception' in data;
|
||||||
}
|
}
|
||||||
@ -35,58 +41,56 @@ export function getCsrfToken(): string {
|
|||||||
return csrfToken;
|
return csrfToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function apiGetBase<T extends Record<string, unknown>>(
|
export async function apiRequest<R extends Dict, D extends ReqData = undefined>(
|
||||||
url: string,
|
url: string,
|
||||||
): Promise<T | ErrorBase | APIError> {
|
method: Method,
|
||||||
|
data?: D,
|
||||||
|
): Promise<APIRes<R>> {
|
||||||
const token = getCsrfToken();
|
const token = getCsrfToken();
|
||||||
const res = await fetch(url, {
|
const headers = new Headers({ 'X-CSRFToken': token });
|
||||||
method: 'GET',
|
|
||||||
headers: { 'X-CSRFToken': token },
|
let body;
|
||||||
credentials: 'same-origin',
|
if (typeof data !== 'undefined') {
|
||||||
});
|
body = JSON.stringify(data);
|
||||||
|
headers.set('content-type', 'application/json');
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await fetch(url, { method, body, headers, credentials: 'same-origin' });
|
||||||
const contentType = res.headers.get('Content-Type');
|
const contentType = res.headers.get('Content-Type');
|
||||||
if (typeof contentType === 'string' && contentType.includes('text')) {
|
if (typeof contentType === 'string' && contentType.includes('text')) {
|
||||||
const error = await res.text();
|
const error = await res.text();
|
||||||
return { error } as ErrorBase;
|
return { error } as ErrorBase;
|
||||||
}
|
}
|
||||||
|
const json = (await res.json()) as R | APIError;
|
||||||
const json = (await res.json()) as T | APIError;
|
|
||||||
if (!res.ok && Array.isArray(json)) {
|
if (!res.ok && Array.isArray(json)) {
|
||||||
const error = json.join('\n');
|
const error = json.join('\n');
|
||||||
return { error } as ErrorBase;
|
return { error } as ErrorBase;
|
||||||
|
} else if (!res.ok && 'detail' in json) {
|
||||||
|
return { error: json.detail } as ErrorBase;
|
||||||
}
|
}
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function apiPostForm<
|
export async function apiPatch<R extends Dict, D extends ReqData = Dict>(
|
||||||
T extends Record<string, unknown>,
|
url: string,
|
||||||
R extends Record<string, unknown>
|
data: D,
|
||||||
>(url: string, data: T): Promise<R | ErrorBase | APIError> {
|
): Promise<APIRes<R>> {
|
||||||
const token = getCsrfToken();
|
return await apiRequest(url, 'PATCH', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function apiGetBase<R extends Dict>(url: string): Promise<APIRes<R>> {
|
||||||
|
return await apiRequest<R>(url, 'GET');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function apiPostForm<R extends Dict, D extends Dict>(
|
||||||
|
url: string,
|
||||||
|
data: D,
|
||||||
|
): Promise<APIRes<R>> {
|
||||||
const body = new URLSearchParams();
|
const body = new URLSearchParams();
|
||||||
for (const [k, v] of Object.entries(data)) {
|
for (const [k, v] of Object.entries(data)) {
|
||||||
body.append(k, String(v));
|
body.append(k, String(v));
|
||||||
}
|
}
|
||||||
const res = await fetch(url, {
|
return await apiRequest<R, URLSearchParams>(url, 'POST', body);
|
||||||
method: 'POST',
|
|
||||||
body,
|
|
||||||
headers: { 'X-CSRFToken': token },
|
|
||||||
});
|
|
||||||
|
|
||||||
const contentType = res.headers.get('Content-Type');
|
|
||||||
if (typeof contentType === 'string' && contentType.includes('text')) {
|
|
||||||
let error = await res.text();
|
|
||||||
if (contentType.includes('text/html')) {
|
|
||||||
error = res.statusText;
|
|
||||||
}
|
|
||||||
return { error } as ErrorBase;
|
|
||||||
}
|
|
||||||
|
|
||||||
const json = (await res.json()) as R | APIError;
|
|
||||||
if (!res.ok && 'detail' in json) {
|
|
||||||
return { error: json.detail as string } as ErrorBase;
|
|
||||||
}
|
|
||||||
return json;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -139,3 +143,19 @@ export function scrollTo(element: Element, offset: number = 0): void {
|
|||||||
window.scrollTo({ top, behavior: 'smooth' });
|
window.scrollTo({ top, behavior: 'smooth' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getSelectedOptions<E extends HTMLElement>(base: E): SelectedOption[] {
|
||||||
|
let selected = [] as SelectedOption[];
|
||||||
|
for (const element of base.querySelectorAll<HTMLSelectElement>('select')) {
|
||||||
|
if (element !== null) {
|
||||||
|
const select = { name: element.name, options: [] } as SelectedOption;
|
||||||
|
for (const option of element.options) {
|
||||||
|
if (option.selected) {
|
||||||
|
select.options.push(option.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selected = [...selected, select];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user