Add choices API endpoint and OpenAPI client setup
Introduces a new /api/choices/ endpoint for fetching model choices with multilingual labels. Updates Django models to use 'cz#' prefix for Czech labels. Adds OpenAPI client generation via orval, refactors frontend API structure, and provides documentation and helper scripts for dynamic choices and OpenAPI usage.
This commit is contained in:
18
frontend/src/api/chocies.ts
Normal file
18
frontend/src/api/chocies.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { publicApi } from "./publicClient";
|
||||
|
||||
export async function getChoices(queries: {
|
||||
model: string;
|
||||
field: string;
|
||||
lang?: string;
|
||||
}[]) {
|
||||
const params = new URLSearchParams();
|
||||
|
||||
queries.forEach((q) => {
|
||||
params.append("model", q.model);
|
||||
params.append("field", q.field);
|
||||
if (q.lang) params.append("lang", q.lang);
|
||||
});
|
||||
|
||||
const { data } = await publicApi.get(`/choices/?${params.toString()}`);
|
||||
return data; // typ: Array<{ value: string; label: string }>
|
||||
}
|
||||
9
frontend/src/api/docs/choices.md
Normal file
9
frontend/src/api/docs/choices.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# 🌈 Choices (dynamic enums)
|
||||
|
||||
Získaní možných hodnot pro pole s výběrem (ChoiceField) z backendu s podporou vícejazyčných labelů, definované v modelech Django.
|
||||
|
||||
```tsx
|
||||
const roles = await getChoices([
|
||||
{ model: "User", field: "role", lang: "cz" },
|
||||
]);
|
||||
```
|
||||
7
frontend/src/api/docs/example_of_getting_data.md
Normal file
7
frontend/src/api/docs/example_of_getting_data.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Získání seznamu objektů (např. Orders)
|
||||
|
||||
```typescript
|
||||
import { ordersList } from "@/api/generated/private";
|
||||
|
||||
const orders = await ordersList();
|
||||
```
|
||||
12
frontend/src/api/docs/login_logout.md
Normal file
12
frontend/src/api/docs/login_logout.md
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
# 🔐 Přihlášení (public)
|
||||
|
||||
```typescript
|
||||
|
||||
import { authLoginCreate } from "@/api/generated/public";
|
||||
|
||||
await authLoginCreate({
|
||||
email: "test@test.com",
|
||||
password: "secret",
|
||||
});
|
||||
```
|
||||
15
frontend/src/api/docs/soubory.md
Normal file
15
frontend/src/api/docs/soubory.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# 🖼️ Podpora FileField / ImageField
|
||||
|
||||
Orval automaticky vytvoří endpointy s multipart/form-data.
|
||||
|
||||
Použití:
|
||||
|
||||
```typescript
|
||||
import { productsUpdate } from "@/api/generated/private";
|
||||
|
||||
const form = new FormData();
|
||||
form.append("name", values.name);
|
||||
form.append("image", fileInput.files[0]);
|
||||
|
||||
await productsUpdate({ id: productId, data: form });
|
||||
```
|
||||
1
frontend/src/api/generated/filler
Normal file
1
frontend/src/api/generated/filler
Normal file
@@ -0,0 +1 @@
|
||||
v tehle složce se vygeneruje schema
|
||||
@@ -1,41 +0,0 @@
|
||||
import Client from "./Client";
|
||||
|
||||
/**
|
||||
* Loads enum values from an OpenAPI schema for a given path, method, and field (e.g., category).
|
||||
*
|
||||
* @param path - API path, e.g., "/api/service-tickets/"
|
||||
* @param method - HTTP method
|
||||
* @param field - field name in parameters or request
|
||||
* @param schemaUrl - URL of the JSON schema, default "/api/schema/?format=json"
|
||||
* @returns Promise<Array<{ value: string; label: string }>>
|
||||
*/
|
||||
export async function fetchEnumFromSchemaJson(
|
||||
path: string,
|
||||
method: "get" | "post" | "patch" | "put",
|
||||
field: string,
|
||||
schemaUrl: string = "/schema/?format=json"
|
||||
): Promise<Array<{ value: string; label: string }>> {
|
||||
try {
|
||||
const schema = await Client.public.get(schemaUrl);
|
||||
|
||||
const methodDef = schema.paths?.[path]?.[method];
|
||||
if (!methodDef) {
|
||||
throw new Error(`Method ${method.toUpperCase()} for ${path} not found in schema.`);
|
||||
}
|
||||
|
||||
// Search in "parameters" (e.g., GET query parameters)
|
||||
const param = methodDef.parameters?.find((p: any) => p.name === field);
|
||||
|
||||
if (param?.schema?.enum) {
|
||||
return param.schema.enum.map((val: string) => ({
|
||||
value: val,
|
||||
label: val,
|
||||
}));
|
||||
}
|
||||
|
||||
throw new Error(`Field '${field}' does not contain enum`);
|
||||
} catch (error) {
|
||||
console.error("Error loading enum values:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import Client from "../Client";
|
||||
import Client from "./Client";
|
||||
|
||||
// Available output containers (must match backend)
|
||||
export const FORMAT_EXTS = ["mp4", "mkv", "webm", "flv", "mov", "avi", "ogg"] as const;
|
||||
@@ -2,7 +2,7 @@
|
||||
// User API model for searching users by username
|
||||
// Structure matches other model files (see order.js for reference)
|
||||
|
||||
import Client from '../Client';
|
||||
import Client from '../legacy/Client';
|
||||
|
||||
const API_BASE_URL = "/account/users";
|
||||
|
||||
27
frontend/src/api/privateClient.ts
Normal file
27
frontend/src/api/privateClient.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import axios from "axios";
|
||||
|
||||
// použij tohle pro API vyžadující autentizaci
|
||||
export const privateApi = axios.create({
|
||||
baseURL: "/api/",
|
||||
withCredentials: true, // potřebuje HttpOnly cookies
|
||||
});
|
||||
|
||||
privateApi.interceptors.response.use(
|
||||
(res) => res,
|
||||
async (error) => {
|
||||
const original = error.config;
|
||||
|
||||
if (error.response?.status === 401 && !original._retry) {
|
||||
original._retry = true;
|
||||
|
||||
try {
|
||||
await privateApi.post("/auth/refresh/");
|
||||
return privateApi(original);
|
||||
} catch {
|
||||
// optional: logout
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
7
frontend/src/api/publicClient.ts
Normal file
7
frontend/src/api/publicClient.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import axios from "axios";
|
||||
|
||||
// použij tohle pro veřejné API nevyžadující autentizaci
|
||||
export const publicApi = axios.create({
|
||||
baseURL: "/api/",
|
||||
withCredentials: false, // veřejné API NEPOSÍLÁ cookies
|
||||
});
|
||||
Reference in New Issue
Block a user