Lewati ke konten utama
MongoDB

MongoDB dan GraphQL: Pasangan Sempurna

Pelajari cara membuat API GraphQL dengan TypeScript dan MongoDB, perpaduan yang tidak hanya efisien, tetapi juga sangat mudah digunakan.
Nic Raboy's photo
Nic Raboy
Diperbarui · 11 mnt Baca

Jelajahi bersama AI

ChatGPTClaudePerplexity

Buat Akun Gratis Anda

Berlatih dan lacak kemajuan Anda.

Lanjutkan Dengan Google
Dengan melanjutkan, Anda menerima Ketentuan Penggunaan kami, Kebijakan Privasi kami dan bahwa data Anda disimpan di Amerika Serikat.

GraphQL adalah cara yang kuat dan efisien untuk membangun API. Klien melakukan kueri ke API, mirip seperti ke basis data, dan API tersebut hanya mengembalikan data yang mereka minta, sering kali mengurangi payload respons dan meningkatkan waktu respons. Waktu respons yang rendah sangat krusial di dunia modern.

Ketika API GraphQL dipasangkan dengan MongoDB, Anda tidak hanya mendapatkan waktu respons yang cepat, tetapi juga format data yang konsisten dari awal hingga akhir.

Bayangkan ini: Klien Anda mengeksekusi kueri GraphQL dan kueri tersebut tampak mirip JSON. Saat data mencapai aplikasi Anda—yang, misalnya, adalah TypeScript pada contoh ini—Anda kini bekerja dengan format data yang mirip JSON di dalam aplikasi. Selangkah lebih jauh, saat bekerja dengan MongoDB, data yang Anda kirim ke dan dari MongoDB juga akan mirip JSON. Jadi yang Anda dapatkan adalah pengalaman data yang konsisten sekaligus performa. Tidak perlu terlalu khawatir memanipulasi dan memformat data, sehingga Anda bisa fokus pada pengalaman pengguna aplikasi Anda, bukan pada basis data dan peralatannya.

Dalam tutorial ini, kita akan melihat betapa mudahnya menggunakan MongoDB di API GraphQL Anda, kali ini dibangun dengan TypeScript.

Prasyarat

Untuk tutorial ini, pastikan beberapa hal berikut sudah siap sebelum kita mulai:

  • Klon MongoDB Atlas
  • Node.js 22+
  • MongoDB Node.js Driver 6.x

Kita tidak akan melakukan hal yang terlalu rumit dari sisi basis data dalam tutorial ini, jadi kluster MongoDB level apa pun akan berfungsi, bahkan tier gratis. Namun, kita tidak akan membahas penyediaan kluster MongoDB Atlas di sini. Ekspektasinya adalah Anda sudah menyiapkan aturan pengguna dan aturan jaringan. Jika Anda butuh bantuan untuk memulai, lihat dokumentasi Get Started With Atlas terkait topik ini.

Anda perlu membuat aplikasi Node.js. Jika Anda mau, jalankan perintah berikut:

mkdir graphql_example
cd graphql_example
npm init -y

Perintah di atas membuat direktori proyek baru dan berkas package.json dasar. Kita akan menggunakan TypeScript, Express Framework, MongoDB, dan Apollo dalam proyek ini. Semuanya dapat diinstal dengan perintah berikut:

npm install @apollo/server@4 body-parser cors dotenv express@4 graphql mongodb
npm install @types/cors @types/express@4 @types/node tsx typescript --save-dev

Perintah di atas akan memasang dependensi sekaligus definisi tipe yang digunakan di TypeScript.

Sebagai bagian terakhir dari prasyarat, Anda perlu memiliki berkas konfigurasi untuk TypeScript. Di root proyek Anda, buat berkas tsconfig.json dengan JSON berikut:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": ["ES2020"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "moduleResolution": "node",
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

Jika kapan pun Anda ingin melihat proyek secara keseluruhan atau mencobanya sendiri, Anda bisa melihatnya di GitHub.

Buat Fondasi dengan Dependensi Apollo, Express, dan MongoDB

Dari sisi struktur proyek, kita akan menggunakan hal-hal berikut:

  • src/database/connection.ts
  • src/database/userService.ts
  • src/resolvers/index.ts
  • src/schema/typeDefs.ts
  • src/types/index.ts
  • src/index.ts
  • .env

