Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 50 additions & 125 deletions app/routes/api.boxes.$deviceId.$sensorId.ts
Original file line number Diff line number Diff line change
@@ -1,128 +1,53 @@
import { type ActionFunction, type ActionFunctionArgs } from "react-router";
import { postSingleMeasurement } from "~/lib/measurement-service.server";
import { type ActionFunction, type ActionFunctionArgs } from 'react-router'
import { postSingleMeasurement } from '~/lib/measurement-service.server'
import { StandardResponse } from '~/utils/response-utils'

export const action: ActionFunction = async ({
request,
params,
request,
params,
}: ActionFunctionArgs): Promise<Response> => {
try {
const { deviceId, sensorId } = params;

if (!deviceId || !sensorId) {
return Response.json(
{
code: "Bad Request",
message: "Invalid device id or sensor id specified",
},
{
status: 400,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
},
);
}

const authorization = request.headers.get("authorization");
const contentType = request.headers.get("content-type") || "";

if (!contentType.includes("application/json")) {
return Response.json(
{
code: "Unsupported Media Type",
message: "Content-Type must be application/json",
},
{
status: 415,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
},
);
}

const body = await request.json();

await postSingleMeasurement(deviceId, sensorId, body, authorization);

return new Response("Measurement saved in box", {
status: 201,
headers: {
"Content-Type": "text/plain; charset=utf-8",
},
});
} catch (err: any) {
if (err.name === "UnauthorizedError") {
return Response.json(
{
code: "Unauthorized",
message: err.message,
},
{
status: 401,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
},
);
}

if (err.name === "NotFoundError") {
return Response.json(
{
code: "Not Found",
message: err.message,
},
{
status: 404,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
},
);
}

if (err.name === "UnprocessableEntityError" || err.type === "UnprocessableEntityError") {
return Response.json(
{
code: "Unprocessable Entity",
message: err.message,
},
{
status: 422,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
},
);
}

if (err.name === "ModelError" && err.type === "UnprocessableEntityError") {
return Response.json(
{
code: "Unprocessable Entity",
message: err.message,
},
{
status: 422,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
},
);
}

return Response.json(
{
code: "Internal Server Error",
message: err.message || "An unexpected error occurred",
},
{
status: 500,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
},
);
}
};
try {
const { deviceId, sensorId } = params

if (!deviceId || !sensorId)
return StandardResponse.badRequest(
'Invalid device id or sensor id specified',
)

const authorization = request.headers.get('authorization')
const contentType = request.headers.get('content-type') || ''

if (!contentType.includes('application/json'))
return StandardResponse.unsupportedMediaType(
'Content-Type must be application/json',
)

const body = await request.json()

await postSingleMeasurement(deviceId, sensorId, body, authorization)

return new Response('Measurement saved in box', {
status: 201,
headers: {
'Content-Type': 'text/plain; charset=utf-8',
},
})
} catch (err: any) {
if (err.name === 'UnauthorizedError')
return StandardResponse.unauthorized(err.message)

if (err.name === 'NotFoundError')
return StandardResponse.notFound(err.message)

if (
err.name === 'UnprocessableEntityError' ||
err.type === 'UnprocessableEntityError' ||
(err.name === 'ModelError' && err.type === 'UnprocessableEntityError')
)
return StandardResponse.unprocessableContent(err.message)

return StandardResponse.internalServerError(
err.message || 'An unexpected error occurred',
)
}
}
12 changes: 6 additions & 6 deletions app/routes/api.boxes.$deviceId.data.$sensorId.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { getMeasurements } from "~/models/sensor.server";
import { type Measurement } from "~/schema";
import { convertToCsv } from "~/utils/csv";
import { parseDateParam, parseEnumParam } from "~/utils/param-utils";
import { badRequest, internalServerError, notFound } from "~/utils/response-utils";
import { StandardResponse } from "~/utils/response-utils";

