diff options
Diffstat (limited to 'viewer-bff/server.js')
| -rw-r--r-- | viewer-bff/server.js | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/viewer-bff/server.js b/viewer-bff/server.js new file mode 100644 index 0000000..30ef81a --- /dev/null +++ b/viewer-bff/server.js @@ -0,0 +1,115 @@ +const express = require("express");
+const path = require("path");
+
+const app = express();
+
+const PORT = process.env.PORT || 8082;
+const MEDIA_API_BASE_URL =
+ process.env.MEDIA_API_BASE_URL || "http://media-access-api:8081";
+const CORS_ALLOWED_ORIGIN = process.env.CORS_ALLOWED_ORIGIN || "*";
+
+app.use(express.json({ limit: "1mb" }));
+
+app.use((req, res, next) => {
+ res.setHeader("Access-Control-Allow-Origin", CORS_ALLOWED_ORIGIN);
+ res.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS");
+ res.setHeader("Access-Control-Allow-Headers", "Authorization,Content-Type");
+ if (req.method === "OPTIONS") {
+ return res.sendStatus(204);
+ }
+ return next();
+});
+
+app.use(express.static(path.join(__dirname, "public")));
+
+app.get("/health", (_req, res) => {
+ res.json({
+ status: "ok",
+ service: "viewer-bff",
+ mediaApiBaseUrl: MEDIA_API_BASE_URL
+ });
+});
+
+function getBearerToken(req) {
+ const authHeader = req.headers.authorization || "";
+ if (!authHeader.startsWith("Bearer ")) {
+ return null;
+ }
+ return authHeader.slice("Bearer ".length).trim();
+}
+
+async function proxyJson(req, res, targetPath, method = "GET", body) {
+ const token = getBearerToken(req);
+ if (!token) {
+ return res.status(401).json({
+ error: "missing_token",
+ message: "Header Authorization Bearer requis"
+ });
+ }
+
+ try {
+ const response = await fetch(`${MEDIA_API_BASE_URL}${targetPath}`, {
+ method,
+ headers: {
+ Authorization: `Bearer ${token}`,
+ "Content-Type": "application/json"
+ },
+ body: body ? JSON.stringify(body) : undefined
+ });
+
+ const text = await response.text();
+ let payload = {};
+ if (text) {
+ try {
+ payload = JSON.parse(text);
+ } catch (_err) {
+ payload = { raw: text };
+ }
+ }
+
+ if (!response.ok) {
+ return res.status(response.status).json({
+ error: "media_api_error",
+ status: response.status,
+ message: payload.message || "Erreur retour media-access-api",
+ details: payload
+ });
+ }
+
+ return res.status(response.status).json(payload);
+ } catch (error) {
+ return res.status(502).json({
+ error: "media_api_unreachable",
+ message: "Impossible de joindre media-access-api",
+ details: error.message
+ });
+ }
+}
+
+app.get("/api/me/permissions", async (req, res) => {
+ return proxyJson(req, res, "/v1/permissions", "GET");
+});
+
+app.post("/api/media/presign", async (req, res) => {
+ const objectKey = req.body?.objectKey;
+ if (!objectKey || typeof objectKey !== "string") {
+ return res.status(400).json({
+ error: "invalid_payload",
+ message: "Champ objectKey requis"
+ });
+ }
+
+ return proxyJson(req, res, "/v1/presign", "POST", { objectKey });
+});
+
+app.get("*", (req, res) => {
+ if (req.path.startsWith("/api/")) {
+ return res.status(404).json({ error: "not_found" });
+ }
+ return res.sendFile(path.join(__dirname, "public", "index.html"));
+});
+
+app.listen(PORT, () => {
+ // eslint-disable-next-line no-console
+ console.log(`viewer-bff listening on port ${PORT}`);
+});
|