Berkas src/index.ts akan memuat seluruh bootstrap Express Framework dan Apollo. Ini mencakup memulai server, mendefinisikan endpoint GraphQL, dan seterusnya. Berkas src/types/index.ts akan memuat definisi TypeScript untuk bekerja dengan model data basis data di dalam aplikasi. Ini jangan disamakan dengan berkas src/schema/typeDefs.ts yang, meski mirip, berfokus pada definisi tipe GraphQL.

Artinya, kita memiliki direktori database dan resolvers. Sebagian besar logika aplikasi dan basis data akan berada di berkas-berkas ini, yang akan segera kita bahas.

Untuk saat ini, mari fokus menyiapkan server pada berkas src/index.ts:

import 'dotenv/config';
import { ApolloServer } from '@apollo/server';
import { expressMiddleware } from '@apollo/server/express4';
import express from 'express';
import http from 'http';
import cors from 'cors';
import bodyParser from 'body-parser';
import { typeDefs } from './schema/typeDefs';
import { resolvers } from './resolvers';

async function startServer() {
  try {

    const app = express();
    
    const httpServer = http.createServer(app);

    const server = new ApolloServer({
      typeDefs,
      resolvers,
    });

    await server.start();

    app.use(
      '/graphql',
      cors<cors.CorsRequest>(),
      bodyParser.json(),
      expressMiddleware(server)
    );

    const PORT = process.env.PORT || 3000;
    await new Promise<void>((resolve) => httpServer.listen({ port: PORT }, resolve));
    
    console.log(Server ready at http://localhost:${PORT}/graphql);

  } catch (error) {
    console.error('Error starting server:', error);
    process.exit(1);
  }
}

startServer();

Kita akan mengembangkan berkas di atas seiring progres.

Sebagai awal, kita mengimpor semua dependensi proyek. Selanjutnya, kita mengonfigurasi server Express Framework dan middleware Apollo.

const server = new ApolloServer({
  typeDefs,
  resolvers,
});

Kita belum menambahkan apa pun ke berkas src/schema/typeDefs.ts dan src/resolvers/index.ts, tetapi pada tahap ini, kita menyiapkan semuanya. Kita belum bisa menjalankan server tanpa error sampai kita mulai melengkapi bagian kosong di berkas lain.

Perlu disebutkan bahwa contoh ini mengizinkan permintaan dari semua origin karena hal berikut:

cors<cors.CorsRequest>(),

Meskipun ini baik untuk lingkungan pengembangan, pertimbangkan untuk menambahkan hanya origin yang Anda perlukan pada penerapan produksi.

Berinteraksi dengan MongoDB dari Aplikasi TypeScript dengan Node.js

Walau fondasi server Express Framework dan Apollo sudah ada, kita belum mengonfigurasi MongoDB dalam aplikasi. Sebelum masuk ke kode, kita perlu menambahkan informasi koneksi ke berkas .env:

MONGODB_URI="mongodb+srv://<USERNAME>:<PASSWORD>@<HOST>/?appName=devrel-graphql"
DB_NAME="graphql_example"

Nilai <USERNAME>, <PASSWORD>, dan <HOST> harus diganti dengan informasi kluster MongoDB Atlas Anda yang dapat ditemukan di dasbor MongoDB Atlas Anda.

Selanjutnya, mari tetapkan logika koneksi basis data untuk aplikasi kita. Di dalam berkas **src/database/connection.ts**, tambahkan kode berikut:

import { MongoClient, Db } from 'mongodb';

let db: Db | null = null;
let client: MongoClient | null = null;

export async function connectToDatabase(): Promise<Db> {
  if (db) {
    return db;
  }

  try {
    const MONGODB_URI = process.env.MONGODB_URI;
    if (!MONGODB_URI) {
      throw new Error('MONGODB_URI is not set');
    }
    const DB_NAME = process.env.DB_NAME || 'graphql_example';
    const APP_NAME = process.env.APP_NAME || 'devrel-graphql';

    console.log('Connecting to MongoDB...');
    
    client = new MongoClient(MONGODB_URI, { appName: APP_NAME });
    await client.connect();
    
    db = client.db(DB_NAME);
    
    console.log(Successfully connected to MongoDB database: ${DB_NAME});
    
    return db;
  } catch (error) {
    console.error('MongoDB connection error:', error);
    throw error;
  }
}

export function getDatabase(): Db {
  if (!db) {
    throw new Error('Database not initialized. Call connectToDatabase() first.');
  }
  return db;
}

export async function closeDatabase(): Promise<void> {
  if (client) {
    await client.close();
    db = null;
    client = null;
    console.log('MongoDB connection closed');
  }
}

Gagasannya di sini adalah kita membuat koneksi singleton. Ada banyak metode lain untuk membuat MongoDB berfungsi dalam aplikasi Anda, tetapi ini jalur yang kita pilih untuk aplikasi ini.

Fungsi connectToDatabase akan mengambil informasi koneksi dari berkas **.env**, melakukan koneksi, dan mengembalikan basis data yang Anda tentukan. Jika gagal, error akan ditangkap dan dilempar. Anda hanya perlu menggunakan fungsi connectToDatabase saat menyiapkan server seperti pada berkas sebelumnya.

Fungsi getDatabase akan digunakan setiap kali ada permintaan ke aplikasi kita. Ini memungkinkan kita mendapatkan instance koneksi saat ini.

Terakhir, jika kita ingin menjaga kebersihan, kita memiliki fungsi closeDatabase untuk menutup koneksi ke basis data saat server dihentikan. Terserah Anda ingin menyertakan fungsi seperti ini atau tidak, tetapi sebaiknya ada.

Sebelum masuk ke logika basis data, ada baiknya kita menyiapkan tipe TypeScript untuk data transfer object (DTO):

export interface User {
  id: string;
  name: string;
  email: string;
  age?: number;
  createdAt: string;
}

export interface CreateUserInput {
  name: string;
  email: string;
  age?: number;
}

export interface UpdateUserInput {
  id: string;
  name?: string;
  email?: string;
  age?: number;
}

Antarmuka di atas, yang terdapat di berkas **src/types/index.ts**, dikelola oleh API kita, tetapi logika basis data tetap perlu mengenalnya. Sebentar lagi Anda akan melihatnya.

Ini membawa kita ke interaksi basis data sebenarnya untuk create, retrieve, update, delete (CRUD), yang dilakukan di berkas src/database/userService.ts. Idenya adalah resolver GraphQL kita akan menangani logika aplikasi dan memanggil fungsi dalam berkas service ini, dan service akan menangani logika basis data.

Di berkas src/database/userService.ts, kita memiliki kode berikut:

import { Collection, ObjectId } from 'mongodb';
import { getDatabase } from './connection';
import { User, CreateUserInput, UpdateUserInput } from '../types';

interface UserDocument {
  _id: ObjectId;
  name: string;
  email: string;
  age?: number;
  createdAt: Date;
}

export class UserService {
  private collection: Collection<UserDocument>;

  constructor() {
    const db = getDatabase();
    this.collection = db.collection<UserDocument>('users');
  }

  private toUser(doc: UserDocument): User {
    return {
      id: doc._id.toString(),
      name: doc.name,
      email: doc.email,
      age: doc.age,
      createdAt: doc.createdAt.toISOString(),
    };
  }

  async getAllUsers(): Promise<User[]> {
    const users = await this.collection.find().toArray();
    return users.map(doc => this.toUser(doc));
  }

  async getUserById(id: string): Promise<User | null> {
    try {
      const doc = await this.collection.findOne({ _id: new ObjectId(id) });
      return doc ? this.toUser(doc) : null;
    } catch (error) {
      return null;
    }
  }

  async createUser(input: CreateUserInput): Promise<User> {
    const newUser: Omit<UserDocument, '_id'> = {
      name: input.name,
      email: input.email,
      age: input.age,
      createdAt: new Date(),
    };

    const result = await this.collection.insertOne(newUser as UserDocument);
    
    const createdUser = await this.collection.findOne({ _id: result.insertedId });
    
    if (!createdUser) {
      throw new Error('Failed to create user');
    }

    return this.toUser(createdUser);
  }

  async updateUser(input: UpdateUserInput): Promise<User | null> {
    try {
      const updateFields: Partial<Omit<UserDocument, '_id'>> = {};
      
      if (input.name !== undefined) updateFields.name = input.name;
      if (input.email !== undefined) updateFields.email = input.email;
      if (input.age !== undefined) updateFields.age = input.age;

      const result = await this.collection.findOneAndUpdate(
        { _id: new ObjectId(input.id) },
        { $set: updateFields },
        { returnDocument: 'after' }
      );

      return result ? this.toUser(result) : null;
    } catch (error) {
      return null;
    }
  }

  async deleteUser(id: string): Promise<boolean> {
    try {
      const result = await this.collection.deleteOne({ _id: new ObjectId(id) });
      return result.deletedCount > 0;
    } catch (error) {
      return false;
    }
  }

  async createIndexes(): Promise<void> {
    await this.collection.createIndex({ email: 1 }, { unique: true });
    await this.collection.createIndex({ createdAt: -1 });
    console.log('Database indexes created');
  }
}

Hal pertama yang mungkin Anda perhatikan di atas adalah antarmuka berikut:

interface UserDocument {
  _id: ObjectId;
  name: string;
  email: string;
  age?: number;
  createdAt: Date;
}

Sekilas mirip dengan antarmuka User, tetapi tidak persis sama. UserDocument lebih ketat dimodelkan mengikuti apa yang digunakan basis data kita. Kita bekerja dengan ObjectId di basis data, tetapi string hash di aplikasi. Di MongoDB, id direpresentasikan sebagai _id alih-alih id, seperti yang kita lihat pada antarmuka User.

Ini membawa kita ke kelas UserService.

Setelah mendapatkan handle ke koleksi dari instance basis data melalui metode constructor, kita memiliki deretan fungsi berikut:

  • toUser
  • getAllUsers
  • getUserById
  • createUser
  • updateUser
  • deleteUser
  • createIndexes

Fungsi toUser pada dasarnya adalah fungsi pembantu yang mengonversi antara User dan UserDocument. Kita mengirim dan menerima UserDocument ke dan dari basis data dan perlu mengonversinya agar kita dapat mengirim dan menerima User dari aplikasi.

async createIndexes(): Promise<void> {
	await this.collection.createIndex({ email: 1 }, { unique: true });
	await this.collection.createIndex({ createdAt: -1 });
	console.log('Database indexes created');
}

Fungsi createIndexes akan membuat beberapa indeks contoh yang mungkin berguna. Secara bawaan, indeks hanya akan ada pada bidang _id, yang tidak masalah untuk demo dengan hanya segelintir dokumen, tetapi seiring pertumbuhan aplikasi Anda, jangan abaikan pembuatan indeks yang tepat berdasarkan data dan kebutuhan kueri Anda. Dua indeks di atas hanyalah contoh dari apa yang mungkin Anda butuhkan.

Sekarang, kita bisa melihat tiap fungsi service dimulai dari fungsi getAllUsers:

async getAllUsers(): Promise<User[]> {
	const users = await this.collection.find().toArray();
	return users.map(doc => this.toUser(doc));
}

Fungsi di atas akan menemukan semua dokumen di koleksi karena tidak ada kriteria filter pada fungsi find. Hasilnya dikonversi dengan fungsi toUser dan dikembalikan ke aplikasi, yang nantinya akan menjadi resolver Apollo kita.

async getUserById(id: string): Promise<User | null> {
	try {
	  const doc = await this.collection.findOne({ _id: new ObjectId(id) });
	  return doc ? this.toUser(doc) : null;
	} catch (error) {
	  return null;
	}
}

Fungsi getByUserId mirip, tetapi kali ini kita menggunakan findOne dan menentukan kriteria filter—kriterianya adalah kita ingin satu pengguna berdasarkan bidang unik _id. Karena bidang id pada antarmuka User berupa string, kita perlu membungkusnya dalam objek ObjectId agar sesuai untuk kueri di MongoDB.

Selanjutnya, kita membuat data di MongoDB melalui fungsi createUser:

async createUser(input: CreateUserInput): Promise<User> {
	const newUser: Omit<UserDocument, '_id'> = {
	  name: input.name,
	  email: input.email,
	  age: input.age,
	  createdAt: new Date(),
	};
	
	const result = await this.collection.insertOne(newUser as UserDocument);
	
	const createdUser = await this.collection.findOne({ _id: result.insertedId });
	
	if (!createdUser) {
	  throw new Error('Failed to create user');
	}
	
	return this.toUser(createdUser);
}

Setelah menggunakan fungsi insertOne untuk menyisipkan data, kita menggunakan insertedId yang dikembalikan untuk kemudian mengkueri data tersebut. Kita melakukan ini karena di API GraphQL, ketika data dibuat, ekspektasi umumnya adalah Anda bisa mengkueri data itu dalam mutasi yang sama.

Fungsi updateUser sedikit berbeda:

async updateUser(input: UpdateUserInput): Promise<User | null> {
	try {
	  const updateFields: Partial<Omit<UserDocument, '_id'>> = {};
	  
	  if (input.name !== undefined) updateFields.name = input.name;
	  if (input.email !== undefined) updateFields.email = input.email;
	  if (input.age !== undefined) updateFields.age = input.age;
	
	  const result = await this.collection.findOneAndUpdate(
		{ _id: new ObjectId(input.id) },
		{ $set: updateFields },
		{ returnDocument: 'after' }
	  );
	
	  return result ? this.toUser(result) : null;
	} catch (error) {
	  return null;
	}
}

Dalam aplikasi ini, kita hanya mengizinkan pembaruan pada bidang name, email, dan age. Semua bidang ini bersifat opsional, jadi kita harus menetapkannya dalam kriteria pembaruan jika ada.

Ini mengantarkan kita ke fungsi findOneAndUpdate.

Parameter objek pertama fungsi ini adalah kriteria filter. Kita hanya tertarik melakukan pembaruan jika _id cocok. Untuk setiap kecocokan, kita menggunakan operator $set untuk mengganti atau membuat bidang apa pun di objek updateFields. Bidang yang tidak muncul di objek tidak akan diubah. Terakhir, karena ekspektasinya kita mencari dan memperbarui, bukan sekadar memperbarui, kita menetapkan returnDocument ke after karena kita menginginkan dokumen yang sudah berubah sebagai respons, bukan dokumen aslinya. Jika kita menggunakan updateOne alih-alih findOneAndUpdate, kita hanya akan menerima informasi tentang operasi pembaruan, bukan datanya.

Operasi CRUD terakhir untuk API ini adalah menghapus data dari MongoDB, dan ini dilakukan melalui fungsi deleteUser:

async deleteUser(id: string): Promise<boolean> {
	try {
	  const result = await this.collection.deleteOne({ _id: new ObjectId(id) });
	  return result.deletedCount > 0;
	} catch (error) {
	  return false;
	}
}

Fungsi deleteOne di atas terlihat seperti findOne karena kita hanya menggunakan kriteria filter berdasarkan _id. Bedanya, kecocokan apa pun—dalam kasus ini, maksimal satu dokumen—akan dihapus.

Pada titik ini, logika basis data sudah siap. Untuk meresmikannya, kita perlu melakukan koneksi dari berkas **src/index.ts**:

// Previous imports here...
import { connectToDatabase, closeDatabase } from './database/connection';
import { UserService } from './database/userService';

async function startServer() {
  try {

    await connectToDatabase();
    
    const userService = new UserService();
    await userService.createIndexes();
    
    // The rest of the file here...
}

Pada cuplikan di atas, sebagian besar berkas src/index.ts dihilangkan. Tujuannya hanya menunjukkan penggunaan fungsi connectToDatabase dan pembuatan indeks. Lebih jelasnya, letakkan tiga baris tersebut di bagian atas fungsi startServer Anda.

Pada titik ini, kita bisa fokus pada logika API.

Definisikan Tipe GraphQL, Resolver, dan Logika Aplikasi Kustom

Kita sudah memiliki tipe TypeScript yang didefinisikan untuk bekerja dengan basis data serta mengoper data di dalam aplikasi. Namun, kita belum membuat definisi tipe GraphQL, sesuatu yang mendefinisikan apa yang bisa diakses pengguna saat menggunakan API kita.

Di berkas src/schema/typeDefs.ts, tambahkan hal berikut:

export const typeDefs = #graphql
  type User {
    id: ID!
    name: String!
    email: String!
    age: Int
    createdAt: String!
  }

  type Query {
    users: [User!]!
    user(id: ID!): User
  }

  type Mutation {
    createUser(name: String!, email: String!, age: Int): User!
    updateUser(id: ID!, name: String, email: String, age: Int): User
    deleteUser(id: ID!): Boolean!
  }
;

Tipe User adalah apa yang boleh diminta klien dalam kueri. Pada contoh ini, cocok dengan antarmuka User, tetapi tidak harus demikian. Misalnya, mungkin antarmuka User Anda berisi data yang tidak ingin pernah dikembalikan ke klien, seperti kata sandi.

Tipe Query mendefinisikan jenis kueri yang dapat dijalankan dalam API kita. Setiap kueri akan mengembalikan User atau array User, tetapi kita bisa memiliki logika khusus di antara kueri-kueri ini.

Tipe Mutation mirip dengan Query, tetapi dimaksudkan untuk kueri yang memanipulasi data.

Dengan definisi tipe GraphQL siap, kita bisa fokus pada logika resolver untuk aplikasi. Di berkas proyek src/resolvers/index.ts, sertakan kode berikut:

import { UserService } from '../database/userService';
import { User, CreateUserInput, UpdateUserInput } from '../types';

export const resolvers = {
  Query: {
    users: async (): Promise<User[]> => {
      const userService = new UserService();
      return await userService.getAllUsers();
    },

    user: async (_: unknown, { id }: { id: string }): Promise<User | null> => {
      const userService = new UserService();
      return await userService.getUserById(id);
    },
  },

  Mutation: {
    createUser: async (
      _: unknown,
      { name, email, age }: CreateUserInput
    ): Promise<User> => {
      const userService = new UserService();
      return await userService.createUser({ name, email, age });
    },

    updateUser: async (
      _: unknown,
      { id, name, email, age }: UpdateUserInput
    ): Promise<User | null> => {
      const userService = new UserService();
      return await userService.updateUser({ id, name, email, age });
    },

    deleteUser: async (_: unknown, { id }: { id: string }): Promise<boolean> => {
      const userService = new UserService();
      return await userService.deleteUser(id);
    },
  },
};

Resolver di atas hanyalah perpanjangan dari apa yang kita lihat di berkas definisi tipe untuk kueri dan mutasi.

Perhatikan kueri users berikut:

users: async (): Promise<User[]> => {
  const userService = new UserService();
  return await userService.getAllUsers();
},

Kueri GraphQL ini akan memanfaatkan UserService kita, bagian dari logika basis data, untuk mengambil semua pengguna. Respons User[] akan dikirim kembali ke pengguna, tetapi hanya bagian-bagian yang diminta yang sesuai dengan definisi tipe GraphQL.

Sebagai contoh, misalnya klien mengirim kueri ini:

query {
	users {
		name
		email
	}
}

Pada contoh di atas, kita memiliki lebih banyak bidang untuk dikerjakan, tetapi klien hanya menginginkan bidang name dan email. Ini ditangani berdasarkan definisi tipe GraphQL yang digunakan klien. Apollo menangani sihirnya agar itu terjadi.

Aturan yang sama berlaku untuk setiap kueri dan mutasi dalam berkas **src/resolvers/index.ts** kita.

createUser: async (
  _: unknown,
  { name, email, age }: CreateUserInput
): Promise<User> => {
  const userService = new UserService();
  return await userService.createUser({ name, email, age });
},

Untuk definisi tipe createUser, kita melihat bahwa klien dapat mengirim bidang name, email, dan age. Dalam fungsi resolver createUser, kita melakukan hal yang sama dan memanggil fungsi createUser dari service basis data. Respons dikembalikan ke klien berdasarkan bidang apa pun yang mereka minta.

Build dan Jalankan API GraphQL

Pada titik ini, API GraphQL seharusnya sudah dalam kondisi sangat baik. Ada beberapa cara untuk membangun dan menjalankan aplikasi ini.

Sebagai contoh, Anda bisa menambahkan hal berikut ke berkas **package.json** Anda:

"scripts": {
	"build": "tsc",
	"start": "node dist/index.js",
	"dev": "tsx src/index.ts",
	"dev:watch": "tsx watch src/index.ts",
	"watch": "tsc -w"
},

Jika Anda memilih jalur ini, Anda bisa menjalankan npm run build untuk membangun proyek dan npm run start untuk mulai menyajikan proyek. Port bawaan adalah 3000, dan dapat diuji dengan cURL atau alat apa pun yang Anda sukai.

Kesimpulan

Anda baru saja melihat cara membuat API GraphQL dengan TypeScript dan MongoDB sebagai basis data. Meskipun contoh ini dibuat sederhana, kita melihat cara membangun kueri dan mutasi untuk melakukan operasi CRUD terhadap basis data. MongoDB adalah pasangan yang sempurna saat digunakan dalam API GraphQL karena data yang Anda gunakan diformat serupa dari awal hingga akhir. Misalnya, klien menjalankan kueri yang terlihat mirip JSON. Data yang dilewatkan melalui kueri dapat digunakan dengan sedikit pemformatan dan penyesuaian, demikian pula saat dikirim ke dan dari basis data. Pengalamannya mulus, memungkinkan Anda fokus pada pengalaman pengguna dan tidak terlalu memanipulasi data untuk memenuhi kebutuhan basis data.

Jika Anda mengalami kendala di titik mana pun dalam tutorial ini, pastikan untuk melihat proyek yang sudah selesai di GitHub.

FAQs

Mengapa saya harus menggunakan GraphQL?

GraphQL sangat bagus karena Anda dapat melakukan kueri ke API seperti ke basis data, meminta hanya apa yang Anda butuhkan. Ini membuatnya ringan dan efisien bagi klien.

Apakah Apollo satu-satunya opsi untuk GraphQL?

Apollo membuat pembuatan API GraphQL menjadi sangat mudah, tetapi ini bukan satu-satunya opsi. Namun, opsi lain berada di luar cakupan tutorial ini.

Mengapa menggunakan MongoDB dengan GraphQL?

Keduanya bekerja dengan format data mirip JSON, sehingga Anda tidak perlu terus-menerus mengonversi antara struktur data yang berbeda saat informasi mengalir dari basis data ke API lalu ke klien.

Apa yang dilakukan resolver?

Resolver adalah fungsi yang memberi tahu GraphQL cara mengambil atau memodifikasi data untuk bidang tertentu di skema Anda.

Apa perbedaan antara query dan mutation?

Query digunakan untuk membaca/mengambil data (seperti permintaan GET), sedangkan mutasi digunakan untuk membuat, memperbarui, atau menghapus data (seperti POST, PUT, DELETE).


Nic Raboy's photo
Author
Nic Raboy

Nic Raboy adalah Pimpinan Developer Relations di MongoDB, memimpin tim pengembang Python, Java, C#, dan PHP yang membuat konten luar biasa untuk membantu para pengembang berhasil mengintegrasikan MongoDB ke dalam proyek mereka. Ia berpengalaman dengan Golang dan JavaScript dan sering menulis tentang berbagai petualangan pengembangannya.

Topik
MongoDB

Kursus Teratas di DataCamp

Kursus

Pengantar MongoDB di Python

3 jam
24.4K
Kuasai manipulasi dan analisis data berstruktur fleksibel menggunakan MongoDB.
Lihat DetailMulai Kursus

Buat Akun Gratis Anda

Berlatih dan lacak kemajuan Anda.

Lanjutkan Dengan Google
Dengan melanjutkan, Anda menerima Ketentuan Penggunaan kami, Kebijakan Privasi kami dan bahwa data Anda disimpan di Amerika Serikat.
Lihat Selengkapnya
Terkait

blogs

Spaghetti Plot dan Jalur Badai

Temukan alasan mengapa Anda sebaiknya (tidak) menggunakan spaghetti plot untuk menyampaikan ketidakpastian jalur prediksi badai serta dampaknya terhadap interpretasi.
Hugo Bowne-Anderson's photo

Hugo Bowne-Anderson

13 mnt

blogs

Tutorial Korelasi di R

Dapatkan pengenalan dasar-dasar korelasi di R: pelajari lebih lanjut tentang koefisien korelasi, matriks korelasi, plotting korelasi, dan sebagainya.
David Woods's photo

David Woods

13 mnt

blogs

12 Alternatif ChatGPT Terbaik yang Bisa Anda Coba pada 2026

Artikel ini menyajikan daftar alternatif ChatGPT yang akan meningkatkan produktivitas Anda.
Javier Canales Luna's photo

Javier Canales Luna

14 mnt

blogs

40 Pertanyaan Wawancara DBMS Teratas di 2026

Kuasai pertanyaan wawancara basis data, dari konsep SQL dasar hingga skenario desain sistem tingkat lanjut. Panduan mendalam ini mencakup semua yang Anda perlukan untuk sukses di wawancara DBMS dan meraih peran berikutnya.
Dario Radečić's photo

Dario Radečić

15 mnt

Lihat Selengkapnya