feat: adds vercel style guide in API package (#2861)

This commit is contained in:
Piyush Gupta
2024-07-09 18:09:56 +05:30
committed by GitHub
parent c563d781d3
commit 482a85565f
16 changed files with 126 additions and 75 deletions

View File

@@ -2,11 +2,11 @@ import { NextApiResponse } from "next";
export type ApiResponse = ApiSuccessResponse | ApiErrorResponse;
export interface ApiSuccessResponse<T = { [key: string]: any }> {
interface ApiSuccessResponse<T = { [key: string]: unknown }> {
data: T;
}
export interface ApiErrorResponse {
interface ApiErrorResponse {
code:
| "not_found"
| "gone"

View File

@@ -1,4 +1,7 @@
module.exports = {
extends: ["@formbricks/eslint-config/legacy-library.js"],
parser: "@typescript-eslint/parser",
extends: ["@formbricks/eslint-config/library.js"],
parserOptions: {
project: "tsconfig.json",
tsconfigRootDir: __dirname,
},
};

View File

@@ -1,7 +1,7 @@
import { TActionInput } from "@formbricks/types/actions";
import { Result } from "@formbricks/types/errorHandlers";
import { NetworkError } from "@formbricks/types/errors";
import { makeRequest } from "../../utils/makeRequest";
import { type TActionInput } from "@formbricks/types/actions";
import { type Result } from "@formbricks/types/errorHandlers";
import { type NetworkError } from "@formbricks/types/errors";
import { makeRequest } from "../../utils/make-request";
export class ActionAPI {
private apiHost: string;
@@ -12,7 +12,9 @@ export class ActionAPI {
this.environmentId = environmentId;
}
async create(actionInput: Omit<TActionInput, "environmentId">): Promise<Result<{}, NetworkError | Error>> {
async create(
actionInput: Omit<TActionInput, "environmentId">
): Promise<Result<object, NetworkError | Error>> {
return makeRequest(this.apiHost, `/api/v1/client/${this.environmentId}/actions`, "POST", actionInput);
}
}

View File

@@ -1,7 +1,7 @@
import { TAttributeUpdateInput } from "@formbricks/types/attributes";
import { Result } from "@formbricks/types/errorHandlers";
import { NetworkError } from "@formbricks/types/errors";
import { makeRequest } from "../../utils/makeRequest";
import { type TAttributeUpdateInput } from "@formbricks/types/attributes";
import { type Result } from "@formbricks/types/errorHandlers";
import { type NetworkError } from "@formbricks/types/errors";
import { makeRequest } from "../../utils/make-request";
export class AttributeAPI {
private apiHost: string;
@@ -16,7 +16,7 @@ export class AttributeAPI {
attributeUpdateInput: Omit<TAttributeUpdateInput, "environmentId">
): Promise<Result<{ changed: boolean; message: string }, NetworkError | Error>> {
// transform all attributes to string if attributes are present into a new attributes copy
const attributes: { [key: string]: string } = {};
const attributes: Record<string, string> = {};
for (const key in attributeUpdateInput.attributes) {
attributes[key] = String(attributeUpdateInput.attributes[key]);
}

View File

@@ -1,7 +1,7 @@
import { TDisplayCreateInput, TDisplayUpdateInput } from "@formbricks/types/displays";
import { Result } from "@formbricks/types/errorHandlers";
import { NetworkError } from "@formbricks/types/errors";
import { makeRequest } from "../../utils/makeRequest";
import { type TDisplayCreateInput, type TDisplayUpdateInput } from "@formbricks/types/displays";
import { type Result } from "@formbricks/types/errorHandlers";
import { type NetworkError } from "@formbricks/types/errors";
import { makeRequest } from "../../utils/make-request";
export class DisplayAPI {
private apiHost: string;
@@ -21,7 +21,7 @@ export class DisplayAPI {
async update(
displayId: string,
displayInput: Omit<TDisplayUpdateInput, "environmentId">
): Promise<Result<{}, NetworkError | Error>> {
): Promise<Result<object, NetworkError | Error>> {
return makeRequest(
this.apiHost,
`/api/v1/client/${this.environmentId}/displays/${displayId}`,

View File

@@ -1,4 +1,4 @@
import { ApiConfig } from "../../types";
import { type ApiConfig } from "../../types";
import { ActionAPI } from "./action";
import { AttributeAPI } from "./attribute";
import { DisplayAPI } from "./display";

View File

@@ -1,6 +1,6 @@
import { Result } from "@formbricks/types/errorHandlers";
import { NetworkError } from "@formbricks/types/errors";
import { makeRequest } from "../../utils/makeRequest";
import { type Result } from "@formbricks/types/errorHandlers";
import { type NetworkError } from "@formbricks/types/errors";
import { makeRequest } from "../../utils/make-request";
export class PeopleAPI {
private apiHost: string;
@@ -11,7 +11,7 @@ export class PeopleAPI {
this.environmentId = environmentId;
}
async create(userId: string): Promise<Result<{}, NetworkError | Error>> {
async create(userId: string): Promise<Result<{ userId: string }, NetworkError | Error>> {
return makeRequest(this.apiHost, `/api/v1/client/${this.environmentId}/people`, "POST", {
environmentId: this.environmentId,
userId,

View File

@@ -1,7 +1,7 @@
import { Result } from "@formbricks/types/errorHandlers";
import { NetworkError } from "@formbricks/types/errors";
import { TResponseInput, TResponseUpdateInput } from "@formbricks/types/responses";
import { makeRequest } from "../../utils/makeRequest";
import { type Result } from "@formbricks/types/errorHandlers";
import { type NetworkError } from "@formbricks/types/errors";
import { type TResponseInput, type TResponseUpdateInput } from "@formbricks/types/responses";
import { makeRequest } from "../../utils/make-request";
type TResponseUpdateInputWithResponseId = TResponseUpdateInput & { responseId: string };
@@ -26,7 +26,7 @@ export class ResponseAPI {
data,
ttc,
language,
}: TResponseUpdateInputWithResponseId): Promise<Result<{}, NetworkError | Error>> {
}: TResponseUpdateInputWithResponseId): Promise<Result<object, NetworkError | Error>> {
return makeRequest(this.apiHost, `/api/v1/client/${this.environmentId}/responses/${responseId}`, "PUT", {
finished,
data,

View File

@@ -1,4 +1,4 @@
import { TUploadFileConfig } from "@formbricks/types/storage";
import type { TUploadFileConfig, TUploadFileResponse } from "@formbricks/types/storage";
export class StorageAPI {
private apiHost: string;
@@ -33,12 +33,13 @@ export class StorageAPI {
});
if (!response.ok) {
throw new Error(`Upload failed with status: ${response.status}`);
throw new Error(`Upload failed with status: ${String(response.status)}`);
}
const json = await response.json();
const json = (await response.json()) as TUploadFileResponse;
const { data } = json;
const { signedUrl, fileUrl, signingData, presignedFields, updatedFileName } = data;
let requestHeaders: Record<string, string> = {};
@@ -76,7 +77,7 @@ export class StorageAPI {
if (!uploadResponse.ok) {
// if local storage is used, we'll use the json response:
if (signingData) {
const uploadJson = await uploadResponse.json();
const uploadJson = (await uploadResponse.json()) as { message: string };
const error = new Error(uploadJson.message);
error.name = "FileTooLargeError";
throw error;
@@ -84,13 +85,13 @@ export class StorageAPI {
// if s3 is used, we'll use the text response:
const errorText = await uploadResponse.text();
if (presignedFields && errorText && errorText.includes("EntityTooLarge")) {
if (presignedFields && errorText.includes("EntityTooLarge")) {
const error = new Error("File size exceeds the size limit for your plan");
error.name = "FileTooLargeError";
throw error;
}
throw new Error(`Upload failed with status: ${uploadResponse.status}`);
throw new Error(`Upload failed with status: ${String(uploadResponse.status)}`);
}
return fileUrl;

View File

@@ -1,5 +1,5 @@
import { Client } from "./api/client";
import { ApiConfig } from "./types/index";
import { type ApiConfig } from "./types/index";
export class FormbricksAPI {
client: Client;

View File

@@ -3,6 +3,22 @@ export interface ApiConfig {
apiHost: string;
}
export type ApiResponse<T> = {
export type ApiResponse = ApiSuccessResponse | ApiErrorResponse;
export interface ApiSuccessResponse<T = Record<string, unknown>> {
data: T;
};
}
export interface ApiErrorResponse {
code:
| "not_found"
| "gone"
| "bad_request"
| "internal_server_error"
| "unauthorized"
| "method_not_allowed"
| "not_authenticated"
| "forbidden";
message: string;
details: Record<string, string | string[] | number | number[] | boolean | boolean[]>;
}

View File

@@ -0,0 +1,40 @@
import { type Result, err, ok, wrapThrowsAsync } from "@formbricks/types/errorHandlers";
import { type NetworkError } from "@formbricks/types/errors";
import type { ApiErrorResponse, ApiResponse, ApiSuccessResponse } from "../types";
export const makeRequest = async <T>(
apiHost: string,
endpoint: string,
method: "GET" | "POST" | "PUT" | "DELETE",
data?: unknown
): Promise<Result<T, NetworkError | Error>> => {
const url = new URL(apiHost + endpoint);
const body = data ? JSON.stringify(data) : undefined;
const res = await wrapThrowsAsync(fetch)(url.toString(), {
method,
headers: {
"Content-Type": "application/json",
},
body,
});
if (!res.ok) return err(res.error);
const response = res.data;
const json = (await response.json()) as ApiResponse;
if (!response.ok) {
const errorResponse = json as ApiErrorResponse;
return err({
code: "network_error",
status: response.status,
message: errorResponse.message || "Something went wrong",
url,
...(Object.keys(errorResponse.details).length > 0 && { details: errorResponse.details }),
});
}
const successResponse = json as ApiSuccessResponse<T>;
return ok(successResponse.data);
};

View File

@@ -1,36 +0,0 @@
import { Result, err, ok, wrapThrows } from "@formbricks/types/errorHandlers";
import { NetworkError } from "@formbricks/types/errors";
export const makeRequest = async <T>(
apiHost: string,
endpoint: string,
method: "GET" | "POST" | "PUT" | "DELETE",
data?: any
): Promise<Result<T, NetworkError | Error>> => {
const url = new URL(apiHost + endpoint);
const body = JSON.stringify(data);
const res = wrapThrows(fetch)(url.toString(), {
method,
headers: {
"Content-Type": "application/json",
},
body,
});
if (res.ok === false) return err(res.error);
const response = await res.data;
const json = await response.json();
if (!response.ok) {
return err({
code: "network_error",
status: response.status,
message: json.message || "Something went wrong",
url,
...(json.details && { details: json.details }),
});
}
return ok(json.data as T);
};

View File

@@ -30,5 +30,5 @@ module.exports = {
},
},
},
ignorePatterns: ["node_modules/", "dist/"],
ignorePatterns: ["node_modules/", "dist/", "*.config.js"],
};

View File

@@ -0,0 +1,7 @@
module.exports = {
extends: ["@formbricks/eslint-config/library.js"],
parserOptions: {
project: "tsconfig.json",
tsconfigRootDir: __dirname,
},
};

View File

@@ -15,3 +15,21 @@ export const ZUploadFileConfig = z.object({
});
export type TUploadFileConfig = z.infer<typeof ZUploadFileConfig>;
const ZUploadFileResponse = z.object({
data: z.object({
signedUrl: z.string(),
fileUrl: z.string(),
signingData: z
.object({
signature: z.string(),
timestamp: z.number(),
uuid: z.string(),
})
.nullable(),
presignedFields: z.record(z.string()).optional(),
updatedFileName: z.string(),
}),
});
export type TUploadFileResponse = z.infer<typeof ZUploadFileResponse>;