fix: api errors (#3150)

Co-authored-by: Piyush Gupta <piyushguptaa2z123@gmail.com>
This commit is contained in:
Anshuman Pandey
2024-09-18 15:22:05 +05:30
committed by GitHub
parent 774c6f19a5
commit 10255aa102
13 changed files with 85 additions and 18 deletions
@@ -40,16 +40,16 @@ export const getEnvironmentState = async (
getProductByEnvironmentId(environmentId),
]);
if (!organization) {
throw new ResourceNotFoundError("organization", environmentId);
}
if (!environment) {
throw new ResourceNotFoundError("environment", environmentId);
}
if (!organization) {
throw new ResourceNotFoundError("organization", null);
}
if (!product) {
throw new ResourceNotFoundError("product", environmentId);
throw new ResourceNotFoundError("product", null);
}
if (product.config.channel && product.config.channel !== "app") {
@@ -3,6 +3,7 @@ import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextRequest } from "next/server";
import { environmentCache } from "@formbricks/lib/environment/cache";
import { ResourceNotFoundError } from "@formbricks/types/errors";
import { ZJsSyncInput } from "@formbricks/types/js";
export const OPTIONS = async (): Promise<Response> => {
@@ -49,6 +50,10 @@ export const GET = async (
"public, s-maxage=600, max-age=840, stale-while-revalidate=600, stale-if-error=600"
);
} catch (err) {
if (err instanceof ResourceNotFoundError) {
return responses.notFoundResponse(err.resourceType, err.resourceId);
}
console.error(err);
return responses.internalServerErrorResponse(err.message, true);
}
@@ -2,6 +2,7 @@ import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextRequest, userAgent } from "next/server";
import { personCache } from "@formbricks/lib/person/cache";
import { ResourceNotFoundError } from "@formbricks/types/errors";
import { ZJsPersonIdentifyInput } from "@formbricks/types/js";
import { getPersonState } from "./lib/personState";
@@ -53,6 +54,10 @@ export const GET = async (
"public, s-maxage=600, max-age=840, stale-while-revalidate=600, stale-if-error=600"
);
} catch (err) {
if (err instanceof ResourceNotFoundError) {
return responses.notFoundResponse(err.resourceType, err.resourceId);
}
console.error(err);
return responses.internalServerErrorResponse(err.message ?? "Unable to fetch person state", true);
}
@@ -3,6 +3,7 @@ import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextRequest } from "next/server";
import { getAttributesByUserId, updateAttributes } from "@formbricks/lib/attribute/service";
import { createPerson, getPersonByUserId } from "@formbricks/lib/person/service";
import { ResourceNotFoundError } from "@formbricks/types/errors";
import { ZJsPeopleUpdateAttributeInput } from "@formbricks/types/js";
export const OPTIONS = async () => {
@@ -81,6 +82,10 @@ export const PUT = async (
return responses.forbiddenResponse(err.message || "Forbidden", true, { ignore: true });
}
if (err instanceof ResourceNotFoundError) {
return responses.notFoundResponse(err.resourceType, err.resourceId, true);
}
return responses.internalServerErrorResponse("Something went wrong", true);
}
};
@@ -40,16 +40,16 @@ export const getEnvironmentState = async (
getProductByEnvironmentId(environmentId),
]);
if (!organization) {
throw new ResourceNotFoundError("organization", environmentId);
}
if (!environment) {
throw new ResourceNotFoundError("environment", environmentId);
}
if (!organization) {
throw new ResourceNotFoundError("organization", null);
}
if (!product) {
throw new ResourceNotFoundError("product", environmentId);
throw new ResourceNotFoundError("product", null);
}
if (product.config.channel && product.config.channel !== "website") {
@@ -2,6 +2,7 @@ import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextRequest } from "next/server";
import { environmentCache } from "@formbricks/lib/environment/cache";
import { ResourceNotFoundError } from "@formbricks/types/errors";
import { ZJsSyncInput } from "@formbricks/types/js";
import { getEnvironmentState } from "./lib/environmentState";
@@ -44,6 +45,11 @@ export const GET = async (
"public, s-maxage=600, max-age=840, stale-while-revalidate=600, stale-if-error=600"
);
} catch (err) {
if (err instanceof ResourceNotFoundError) {
return responses.notFoundResponse(err.resourceType, err.resourceId);
}
console.error(err);
return responses.internalServerErrorResponse(err.message ?? "Unable to complete response", true);
}
} catch (error) {
+1 -1
View File
@@ -106,7 +106,7 @@ const methodNotAllowedResponse = (
const notFoundResponse = (
resourceType: string,
resourceId: string,
resourceId: string | null,
cors: boolean = false,
cache: string = "private, no-store"
) => {
@@ -1,5 +1,4 @@
import { Prisma } from "@prisma/client";
import { selectDisplay } from "../../service";
import { TEnvironment } from "@formbricks/types/environment";
export const mockEnvironmentId = "clqkr5961000108jyfnjmbjhi";
export const mockSingleUseId = "qj57j3opsw8b5sxgea20fgcq";
@@ -50,3 +49,13 @@ export const mockDisplayUpdate = {
userId: mockUserId,
responseId: mockResponseId,
};
export const mockEnvironment: TEnvironment = {
id: mockId,
createdAt: new Date(),
updatedAt: new Date(),
type: "production",
productId: mockId,
appSetupCompleted: false,
websiteSetupCompleted: false,
};
+6 -1
View File
@@ -7,13 +7,14 @@ import {
mockDisplayUpdate,
mockDisplayWithPersonId,
mockDisplayWithResponseId,
mockEnvironment,
mockResponseId,
mockSurveyId,
} from "./__mocks__/data.mock";
import { Prisma } from "@prisma/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { testInputValidation } from "vitestSetup";
import { DatabaseError } from "@formbricks/types/errors";
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/errors";
import {
createDisplay,
deleteDisplayByResponseId,
@@ -94,6 +95,7 @@ describe("Tests for getDisplay", () => {
describe("Tests for createDisplay service", () => {
describe("Happy Path", () => {
it("Creates a new display when a userId exists", async () => {
prisma.environment.findUnique.mockResolvedValue(mockEnvironment);
prisma.display.create.mockResolvedValue(mockDisplayWithPersonId);
const display = await createDisplay(mockDisplayInputWithUserId);
@@ -113,6 +115,7 @@ describe("Tests for createDisplay service", () => {
it("Throws DatabaseError on PrismaClientKnownRequestError occurrence", async () => {
const mockErrorMessage = "Mock error message";
prisma.environment.findUnique.mockResolvedValue(mockEnvironment);
const errToThrow = new Prisma.PrismaClientKnownRequestError(mockErrorMessage, {
code: "P2002",
clientVersion: "0.0.1",
@@ -136,6 +139,7 @@ describe("Tests for updateDisplay Service", () => {
describe("Happy Path", () => {
it("Updates a display (responded)", async () => {
prisma.display.update.mockResolvedValue(mockDisplayWithResponseId);
prisma.environment.findUnique.mockResolvedValue(mockEnvironment);
const display = await updateDisplay(mockDisplay.id, mockDisplayUpdate);
expect(display).toEqual(mockDisplayWithResponseId);
@@ -146,6 +150,7 @@ describe("Tests for updateDisplay Service", () => {
testInputValidation(updateDisplay, "123", "123");
it("Throws DatabaseError on PrismaClientKnownRequestError", async () => {
prisma.environment.findUnique.mockResolvedValue(mockEnvironment);
const mockErrorMessage = "Mock error message";
const errToThrow = new Prisma.PrismaClientKnownRequestError(mockErrorMessage, {
code: "P2002",
+11 -1
View File
@@ -4,7 +4,7 @@ import { cache as reactCache } from "react";
import { prisma } from "@formbricks/database";
import { ZOptionalNumber, ZString } from "@formbricks/types/common";
import { ZId } from "@formbricks/types/common";
import { DatabaseError } from "@formbricks/types/errors";
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/errors";
import { TPerson } from "@formbricks/types/people";
import { cache } from "../cache";
import { ITEMS_PER_PAGE } from "../constants";
@@ -218,6 +218,16 @@ export const getPersonByUserId = reactCache(
async () => {
validateInputs([environmentId, ZId], [userId, ZString]);
const environment = await prisma.environment.findUnique({
where: {
id: environmentId,
},
});
if (!environment) {
throw new ResourceNotFoundError("environment", environmentId);
}
// check if userId exists as a column
const personWithUserId = await prisma.person.findFirst({
where: {
+14
View File
@@ -1,3 +1,7 @@
import { TEnvironment } from "@formbricks/types/environment";
export const mockId = "ars2tjk8hsi8oqk1uac00mo8";
export const constantsForTests = {
uuid: "123e4567-e89b-12d3-a456-426614174000",
browser: "Chrome",
@@ -6,3 +10,13 @@ export const constantsForTests = {
text: "Abc12345",
fullName: "Pavitr Prabhakar",
};
export const mockEnvironment: TEnvironment = {
id: mockId,
createdAt: new Date(),
updatedAt: new Date(),
type: "production",
productId: mockId,
appSetupCompleted: false,
websiteSetupCompleted: false,
};
+4 -1
View File
@@ -43,7 +43,7 @@ import {
updateResponse,
} from "../service";
import { buildWhereClause } from "../utils";
import { constantsForTests } from "./constants";
import { constantsForTests, mockEnvironment } from "./constants";
// vitest.mock("../../organization/service", async (methods) => {
// return {
@@ -205,6 +205,7 @@ describe("Tests for createResponse service", () => {
describe("Happy Path", () => {
it("Creates a response linked to an existing user", async () => {
prisma.attribute.findMany.mockResolvedValue([]);
prisma.environment.findUnique.mockResolvedValue(mockEnvironment);
const response = await createResponse(mockResponseInputWithUserId);
expect(response).toEqual(expectedResponseWithPerson);
});
@@ -216,6 +217,7 @@ describe("Tests for createResponse service", () => {
it("Creates a new person and response when the person does not exist", async () => {
prisma.person.findFirst.mockResolvedValue(null);
prisma.environment.findUnique.mockResolvedValue(mockEnvironment);
prisma.person.create.mockResolvedValue(mockPerson);
prisma.attribute.findMany.mockResolvedValue([]);
@@ -246,6 +248,7 @@ describe("Tests for createResponse service", () => {
clientVersion: "0.0.1",
});
prisma.environment.findUnique.mockResolvedValue(mockEnvironment);
prisma.response.create.mockRejectedValue(errToThrow);
prisma.attribute.findMany.mockResolvedValue([]);
+7 -2
View File
@@ -2,9 +2,14 @@ import { z } from "zod";
class ResourceNotFoundError extends Error {
statusCode = 404;
constructor(resource: string, id: string) {
super(`${resource} with ID ${id} not found`);
resourceId: string | null;
resourceType: string;
constructor(resource: string, id: string | null) {
super(id ? `${resource} with ID ${id} not found` : `${resource} not found`);
this.name = "ResourceNotFoundError";
this.resourceType = resource;
this.resourceId = id;
}
}