added api call to fastapi backend

This commit is contained in:
Khalim Conn-Kowlessar 2023-07-18 11:57:37 +01:00
parent ac545b2b32
commit 0e2ffe97c3
3 changed files with 101 additions and 26 deletions

View file

@ -0,0 +1,62 @@
import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";
const PresignedUrlBodySchema = z.object({
portfolio_id: z.number(),
housing_type: z.enum(["Social", "Private"]),
goal: z.enum(["Increase EPC", "Reduce energy consumption"]),
goal_value: z.string(),
trigger_file_path: z.string(),
});
export async function POST(request: NextRequest) {
// For the moment, this api specifically handles uploads of csvs
const body = await request.json();
let validatedBody;
try {
validatedBody = PresignedUrlBodySchema.parse(body);
} catch (error) {
console.error("Invalid input: ", error);
return new NextResponse(JSON.stringify({ msg: "Invalid input" }), {
status: 400,
});
}
try {
// We'll trigger the plan build in our fastapi backend and then the user will just have to
// wait for the plan to be ready
const headers = {
"x-api-key": process.env.FASTAPI_API_KEY || "",
Authorization: `Bearer ${
request.cookies.get("next-auth.session-token")?.value
}`,
};
const response = await fetch(
`${process.env.FASTAPI_API_URL}/v1/plan/trigger`,
{
method: "POST",
headers: headers,
body: JSON.stringify(validatedBody),
}
);
if (!response.ok) {
throw new Error("API request failed");
}
const responseData = await response.json();
return new NextResponse(JSON.stringify(responseData), {
status: 200,
});
} catch (error) {
console.error(error);
return new NextResponse(JSON.stringify({ msg: "Internal server error" }), {
status: 500,
});
}
}

View file

@ -5,14 +5,9 @@ import { z } from "zod";
const PresignedUrlBodySchema = z.object({
userId: z.number(),
portfolioId: z.number(),
fileKey: z.string(),
});
function generateS3Key(userId: number, portfolioId: number, filename: string) {
const timestamp = new Date().toISOString().replace(/[:.-]/g, "");
const key = `${userId}/${portfolioId}/${filename}-${timestamp}.csv`;
return key;
}
export async function POST(request: NextRequest) {
// For the moment, this api specifically handles uploads of csvs
@ -36,12 +31,7 @@ export async function POST(request: NextRequest) {
secretAccessKey: process.env.PRESIGN_AWS_SECRET_KEY,
});
const { userId, portfolioId } = validatedBody;
const fileKey = generateS3Key(
userId,
portfolioId,
"portfolio_plan_properties"
);
const { userId, portfolioId, fileKey } = validatedBody;
// Presigned url is valid for 5 minutes
const preSignedUrl = await s3.getSignedUrl("putObject", {

View file

@ -11,14 +11,26 @@ import { useRouter } from "next/navigation";
import { useMutation } from "@tanstack/react-query";
import { useSession } from "next-auth/react";
function generateS3Key(userId: number, portfolioId: number, filename: string) {
const timestamp = new Date().toISOString().replace(/[:.-]/g, "");
const key = `${userId}/${portfolioId}/${filename}-${timestamp}.csv`;
return key;
}
async function generatePresignedUrl({
userId,
portfolioId,
fileKey,
}: {
userId: number;
portfolioId: number;
fileKey: string;
}) {
const body = JSON.stringify({ userId: userId, portfolioId: portfolioId });
const body = JSON.stringify({
userId: userId,
portfolioId: portfolioId,
fileKey: fileKey,
});
const presignedResponse = await fetch(`/api/upload/csv`, {
method: "POST",
@ -75,21 +87,33 @@ export const SubmitPlan = ({
const router = useRouter();
const session = useSession();
const userId = session.data?.user.dbId;
const fileKey = generateS3Key(
userId,
portfolioId,
"portfolio_plan_properties"
);
const { mutate: mutateUploadCsv, isLoading: isUploadLoading } = useMutation(
uploadCsvToS3,
{
onSuccess: (data) => {
const body = JSON.stringify({
// userId: session.data?.user.dbId,
portfolio_id: portfolioId,
housing_type: housingType,
goal: goal,
goal_value: goalValue,
trigger_file_path: fileKey,
});
// After the file has been uploaded, we can trigger the job to build the plan
// const response = fetch(`/api/plan/build`, {
// method: "POST",
// body: JSON.stringify({
// portfolioId: portfolioId,
// housingType: housingType,
// goal: goal,
// goalValue: goalValue,
// }),
// });
// return response;
const response = fetch(`/api/plan/trigger`, {
method: "POST",
body: body,
});
return response;
},
onError: (error) => {
// handle error
@ -123,7 +147,6 @@ export const SubmitPlan = ({
router.push("/");
return null;
}
const userId = session.data.user.dbId;
const handlePlanBuild = () => {
// The plan build is triggered by clicking submit which will:
@ -131,7 +154,7 @@ export const SubmitPlan = ({
// 2) Upload the csv to the pre-signed url
// 3) Trigger the job to build the plan
// 4) Redirect the user to some loading page - this could be the portfolio page itself and we just trigger a regresh with skeleton cards for the properties
mutate({ userId: userId, portfolioId: portfolioId });
mutate({ userId: userId, portfolioId: portfolioId, fileKey: fileKey });
// TODO: Make api call to backend service to trigger the plan build
// Probably need to pass in the file key to mutate (define it outside)
@ -523,7 +546,7 @@ export default function UploadCsvModal({
</button>
<SubmitPlan
buttonDisabled={buttonDisabled}
goal={goalValue}
goal={selectedGoal}
housingType={housingType}
goalValue={goalValue}
portfolioId={portfolioId}