Feat: Resolver

This commit is contained in:
MelvynFaith 2026-09-16 16:51:36 +07:00
parent 3b458298e0
commit e86e5d3bbd
2 changed files with 47 additions and 11 deletions

View File

@ -8,10 +8,10 @@ const pool = new Pool({
ssl: { ssl: {
rejectUnauthorized: false, rejectUnauthorized: false,
}, },
max: 1, // Batasi 1 koneksi per instance serverless max: 1,
}); });
// 2. Definisi Schema GraphQL (typeDefs) // 2. Definisi Schema GraphQL
const typeDefs = `#graphql const typeDefs = `#graphql
type Category { type Category {
id: ID! id: ID!
@ -37,7 +37,26 @@ const typeDefs = `#graphql
} }
`; `;
// 3. Definisi Resolver (Query + Nested Resolvers) // 3. Plugin Apollo untuk menyuntikkan log counter ke response extensions
const metricsPlugin = {
async requestDidStart() {
return {
async willSendResponse({ response, contextValue }) {
if (response.body.kind === 'single') {
response.body.singleResult.extensions = {
...response.body.singleResult.extensions,
nPlusOneMetrics: {
totalCalls: contextValue.metrics.categoryProductsCalls,
resolverLogs: contextValue.metrics.callLogs,
},
};
}
},
};
},
};
// 4. Definisi Resolver
const resolvers = { const resolvers = {
Query: { Query: {
categories: async () => { categories: async () => {
@ -65,7 +84,16 @@ const resolvers = {
// Resolver Relasi Category -> Products (One-to-Many) // Resolver Relasi Category -> Products (One-to-Many)
Category: { Category: {
products: async (parent) => { products: async (parent, _, contextValue) => {
// Increment counter di context request saat ini
contextValue.metrics.categoryProductsCalls += 1;
const currentCall = contextValue.metrics.categoryProductsCalls;
// Simpan log urutan pemanggilan ke array context
contextValue.metrics.callLogs.push(
`[resolver counter] Category.products dipanggil ${currentCall} kali (category_id=${parent.id})`
);
const result = await pool.query( const result = await pool.query(
'SELECT id, title, price::float, category_id, created_by FROM products WHERE category_id = $1 ORDER BY id ASC', 'SELECT id, title, price::float, category_id, created_by FROM products WHERE category_id = $1 ORDER BY id ASC',
[parent.id] [parent.id]
@ -84,17 +112,26 @@ const resolvers = {
}, },
}; };
// 4. Inisialisasi Apollo Server // 5. Inisialisasi Apollo Server dengan Plugin
const server = new ApolloServer({ const server = new ApolloServer({
typeDefs, typeDefs,
resolvers, resolvers,
introspection: true, introspection: true,
csrfPrevention: false, // Mematikan proteksi CSRF agar request dari browser Sandbox tidak dicegat csrfPrevention: false,
plugins: [metricsPlugin],
}); });
const apolloHandler = startServerAndCreateNextHandler(server); // 6. Inisialisasi Handler dengan Context Per-Request
const apolloHandler = startServerAndCreateNextHandler(server, {
context: async () => ({
metrics: {
categoryProductsCalls: 0,
callLogs: [],
},
}),
});
// 5. Handler CORS untuk Apollo Studio dan Embedded Sandbox // 7. Handler CORS dan Serverless Entrypoint
module.exports = async function handler(req, res) { module.exports = async function handler(req, res) {
const allowedOrigins = new Set([ const allowedOrigins = new Set([
'https://studio.apollographql.com', 'https://studio.apollographql.com',
@ -113,7 +150,6 @@ module.exports = async function handler(req, res) {
'Content-Type, Authorization, apollo-require-preflight, x-apollo-operation-name' 'Content-Type, Authorization, apollo-require-preflight, x-apollo-operation-name'
); );
// Respons langsung untuk preflight OPTIONS request
if (req.method === 'OPTIONS') { if (req.method === 'OPTIONS') {
res.status(200).end(); res.status(200).end();
return; return;