summaryrefslogtreecommitdiff
path: root/src/app/db/service/base/response.js
diff options
context:
space:
mode:
authorJules Laplace <julescarbon@gmail.com>2021-10-17 02:52:05 +0200
committerJules Laplace <julescarbon@gmail.com>2021-10-17 02:52:05 +0200
commit06ecdf2af182034496e2123852deee4a58de1043 (patch)
treec8d4eb9664dd368bee5a4bf73dd1e02015ecaf39 /src/app/db/service/base/response.js
making a shoebox
Diffstat (limited to 'src/app/db/service/base/response.js')
-rw-r--r--src/app/db/service/base/response.js118
1 files changed, 118 insertions, 0 deletions
diff --git a/src/app/db/service/base/response.js b/src/app/db/service/base/response.js
new file mode 100644
index 0000000..a4bac60
--- /dev/null
+++ b/src/app/db/service/base/response.js
@@ -0,0 +1,118 @@
+/**
+ * Service API responses
+ * @module app/db/service/base/response
+ */
+
+import { zipCSVs, stringifyCSV, sanitizeCSV } from "app/utils/file_utils";
+import debugModule from "debug";
+
+/**
+ * Debug logger
+ */
+const debug = debugModule("shoebox:service");
+
+/**
+ * Middleware to return the response as JSON or CSV
+ */
+export async function sendResponse(request, response) {
+ if (response.locals.csv) {
+ if (response.locals.csv.files) {
+ await sendCSVZipResponse(response);
+ } else {
+ await sendCSVResponse(response);
+ }
+ } else {
+ await sendJSONResponse(response);
+ }
+}
+
+/**
+ * Respond with a ZIP file containing multiple CSVs
+ * @param {Response} response the response object
+ */
+async function sendCSVZipResponse(response) {
+ const zipData = await zipCSVs(response.locals.csv.files);
+ response.set("Content-Type", "application/zip");
+ response.set(
+ "Content-Disposition",
+ `attachment; filename=${response.locals.csv.filename}`
+ );
+ response.set("Content-Length", zipData.length);
+ response.set("Access-Control-Expose-Headers", "Content-Disposition");
+ response.write(zipData, "binary");
+ response.end(null, "binary");
+}
+
+/**
+ * Respond with a single CSV
+ * @param {Response} response the response object
+ */
+async function sendCSVResponse(response) {
+ const csvData = await stringifyCSV(sanitizeCSV(response.locals.csv.data));
+ response.set("Content-Type", "text/csv; charset=utf-8");
+ response.set(
+ "Content-Disposition",
+ `attachment; filename=${response.locals.csv.filename}`
+ );
+ response.set("Content-Length", csvData.length);
+ response.set("Access-Control-Expose-Headers", "Content-Disposition");
+ response.send(csvData);
+}
+
+/**
+ * Respond with JSON
+ * @param {Response} response the response object
+ */
+async function sendJSONResponse(response) {
+ response.json(response.locals);
+}
+
+/**
+ * Error-handling middleware
+ * @param {Error} error an error object
+ * @param {express.request} request the request object
+ * @param {express.response} response the response object
+ * @param {function} next function to proceed to the next middleware
+ */
+export function handleError(error, request, response, next) {
+ const { errors } = request.service.options;
+ debug("Error", error.name, error.message);
+ let message;
+
+ if (errors) {
+ Object.keys(errors).some((key) => {
+ if (error.message.match(key)) {
+ message = errors[key];
+ return true;
+ }
+ return false;
+ });
+ if (message) {
+ response.status(403).send({ code: 403, error: message });
+ return;
+ }
+ }
+
+ if (error.name === "UnauthorizedError") {
+ debug("Unauthorized");
+ response.status(401).send({ code: 401, error: error.message });
+ } else if (error.message === "EmptyResponse") {
+ debug("Not found");
+ response.status(404).send({ code: 404, error: error.message });
+ } else if (error.message === "UserNotActive") {
+ debug("User not active");
+ response.status(401).send({ code: 401, error: error.message });
+ } else if (error.message === "PermissionsError") {
+ debug("Insufficient permissions");
+ response.status(401).send({ code: 401, error: error.message });
+ } else {
+ debug("Unexpected error");
+ // debug(error);
+ response.status(403).send({
+ code: 403,
+ error: error.name || error.message,
+ message: error.message,
+ });
+ next();
+ }
+}