120 lines
3.9 KiB
TypeScript
120 lines
3.9 KiB
TypeScript
import { ApolloServer } from "@apollo/server";
|
|
import { startStandaloneServer } from "@apollo/server/standalone";
|
|
import { createServer } from "http";
|
|
import { typeDefs } from "./schema.js";
|
|
import { resolvers } from "./resolvers.js";
|
|
import { queryComplexityPlugin } from "./plugins/queryComplexity.js";
|
|
import { createResponseCachePlugin } from "./plugins/responseCache.js";
|
|
import {
|
|
monitoringPlugin,
|
|
queryComplexityMonitoringPlugin,
|
|
} from "./plugins/monitoring.js";
|
|
import { createContext, type GraphQLContext } from "./utils/dataloaders.js";
|
|
import { logger } from "./monitoring/logger.js";
|
|
import { getMetrics } from "./monitoring/metrics.js";
|
|
import { extractTokenFromHeader } from "./auth/jwt.js";
|
|
import { userService } from "./auth/userService.js";
|
|
|
|
const PORT = process.env.PORT ? parseInt(process.env.PORT) : 4000;
|
|
const METRICS_PORT = process.env.METRICS_PORT
|
|
? parseInt(process.env.METRICS_PORT)
|
|
: 9090;
|
|
|
|
// Konfiguration aus Environment Variables
|
|
const MAX_QUERY_COMPLEXITY = process.env.MAX_QUERY_COMPLEXITY
|
|
? parseInt(process.env.MAX_QUERY_COMPLEXITY)
|
|
: 1000;
|
|
|
|
/**
|
|
* Startet einen separaten HTTP-Server für Metrics (Prometheus)
|
|
*/
|
|
function startMetricsServer() {
|
|
const server = createServer(async (req, res) => {
|
|
if (req.url === "/metrics" && req.method === "GET") {
|
|
try {
|
|
const metrics = await getMetrics();
|
|
res.writeHead(200, { "Content-Type": "text/plain; version=0.0.4" });
|
|
res.end(metrics);
|
|
} catch (error) {
|
|
logger.error("Failed to get metrics", { error });
|
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
res.end(JSON.stringify({ error: "Failed to get metrics" }));
|
|
}
|
|
} else if (req.url === "/health" && req.method === "GET") {
|
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
res.end(JSON.stringify({ status: "ok", service: "graphql-middlelayer" }));
|
|
} else {
|
|
res.writeHead(404, { "Content-Type": "application/json" });
|
|
res.end(JSON.stringify({ error: "Not found" }));
|
|
}
|
|
});
|
|
|
|
server.listen(METRICS_PORT, () => {
|
|
logger.info(
|
|
`📊 Metrics Server läuft auf: http://localhost:${METRICS_PORT}/metrics`
|
|
);
|
|
logger.info(
|
|
`❤️ Health Check verfügbar unter: http://localhost:${METRICS_PORT}/health`
|
|
);
|
|
});
|
|
|
|
return server;
|
|
}
|
|
|
|
async function startServer() {
|
|
const server = new ApolloServer<GraphQLContext>({
|
|
typeDefs,
|
|
resolvers,
|
|
plugins: [
|
|
// Monitoring (muss zuerst sein für vollständiges Tracking)
|
|
monitoringPlugin(),
|
|
queryComplexityMonitoringPlugin(),
|
|
// Query Complexity Limit
|
|
queryComplexityPlugin({
|
|
maxComplexity: MAX_QUERY_COMPLEXITY,
|
|
defaultComplexity: 1,
|
|
}),
|
|
// Response Caching
|
|
createResponseCachePlugin(),
|
|
],
|
|
});
|
|
|
|
const { url } = await startStandaloneServer(server, {
|
|
listen: { port: PORT },
|
|
context: async ({ req }) => {
|
|
// Extrahiere User aus Authorization Header
|
|
let user = null;
|
|
const authHeader = req.headers.authorization;
|
|
const token = extractTokenFromHeader(authHeader || null);
|
|
|
|
if (token) {
|
|
try {
|
|
user = await userService.getUserFromToken(token);
|
|
} catch (error) {
|
|
logger.warn("Token verification failed", { error });
|
|
}
|
|
}
|
|
|
|
// Erstelle Context mit Dataloadern und User
|
|
return createContext(user);
|
|
},
|
|
});
|
|
|
|
// Starte Metrics Server
|
|
startMetricsServer();
|
|
|
|
logger.info(`🚀 GraphQL Middlelayer läuft auf: ${url}`);
|
|
logger.info(`📊 GraphQL Playground verfügbar unter: ${url}`);
|
|
logger.info(`⚡ Query Complexity Limit: ${MAX_QUERY_COMPLEXITY}`);
|
|
logger.info(`💾 Response Caching: Aktiviert`);
|
|
logger.info(`🔄 Dataloader: Aktiviert`);
|
|
logger.info(
|
|
`📈 Monitoring: Aktiviert (Structured Logging, Prometheus, Tracing)`
|
|
);
|
|
}
|
|
|
|
startServer().catch((error) => {
|
|
logger.error("Fehler beim Starten des Servers", { error });
|
|
process.exit(1);
|
|
});
|