portal_publico/static/js/api.js

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;
}