53 Logging dan Error Handling di GraphQL Server
Salah satu tantangan dalam membangun API modern adalah memastikan observabilitas dan robustnya penanganan error. Ketika kita membangun server GraphQL, baik dengan Node.js, Python, maupun bahasa lain, logging dan error handling yang baik bukan sekadar pelengkap, tapi bagian fundamental yang tidak boleh diabaikan. Dalam artikel ini, kita akan eksplorasi secara mendalam tentang logging dan error handling pada GraphQL Server, lengkap dengan contoh kode, simulasi, dan diagram alur.
Mengapa Logging dan Error Handling itu Penting?
Logging memberikan visibility tentang apa yang terjadi di sistem, membantu membantu debugging, pemantauan performa, hingga deteksi serangan. Error handling yang baik memastikan aplikasi tetap tangguh dan user mendapat pesan error yang relevan tanpa mengorbankan keamanan sistem.
Konsep Dasar Logging & Error Handling di GraphQL
Logging
Secara sederhana, logging adalah proses mencatat peristiwa selama eksekusi program. Pada server GraphQL, kita bisa membagi logging menjadi beberapa level, misalnya:
Level Log | Deskripsi |
---|---|
Error | Error yang menyebabkan request gagal |
Warning | Hal-hal yang perlu diperhatikan, tapi tidak fatal |
Info | Informasi umum jalannya sistem |
Debug | Detail teknis, biasa dipakai saat develop |
Error Handling
GraphQL memiliki mekanisme untuk error propagation yang berbeda dengan REST. Semua response GraphQL mengembalikan HTTP 200, meski error terjadi; detail error diletakkan di field errors
pada response JSON.
Contoh response error GraphQL:
{
"data": null,
"errors": [
{
"message": "User not found",
"locations": [ { "line": 2, "column": 3 } ],
"path": [ "user" ]
}
]
}
Implementasi Logging di GraphQL Server (Node.js Example)
Mari kita mulai dengan setup sederhana menggunakan Apollo Server dan library logging populer seperti winston.
Instalasi Package
npm install apollo-server winston
Konfigurasi Winston
// logger.js
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.Console(),
// new winston.transports.File({ filename: 'error.log', level: 'error' }),
],
});
module.exports = logger;
Logging pada Resolvers
Kita ingin log setiap kali terjadi error ataupun event penting, misal query user tertentu:
// resolvers.js
const logger = require('./logger');
const resolvers = {
Query: {
user: async (_, { id }, ctx) => {
logger.info(`Fetching user with id=${id}`);
const user = await ctx.db.getUserById(id);
if (!user) {
logger.error(`User not found: id=${id}`);
throw new Error('User not found');
}
return user;
}
}
};
module.exports = resolvers;
Log Request dan Response di Middleware
Apollo Server menyediakan lifecycle hooks agar kita bisa logging lebih terstruktur:
// server.js
const { ApolloServer } = require('apollo-server');
const logger = require('./logger');
const typeDefs = require('./typeDefs');
const resolvers = require('./resolvers');
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => ({ db: require('./db'), req }),
plugins: [
{
requestDidStart(requestContext) {
logger.info(`Received request: ${requestContext.request.query}`);
return {
willSendResponse({ response }) {
if (response.errors) {
logger.error(JSON.stringify(response.errors));
}
logger.info('Sending response...');
},
};
},
},
]
});
server.listen().then(({ url }) => {
logger.info(`🚀 Server ready at ${url}`);
});
Error Handling di GraphQL
Menggunakan Custom Error Classes
GraphQL/Apollo menyediakan class ApolloError
untuk error yang disesuaikan, sehingga kita bisa mengatur kode status & field tambahan:
const { ApolloError, UserInputError, AuthenticationError } = require('apollo-server');
const resolvers = {
Mutation: {
updateProfile: async (_, args, ctx) => {
if (!ctx.user) {
throw new AuthenticationError('You must be logged in');
}
if (!args.email) {
throw new UserInputError('email is required');
}
// ...
try {
// Simulate db error
throw new Error('DB connection failed!');
} catch (err) {
throw new ApolloError('Internal server error', 'INTERNAL_ERROR');
}
}
}
}
Hasilnya, field extensions.code
pada response error akan berisi kode yang sesuai.
Simulasi Output Error
Misal kita kirim mutation updateProfile tanpa login, outputnya:
{
"data": null,
"errors": [{
"message": "You must be logged in",
"extensions": {
"code": "UNAUTHENTICATED"
}
}]
}
Jika error pada database:
{
"data": null,
"errors": [{
"message": "Internal server error",
"extensions": {
"code": "INTERNAL_ERROR"
}
}]
}
Pengelolaan Error Secara Terpusat
Alih-alih menangani error di tiap resolver, kita bisa centralized error handling pada layer server dengan formatError
:
const server = new ApolloServer({
// ...
formatError: (err) => {
logger.error(`[GraphQL Error] ${err.message}`);
// Custom masking: hanya tampilkan pesan aman ke client
if (err.extensions.code === 'INTERNAL_SERVER_ERROR') {
return new Error('An unexpected error occurred'); // Hide internal details
}
return err;
}
});
Flow Logging & Error Handling (Diagram Mermaid)
Mari lihat alur utama proses ini:
flowchart TD A[Request Masuk] --> B{Ada Error?} B -- Ya --> C{Error Known?} C -- Ya --> D[Log Error w/ Context dan Return Custom Error] C -- Tidak --> E[Log Error dan Masking Error, Return Generic Message] B -- Tidak --> F[Log Sukses, Return Data]
Pada diagram tersebut, kita membedakan error yang sudah kita ketahui jenisnya (misal: auth, input validation) dengan error tak terduga (runtime error, db crash dsb).
Praktik Terbaik (Best Practice)
Dari pengalaman deploy GraphQL ke production, berikut beberapa saran yang sebaiknya kamu ikuti:
Pisahkan penanganan error trusted vs untrusted
Trusted: domain error, input, business logic.
Untrusted: jaringan, database, bug runtime — mask error ke client, log detail pada server.Log context yang cukup saat error, jangan log password/api key!
Gunakan kode error/enum yang jelas pada extensions.code
Tambahkan correlation id pada setiap request untuk tracing
Notifikasi ke ops/dev kalau error kritikal muncul (misal integrasi ke Slack, Sentry, atau email)
Jangan expose stack trace atau error internal ke front-end
Penutup
Logging dan error handling di server GraphQL bukan sekadar menambah console.log lalu melempar error. Implementasi yang baik membuat sistem mudah dipantau, aman, dan gampang di-debug. Ingat, sebuah sistem pasti akan error — yang membedakannya, seberapa siap aplikasi kita menghadapinya?
Terus asah kemampuan observabilitas Anda, karena dengan ekosistem yang grow fast seperti GraphQL, robust error handling & logging is no longer optional. Happy hacking!
75. Studi Kasus: API Gateway untuk gRPC Service
Artikel Terhangat
56 Apa Itu Subscription di GraphQL?
08 Aug 2025
78. Men-deploy gRPC Service di Docker
08 Aug 2025
77. gRPC di Kubernetes dengan LoadBalancer
08 Aug 2025
54 Menambahkan Rate Limiting dan Throttling
08 Aug 2025
76. Menyambungkan gRPC Service dengan Kafka
08 Aug 2025

56 Apa Itu Subscription di GraphQL?

78. Men-deploy gRPC Service di Docker

77. gRPC di Kubernetes dengan LoadBalancer

54 Menambahkan Rate Limiting dan Throttling
