Feat: Resolver
This commit is contained in:
parent
3b458298e0
commit
e86e5d3bbd
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,4 +3,4 @@ node_modules
|
|||||||
.vercel
|
.vercel
|
||||||
AGENTS.md
|
AGENTS.md
|
||||||
CLAUDE.md
|
CLAUDE.md
|
||||||
.next
|
.next
|
||||||
@ -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,11 +150,10 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return apolloHandler(req, res);
|
return apolloHandler(req, res);
|
||||||
};
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user