TASK22102: slice5 larger file handler contract cleanup
This commit is contained in:
@@ -1437,3 +1437,38 @@ Validation:
|
||||
Follow-ups:
|
||||
|
||||
- Continue next larger slice on remaining non-proxy file handlers still returning raw error payloads.
|
||||
|
||||
---
|
||||
|
||||
### CL-039: TASK22102 API contract consistency — Slice 5 (larger file-handler batch)
|
||||
|
||||
date: 2026-03-17
|
||||
author: Cline
|
||||
scope: `pages/api/file/{uploadsinglefile,setupcontainer,createrepcompletemessage_api,editRepJson}.js`
|
||||
type: change
|
||||
rationale: Continue with a larger efficiency-focused slice by migrating remaining high-signal file handlers that still returned raw/empty error responses.
|
||||
impact: Improves response-contract consistency and avoids leaking raw error payloads in selected file handlers while preserving success behavior and endpoint semantics.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
|
||||
- Migrated additional file handlers to helper-based responses:
|
||||
- `uploadsinglefile`
|
||||
- `setupcontainer`
|
||||
- `createrepcompletemessage_api`
|
||||
- `editRepJson`
|
||||
- Replaced direct `res.status(...).json(...)` error branches (including raw `error` payload and empty responses) with structured:
|
||||
- `respondError(...)`
|
||||
- `respondSuccess(...)`
|
||||
- Preserved existing success semantics:
|
||||
- `uploadsinglefile` still returns uploaded result + `invalidFiles`
|
||||
- `setupcontainer` still returns `{ data: "success", output }`
|
||||
- `editRepJson` still returns success message on completion
|
||||
|
||||
Validation:
|
||||
|
||||
- `npx next lint --file pages/api/file/uploadsinglefile.js --file pages/api/file/setupcontainer.js --file pages/api/file/createrepcompletemessage_api.js --file pages/api/file/editRepJson.js` -> pass (no warnings/errors)
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Continue next larger slice on remaining file handlers with empty 400 responses to complete contract-consistency rollout.
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
} from "../../../actions/azurestorage";
|
||||
import { hashAPIPath } from "../../../actions/core/hash";
|
||||
import { consoleLogger } from "../../../actions/core/logger";
|
||||
import { respondError, respondSuccess } from "../middleware/apiResponse";
|
||||
|
||||
import nextConnect from "next-connect";
|
||||
import middleware from "../middleware/middleware";
|
||||
@@ -27,7 +28,11 @@ ApiProxy.get(async (req, res) => {
|
||||
typeof checkHash === "undefined" ||
|
||||
checkHash.length === 0
|
||||
) {
|
||||
return res.status(400).json();
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "MISSING_REQUIRED_QUERY",
|
||||
message: "container, tempcaseref, repid and hash are required"
|
||||
});
|
||||
}
|
||||
|
||||
var checkquerypath =
|
||||
@@ -39,16 +44,24 @@ ApiProxy.get(async (req, res) => {
|
||||
filename;
|
||||
|
||||
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
|
||||
return res.status(400).json();
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "INVALID_HASH",
|
||||
message: "Invalid hash"
|
||||
});
|
||||
}
|
||||
|
||||
await createRepCompleteMessage(containerName, tempCaseRef, filename)
|
||||
.then((data) => {
|
||||
return res.status(200).json(data);
|
||||
return respondSuccess(res, data);
|
||||
})
|
||||
.catch((error) => {
|
||||
consoleLogger(error);
|
||||
return res.status(400).json();
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "CREATE_REP_COMPLETE_MESSAGE_FAILED",
|
||||
message: "Failed to create representation complete message"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
import { DefaultAzureCredential } from "@azure/identity";
|
||||
import { BlobServiceClient } from "@azure/storage-blob";
|
||||
import { consoleLogger } from "../../../actions/core/logger";
|
||||
import { respondError, respondSuccess } from "../middleware/apiResponse";
|
||||
|
||||
export default async function handler(req, res) {
|
||||
if (req.method !== "POST") {
|
||||
res.status(405).json({ error: "Method not allowed" });
|
||||
return;
|
||||
return respondError(res, {
|
||||
status: 405,
|
||||
code: "METHOD_NOT_ALLOWED",
|
||||
message: "Method not allowed"
|
||||
});
|
||||
}
|
||||
|
||||
const { container, blobName } = req.body;
|
||||
|
||||
if (!container || !blobName) {
|
||||
res.status(400).json({ error: "Missing container or blobName" });
|
||||
return;
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "MISSING_REQUIRED_BODY",
|
||||
message: "Missing container or blobName"
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -60,10 +68,16 @@ export default async function handler(req, res) {
|
||||
const withTags = await blockBlobClient.setTags(tags);
|
||||
const withMeta = await blockBlobClient.setMetadata(tags);
|
||||
|
||||
res.status(200).json({ message: "repComplete removed successfully" });
|
||||
return respondSuccess(res, {
|
||||
message: "repComplete removed successfully"
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error editing rep.json:", error);
|
||||
res.status(500).json({ error: "Failed to edit rep.json" });
|
||||
consoleLogger(error);
|
||||
return respondError(res, {
|
||||
status: 500,
|
||||
code: "EDIT_REP_JSON_FAILED",
|
||||
message: "Failed to edit rep.json"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
} from "../../../actions/azurestorage";
|
||||
import { hashAPIPath } from "../../../actions/core/hash";
|
||||
import { consoleLogger } from "../../../actions/core/logger";
|
||||
import { respondError, respondSuccess } from "../middleware/apiResponse";
|
||||
|
||||
import middleware from "../middleware/middleware";
|
||||
import nextConnect from "next-connect";
|
||||
@@ -24,22 +25,34 @@ ApiProxy.get(async (req, res) => {
|
||||
typeof checkHash === "undefined" ||
|
||||
checkHash.length === 0
|
||||
) {
|
||||
return res.status(400).json();
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "MISSING_REQUIRED_QUERY",
|
||||
message: "ident and hash are required"
|
||||
});
|
||||
}
|
||||
|
||||
var checkquerypath = "/api/file/setupcontainer?ident=" + containerName;
|
||||
|
||||
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
|
||||
return res.status(400).json();
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "INVALID_HASH",
|
||||
message: "Invalid hash"
|
||||
});
|
||||
}
|
||||
|
||||
await createContainer(containerName)
|
||||
.then((data) => {
|
||||
return res.status(200).json({ data: "success", output: data });
|
||||
return respondSuccess(res, { data: "success", output: data });
|
||||
})
|
||||
.catch((error) => {
|
||||
consoleLogger(error);
|
||||
res.status(400).json(error);
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "SETUP_CONTAINER_FAILED",
|
||||
message: "Failed to setup container"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import nextConnect from "next-connect";
|
||||
import middleware from "../middleware/middleware";
|
||||
import { consoleLogger } from "../../../actions/core/logger";
|
||||
import { hashAPIPath } from "../../../actions/core/hash";
|
||||
import { respondError, respondSuccess } from "../middleware/apiResponse";
|
||||
import { fileTypeFromBuffer } from "file-type";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
@@ -39,13 +40,21 @@ ApiProxy.post(async (req, res) => {
|
||||
var checkHash = req.query.hash;
|
||||
|
||||
if (typeof checkHash === "undefined" || checkHash.length === 0) {
|
||||
return res.status(400).json();
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "HASH_REQUIRED",
|
||||
message: "hash is required"
|
||||
});
|
||||
}
|
||||
|
||||
var checkquerypath = "/api/file/uploadsinglefile";
|
||||
|
||||
if (hashAPIPath(checkquerypath) != "?hash=" + checkHash) {
|
||||
return res.status(400).json();
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "INVALID_HASH",
|
||||
message: "Invalid hash"
|
||||
});
|
||||
}
|
||||
|
||||
const containerID = req.body?.containerID?.[0];
|
||||
@@ -57,7 +66,11 @@ ApiProxy.post(async (req, res) => {
|
||||
typeof casefolderID === "undefined" ||
|
||||
casefolderID.length === 0
|
||||
) {
|
||||
return res.status(400).json();
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "MISSING_REQUIRED_BODY",
|
||||
message: "containerID and casefolderID are required"
|
||||
});
|
||||
}
|
||||
|
||||
const uploadedFiles = req.files || {};
|
||||
@@ -126,10 +139,14 @@ ApiProxy.post(async (req, res) => {
|
||||
containerID,
|
||||
casefolderID
|
||||
);
|
||||
return res.status(200).json({ data, invalidFiles });
|
||||
return respondSuccess(res, { data, invalidFiles });
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
return res.status(500).json({ error: "Failed to upload files" });
|
||||
return respondError(res, {
|
||||
status: 500,
|
||||
code: "UPLOAD_SINGLE_FILE_FAILED",
|
||||
message: "Failed to upload files"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user