80 lines
2.5 KiB
JavaScript
80 lines
2.5 KiB
JavaScript
const PID_API_BASE = "/api";
|
|
|
|
function pidGetCookie(name) {
|
|
const match = document.cookie.match(new RegExp(`(?:^|; )${name}=([^;]*)`));
|
|
return match ? decodeURIComponent(match[1]) : null;
|
|
}
|
|
|
|
async function pidEnsureCsrfCookie() {
|
|
if (pidGetCookie("csrftoken")) return;
|
|
await fetch(`${PID_API_BASE}/auth/csrf/`, { credentials: "include" });
|
|
}
|
|
|
|
function pidErrorMessageFrom(data) {
|
|
if (!data) return "Erro ao processar a solicitação.";
|
|
if (typeof data === "string") return data;
|
|
if (typeof data.detail === "string") return data.detail;
|
|
const values = Object.values(data).flat().filter((v) => typeof v === "string");
|
|
return values.length ? values.join(" ") : "Erro ao processar a solicitação.";
|
|
}
|
|
|
|
/**
|
|
* Fetch com sessão (cookie) do Django. Adiciona X-CSRFToken automaticamente em
|
|
* métodos que não são GET/HEAD/OPTIONS, buscando o cookie csrftoken antes se
|
|
* ainda não existir. Em 401, redireciona para o login por padrão — passe
|
|
* `redirectOn401: false` em telas onde uma resposta 401 é esperada (ex.: o
|
|
* próprio formulário de login, ou a checagem de sessão já ativa em index.html).
|
|
*/
|
|
async function pidApiRequest(path, options = {}) {
|
|
const method = (options.method || "GET").toUpperCase();
|
|
const isSafeMethod = method === "GET" || method === "HEAD" || method === "OPTIONS";
|
|
const redirectOn401 = options.redirectOn401 !== false;
|
|
|
|
if (!isSafeMethod) await pidEnsureCsrfCookie();
|
|
|
|
const headers = { Accept: "application/json", ...(options.headers || {}) };
|
|
let body = options.body;
|
|
const isFormData = typeof FormData !== "undefined" && body instanceof FormData;
|
|
if (body !== undefined && !isFormData) {
|
|
headers["Content-Type"] = "application/json";
|
|
body = JSON.stringify(body);
|
|
}
|
|
// FormData: deixa o browser definir o Content-Type (com o boundary do multipart) sozinho.
|
|
if (!isSafeMethod) headers["X-CSRFToken"] = pidGetCookie("csrftoken") || "";
|
|
|
|
let response;
|
|
try {
|
|
response = await fetch(`${PID_API_BASE}${path}`, {
|
|
method,
|
|
credentials: "include",
|
|
headers,
|
|
body,
|
|
});
|
|
} catch (e) {
|
|
throw new Error("Não foi possível conectar ao servidor.");
|
|
}
|
|
|
|
if (response.status === 401 && redirectOn401) {
|
|
window.location.href = "index.html";
|
|
return null;
|
|
}
|
|
|
|
if (response.status === 204) return null;
|
|
|
|
const text = await response.text();
|
|
let data = null;
|
|
if (text) {
|
|
try {
|
|
data = JSON.parse(text);
|
|
} catch (e) {
|
|
data = null;
|
|
}
|
|
}
|
|
|
|
if (!response.ok) {
|
|
throw new Error(pidErrorMessageFrom(data));
|
|
}
|
|
|
|
return data;
|
|
}
|