Files
no-twitter-bot-stats/src/app/api/graphql/route.ts
Lucid 8ae9946ef9
All checks were successful
Main / build-and-push-docker-image (20.x) (push) Successful in 8m44s
secure api
2025-12-06 20:29:16 -05:00

75 lines
2.0 KiB
TypeScript

/* eslint-disable react-hooks/rules-of-hooks */
import { createYoga, Plugin, createSchema } from "graphql-yoga";
import { EnvelopArmor } from "@escape.tech/graphql-armor";
import resolvers from "@/graphql/resolvers";
import typeDefs from "@/graphql/types";
interface NextContext {
params: Promise<Record<string, string>>;
}
const environment = process.env.NODE_ENV || "development";
const isValidApiKey = (apiKey: string): boolean => {
const envApiKey = process.env.NEXT_PUBLIC_API_TOKEN;
return apiKey === envApiKey;
};
function useApiKey(): Plugin {
return {
async onRequest({ request, endResponse, fetchAPI }) {
const apiKey = await request.headers.get("x-api-key");
if (environment === "production") {
if (!apiKey || apiKey == null) {
endResponse(
new fetchAPI.Response(
JSON.stringify({
message: "No API Key provided"
}),
{ status: 401, headers: { "Content-Type": "application/json" } }
)
);
}
if (apiKey !== null && !(await isValidApiKey(apiKey))) {
endResponse(
new fetchAPI.Response(
JSON.stringify({
message: "Invalid API Key"
}),
{ status: 403, headers: { "Content-Type": "application/json" } }
)
);
}
}
}
};
}
const armor = new EnvelopArmor();
const protection = armor.protect();
const { handleRequest } = createYoga<NextContext>({
schema: createSchema({
typeDefs: typeDefs,
resolvers: resolvers
}),
// While using Next.js file convention for routing, we need to configure Yoga to use the correct endpoint
graphqlEndpoint: "/api/graphql",
// Yoga needs to know how to create a valid Next response
fetchAPI: { Response },
plugins: [...protection.plugins, useApiKey()],
graphiql: environment !== "production" ? true : false
});
export {
handleRequest as GET,
handleRequest as POST,
handleRequest as OPTIONS
};