Sări la conținutul principal

Server Proxy API complet (Python)

Dacă frontend-ul JavaScript trebuie să apeleze punctele finale API Qarta, trebuie să rutezi acele cereri printr-un proxy pe partea de server. Integrarea cheii API în codul browserului o expune oricui vede sursa paginii sau traficul de rețea.

Proxy-ul din acest ghid redirecționează orice metodă HTTP către orice punct final Qarta, adăugând antetul Authorization pe partea de server. Frontend-ul tău face cereri neautentificate către proxy; proxy-ul autentifică și redirecționează.

Browser  →  /graph/api/v1/places/geocode?q=Berlin  →  Proxy (adaugă Authorization)  →  Qarta

Proxy-ul este intenționat minimal — doar atașează cheia API și redirecționează cererea. Nu stochează în cache, nu transformă și nu restricționează ce puncte finale pot fi apelate.

Descărcare

Descarcă api-proxy.zip

Fișierul zip conține proxy.py, pyproject.toml și o suită completă de teste.

Rularea proxy-ului

Instalare dependențe:

unzip api-proxy.zip
cd api-proxy
pip install -e ".[dev]"

Pornire server:

export QARTA_API_KEY=your_api_key_here
python proxy.py
# Listening on http://0.0.0.0:8081

Variabile de mediu opționale:

VariabilăImplicitDescriere
QARTA_API_KEY(obligatoriu)Cheia API Qarta
QARTA_BASE_URLhttps://graph.quarticle.roURL-ul de bază Qarta aval
PROXY_TIMEOUT30Timeout cere aval în secunde

Efectuarea de cereri prin proxy

În loc să apelezi Qarta direct cu o cheie API în browser:

// NU face asta în browser — expune cheia API
const response = await fetch(
'https://graph.quarticle.ro/graph/api/v1/places/geocode?q=Berlin',
{ headers: { 'Authorization': 'YOUR_API_KEY' } }
);

Apelează proxy-ul în schimb (fără antet Authorization necesar în cod pe partea de client):

// FA asta — proxy adaugă cheia API pe partea de server
const response = await fetch('/graph/api/v1/places/geocode?q=Berlin');
const data = await response.json();

Proxy-ul oglindește structura completă a URL-ului Qarta, deci orice cale care funcționează împotriva https://graph.quarticle.ro funcționează împotriva proxy-ului prin înlocuirea URL-ului de bază.

Cererile POST cu un corp JSON funcționează în același mod:

const response = await fetch('/graph/api/v1/reports/portfolio/points/selection', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ points: [{ lat: 51.5, lon: -0.1 }] })
});

Codul sursă al proxy-ului

examples/api-proxy/proxy.py
import os

import requests
from flask import Flask, Response, request

QARTA_BASE_URL = os.getenv("QARTA_BASE_URL", "https://graph.quarticle.ro")
QARTA_API_KEY = os.getenv("QARTA_API_KEY")
PROXY_TIMEOUT = int(os.getenv("PROXY_TIMEOUT", "30"))

# Anteturi din cererile clientului care nu trebuie redirecționate aval
_STRIP_HEADERS = {"host", "authorization", "transfer-encoding", "connection", "content-length"}

app = Flask(__name__)


@app.route("/<path:path>", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
def proxy(path: str) -> Response:
upstream_url = f"{QARTA_BASE_URL}/{path}"

forward_headers = {"Authorization": QARTA_API_KEY}
for key, value in request.headers:
if key.lower() not in _STRIP_HEADERS:
forward_headers[key] = value

resp = requests.request(
method=request.method,
url=upstream_url,
params=request.args,
data=request.get_data(),
headers=forward_headers,
timeout=PROXY_TIMEOUT,
stream=True,
)

return Response(
resp.iter_content(chunk_size=8192),
status=resp.status_code,
content_type=resp.headers.get("Content-Type", "application/octet-stream"),
)


if __name__ == "__main__":
if not QARTA_API_KEY:
raise RuntimeError("QARTA_API_KEY environment variable is required")
app.run(host="0.0.0.0", port=8081)

Rularea testelor

cd api-proxy
pytest tests/ -v

Testele utilizează responses pentru a simula toate apelurile Qarta aval — nu se fac cereri de rețea reale.

Pași următori