/**
* @openapi
Expand Down Expand Up @@ -152,7 +152,7 @@ export const loader: LoaderFunction = async ({

let meas: Measurement[] | TransformedMeasurement[] = await getMeasurements(sensorId, fromDate.toISOString(), toDate.toISOString());
if (meas == null)
return notFound("Device not found.");
return StandardResponse.notFound("Device not found.");

if (outliers)
meas = transformOutliers(meas, outlierWindow, outliers == "replace");
Expand All @@ -177,7 +177,7 @@ export const loader: LoaderFunction = async ({

} catch (err) {
console.warn(err);
return internalServerError();
return StandardResponse.internalServerError();
}
};

Expand All @@ -196,10 +196,10 @@ function collectParameters(request: Request, params: Params<string>):
// deviceId is there for legacy reasons
const deviceId = params.deviceId;
if (deviceId === undefined)
return badRequest("Invalid device id specified");
return StandardResponse.badRequest("Invalid device id specified");
const sensorId = params.sensorId;
if (sensorId === undefined)
return badRequest("Invalid sensor id specified");
return StandardResponse.badRequest("Invalid sensor id specified");

const url = new URL(request.url);

Expand All @@ -211,7 +211,7 @@ function collectParameters(request: Request, params: Params<string>):
let outlierWindow: number = 15;
if (outlierWindowParam !== null) {
if (Number.isNaN(outlierWindowParam) || Number(outlierWindowParam) < 1 || Number(outlierWindowParam) > 50)
return badRequest("Illegal value for parameter outlier-window. Allowed values: numbers between 1 and 50");
return StandardResponse.badRequest("Illegal value for parameter outlier-window. Allowed values: numbers between 1 and 50");
outlierWindow = Number(outlierWindowParam);
}

Expand Down
73 changes: 10 additions & 63 deletions app/routes/api.boxes.$deviceId.data.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,15 @@
import { type ActionFunction, type ActionFunctionArgs } from "react-router";
import { postNewMeasurements } from "~/lib/measurement-service.server";
import { StandardResponse } from "~/utils/response-utils";

export const action: ActionFunction = async ({
request,
params,
}: ActionFunctionArgs): Promise<Response> => {
try {
const deviceId = params.deviceId;
if (deviceId === undefined) {
return Response.json(
{
code: "Bad Request",
message: "Invalid device id specified",
},
{
status: 400,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
},
);
}
if (deviceId === undefined)
return StandardResponse.badRequest("Invalid device id specified");

const searchParams = new URL(request.url).searchParams;
const luftdaten = searchParams.get("luftdaten") !== null;
Expand Down Expand Up @@ -55,57 +44,15 @@ export const action: ActionFunction = async ({
});
} catch (err: any) {
// Handle different error types
if (err.name === "UnauthorizedError") {
return Response.json(
{
code: "Unauthorized",
message: err.message,
},
{
status: 401,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
},
);
}
if (err.name === "UnauthorizedError")
return StandardResponse.unauthorized(err.message);

if (err.name === "ModelError" && err.type === "UnprocessableEntityError") {
return Response.json(
{
code: "UnprocessableEntity",
message: err.message,
},
{ status: 422 }
);
}
if (err.name === "ModelError" && err.type === "UnprocessableEntityError")
return StandardResponse.unprocessableContent(err.message);

if (err.name === "UnsupportedMediaTypeError") {
return Response.json(
{
code: "Unsupported Media Type",
message: err.message,
},
{
status: 415,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
},
);
}
if (err.name === "UnsupportedMediaTypeError")
return StandardResponse.unsupportedMediaType(err.message);

return Response.json(
{
code: "Internal Server Error",
message: err.message || "An unexpected error occurred",
},
{
status: 500,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
},
);
return StandardResponse.internalServerError(err.message || "An unexpected error occurred");
}
};
8 changes: 4 additions & 4 deletions app/routes/api.boxes.$deviceId.locations.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { type Params, type LoaderFunction, type LoaderFunctionArgs } from "react-router";
import { getLocations } from "~/models/device.server";
import { parseDateParam, parseEnumParam } from "~/utils/param-utils";
import { badRequest, internalServerError, notFound } from "~/utils/response-utils";
import { StandardResponse } from "~/utils/response-utils";

/**
* @openapi
Expand Down Expand Up @@ -104,7 +104,7 @@ export const loader: LoaderFunction = async ({

const locations = await getLocations({ id: deviceId}, fromDate, toDate);
if (!locations)
return notFound("Device not found");
return StandardResponse.notFound("Device not found");

const jsonLocations = locations.map((location) => {
return {
Expand Down Expand Up @@ -140,7 +140,7 @@ export const loader: LoaderFunction = async ({

} catch (err) {
console.warn(err);
return internalServerError();
return StandardResponse.internalServerError();
}
};

Expand All @@ -153,7 +153,7 @@ function collectParameters(request: Request, params: Params<string>):
} {
const deviceId = params.deviceId;
if (deviceId === undefined)
return badRequest("Invalid device id specified");
return StandardResponse.badRequest("Invalid device id specified");

const url = new URL(request.url);

Expand Down
Loading
Loading