Kurs
GraphQL, API geliştirmek için güçlü ve verimli bir yöntemdir. İstemci, bir veritabanını sorgular gibi API'yi sorgular ve bu API yalnızca talep edilen verileri döndürür; bu da çoğu zaman yanıt yükünü azaltır ve yanıt sürelerini iyileştirir. Düşük yanıt süreleri günümüz dünyasında kritik öneme sahiptir.
GraphQL API'si MongoDB ile eşleştirildiğinde, yalnızca hızlı yanıt süreleri elde etmekle kalmaz, baştan sona tutarlı bir veri formatı da elde edersiniz.
Şunu hayal edin: İstemciniz bir GraphQL sorgusu çalıştırıyor ve bu sorgu JSON'a benziyor. Veriler uygulamanıza ulaştığında—örneğin bu örnekte TypeScript olsun—artık uygulamanızda JSON'a benzer bir veri formatıyla çalışıyorsunuz. Bir adım daha ileri gidip MongoDB ile çalışırken, MongoDB'ye gönderdiğiniz ve MongoDB'den aldığınız veriler de JSON'a benzer olacaktır. Yani performansın yanı sıra tutarlı bir veri deneyimi elde ediyorsunuz. Verilerinizi manipüle etme ve biçimlendirme konusunda fazla endişelenmenize gerek kalmaz; bunun yerine odak noktanız veritabanı ve araçlar değil, uygulamanızın kullanıcı deneyimi olur.
Bu eğitimde, MongoDB'yi GraphQL API'nizde kullanmanın ne kadar kolay olduğunu, bu kez TypeScript ile nasıl inşa edildiğini göreceğiz.
Ön Koşullar
Bu özel eğitim için başlamadan önce hazır olmamız gereken birkaç unsur var:
- Bir MongoDB Atlas kümesi
- Node.js 22+
- MongoDB Node.js Sürücüsü 6.x
Bu eğitimde veritabanı açısından özellikle olağanüstü bir şey yapmayacağız; bu nedenle MongoDB'nin herhangi bir katmanlı kümesi, ücretsiz katman da dahil, iş görecektir. Ancak bu eğitimde bir MongoDB Atlas kümesinin sağlanmasını ele almayacağız. Beklenti, kullanıcı kurallarınızın ve ağ kurallarınızın hazır olmasıdır. Başlamak için yardıma ihtiyacınız varsa, konuyla ilgili Atlas ile Başlayın belgelerine göz atın.
Bir Node.js uygulaması oluşturmuş olmanız gerekecek. İsterseniz aşağıdaki komutları çalıştırabilirsiniz:
mkdir graphql_example
cd graphql_example
npm init -y
Yukarıdaki komutlar yeni bir proje dizini ve temel bir package.json dosyası oluşturur. Bu projede TypeScript, Express Framework, MongoDB ve Apollo kullanacağız. Her biri aşağıdaki komutlarla kurulabilir:
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
Yukarıdaki komutlar, bağımlılıkları ve TypeScript'te kullanılacak tür tanımlarını yükler.
Ön koşulların son kısmı olarak, TypeScript için bir yapılandırma dosyanızın olması gerekir. Projenizin kök dizininde aşağıdaki JSON ile bir tsconfig.json dosyası oluşturun:
{
"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"]
}
Projenin tamamını herhangi bir noktada görmek veya kendiniz denemek isterseniz, GitHub'da inceleyebilirsiniz.
Apollo, Express ve MongoDB Bağımlılıklarıyla Temeli Oluşturun
Proje yapısı açısından aşağıdakileri kullanacağız:
- src/database/connection.ts
- src/database/userService.ts
- src/resolvers/index.ts
- src/schema/typeDefs.ts
- src/types/index.ts
- src/index.ts
- .env
src/index.ts dosyası, tüm Express Framework ve Apollo başlatma işlemlerimizi içerecek. Bu; sunucuyu başlatmak, GraphQL uç noktalarını tanımlamak vb. anlamına gelir. src/types/index.ts dosyası, uygulamamız içinde veritabanı veri modeliyle çalışmak için TypeScript tanımlarımızı içerecek. Bu, benzer olsa da GraphQL tür tanımlarına odaklanan src/schema/typeDefs.ts dosyasıyla karıştırılmamalıdır.
Geriye database ve resolvers dizinlerimiz kalıyor. Uygulama ve veritabanı mantığımızın çoğu bu dosyalarda olacak; bunu birazdan inceleyeceğiz.
Şimdilik, src/index.ts dosyasında sunucumuzu kurmaya odaklanalım:
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();
İlerledikçe yukarıdaki dosyayı genişleteceğiz.
Başlangıç olarak tüm proje bağımlılıklarımızı içe aktarıyoruz. Ardından Express Framework sunucumuzu ve Apollo ara katmanımızı yapılandırıyoruz.
const server = new ApolloServer({
typeDefs,
resolvers,
});
src/schema/typeDefs.ts ve src/resolvers/index.ts dosyalarımıza henüz bir şey eklemedik, ancak bu aşamanın bir parçası olarak her şeyi hazır hale getiriyoruz. Diğer dosyaların boşluklarını doldurmaya başlamadan hatasız bir şekilde sunucuyu çalıştıramayacağız.
Şunu da belirtmek gerekir ki, bu özel örnek şu nedenle tüm kökenlerden gelen isteklere izin veriyor:
cors<cors.CorsRequest>(),
Bu geliştirme ortamı için iyi olsa da, üretim dağıtımında yalnızca ihtiyaç duyduğunuz kökenleri eklemeyi düşünün.
TypeScript ve Node.js Uygulamasından MongoDB ile Etkileşim
Express Framework ve Apollo sunucu temelini oluşturmuş olsak da, uygulama içinde MongoDB veritabanımızı henüz yapılandırmadık. Koda geçmeden önce, bağlantı bilgilerini .env dosyamıza eklememiz gerekiyor:
MONGODB_URI="mongodb+srv://<USERNAME>:<PASSWORD>@<HOST>/?appName=devrel-graphql"
DB_NAME="graphql_example"
<USERNAME>, <PASSWORD> ve <HOST> alanlarını, MongoDB Atlas kontrol panelinizde bulunan MongoDB Atlas kümesi bilgilerinizle değiştirin.
Sonraki adımda, uygulamamız için veritabanı bağlantı mantığını oluşturalım. **src/database/connection.ts** dosyası içine aşağıdaki kodu ekleyin:
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');
}
}
Buradaki fikir, tekil (singleton) bir bağlantı oluşturmaktır. Uygulamanızda MongoDB'yi çalıştırmanın başka birçok yöntemi var; ancak bu özel uygulama için bu yolu seçiyoruz.
connectToDatabase işlevi, **.env** dosyasındaki bağlantı bilgilerini alır, bağlanır ve tanımladığınız veritabanını döndürür. Başarısız olursa, hata yakalanır ve fırlatılır. Önceki dosyada görüldüğü gibi, sunucunuzu kurarken yalnızca connectToDatabase işlevini kullanmanız gerekir.
getDatabase işlevi, uygulamamıza herhangi bir istek yapıldığında kullanılacaktır. Bu, bağlantımızın geçerli örneğini almamıza olanak tanır.
Son olarak, işleri temiz tutmak istersek, sunucumuz sonlandığında veritabanı bağlantısını kapatmak için bir closeDatabase işlevimiz var. Böyle bir işlevi dahil etmek size kalmış; ancak bulundurmak iyi bir uygulamadır.
Veritabanı mantığına geçmeden önce, veri transfer nesnelerimiz (DTO) için TypeScript türlerimizi edinmek muhtemelen iyi bir fikir:
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;
}
**src/types/index.ts** dosyasında bulunan yukarıdaki arayüzler API'miz tarafından yönetilir; ancak veritabanı mantığımızın da bunlardan haberdar olması gerekir. Bunu az sonra göreceksiniz.
Bu da bizi oluşturma, okuma, güncelleme, silme (CRUD) için gerçek veritabanı etkileşimlerimize getiriyor; bu işlemler src/database/userService.ts dosyasında yapılır. Buradaki amaç, GraphQL çözücülerimizin (resolver) uygulama mantığını ele alması ve bu servis dosyasındaki işlevleri çağırması, servisin de veritabanı mantığını yönetmesidir.
src/database/userService.ts dosyasında aşağıdaki kod bulunur:
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');
}
}
Yukarıda ilk fark edeceğiniz şey şu arayüz olacaktır:
interface UserDocument {
_id: ObjectId;
name: string;
email: string;
age?: number;
createdAt: Date;
}
User arayüzümüze benziyor; ancak tam olarak aynı değil. UserDocument, veritabanımızın çalıştığı şeye daha sıkı biçimde modellenmiştir. Veritabanımızda ObjectId ile, ama uygulamamızda string karmalarla (hash) çalışıyoruz. MongoDB'de kimlik id yerine _id olarak temsil edilir; User arayüzünde gördüğümüz gibi.
Bu da bizi UserService sınıfına getiriyor.
constructor yöntemi aracılığıyla veritabanı örneğinden koleksiyonumuza bir tutamak (handle) aldıktan sonra, aşağıdaki işlev serisine sahibiz:
- toUser
- getAllUsers
- getUserById
- createUser
- updateUser
- deleteUser
- createIndexes
toUser işlevi, esasen User ile UserDocument arasında dönüşüm yapan bir yardımcı işlevidir. Veritabanına UserDocument gönderir ve ondan UserDocument alırız; bunu, uygulamadan User gönderip alabilmemiz için dönüştürmemiz gerekir.
async createIndexes(): Promise<void> {
await this.collection.createIndex({ email: 1 }, { unique: true });
await this.collection.createIndex({ createdAt: -1 });
console.log('Database indexes created');
}
createIndexes işlevi, bize değerli olabilecek bazı örnek indeksler oluşturur. Varsayılan olarak, yalnızca _id alanında bir indeks bulunur; bu, yalnızca az sayıda belge içeren bir demo için yeterlidir; ancak uygulamanız büyüdükçe, verileriniz ve sorgu ihtiyaçlarınıza göre uygun indeks oluşturmayı göz ardı etmeyin. Yukarıdaki iki indeks, isteyebileceğiniz şeylere yalnızca örnektir.
Şimdi, getAllUsers işleviyle başlayarak her servis işlevine bakabiliriz:
async getAllUsers(): Promise<User[]> {
const users = await this.collection.find().toArray();
return users.map(doc => this.toUser(doc));
}
Yukarıdaki işlev, find işlevinde herhangi bir filtre ölçütü olmadığı için koleksiyondaki tüm belgeleri bulur. Sonuçlar toUser işlevimizle dönüştürülür ve daha sonra Apollo çözücülerimiz olacak uygulamaya döndürülür.
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;
}
}
getByUserId işlevi benzerdir; ancak bu kez findOne kullanıyor ve bir filtre ölçütü belirtiyoruz—buradaki ölçüt, benzersiz _id alanına göre tek bir kullanıcı istememizdir. User arayüzündeki id alanı bir string olduğundan, MongoDB içindeki sorgularımıza uygun hale getirmek için onu ObjectId nesnesine sarmamız gerekir.
Bu da bizi createUser işlevi aracılığıyla MongoDB içinde veri oluşturmaya getiriyor:
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);
}
Verilerimizi eklemek için insertOne işlevini kullandıktan sonra, bu verileri sorgulamak için döndürülen insertedId'yi kullanırız. Bunu yapmamızın nedeni, bir GraphQL API'sinde veri oluşturulduğunda, genel beklentinin aynı mutasyonda bu verilerin sorgulanabilmesidir.
updateUser işlevi biraz farklıdır:
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;
}
}
Bu özel uygulamada, verilerimizin yalnızca name, email ve age alanlarına yönelik güncellemelere izin veriyoruz. Bu alanların tümü isteğe bağlıdır; bu nedenle mevcutlarsa güncelleme ölçütlerimize eklememiz gerekir.
Bu da bizi findOneAndUpdate işlevine götürür.
Bu işlevin ilk nesne parametresi filtre ölçütüdür. Yalnızca _id'nin eşleştiği durumlarda güncelleme yapmakla ilgileniyoruz. Herhangi bir eşleşme için, updateFields nesnemizdeki alanları değiştirmek veya oluşturmak için $set operatörünü kullanıyoruz. Nesnede yer almayan alanlar değiştirilmez. Son olarak, beklenti yalnızca güncelleme değil, bul ve güncelle olduğu için, yanıta orijinal belge yerine değişmiş belgeyi almak üzere returnDocument'ı after olarak ayarlıyoruz. findOneAndUpdate yerine updateOne yapsaydık, veriler yerine yalnızca güncelleme işlemi hakkında bilgi alırdık.
Bu API için son CRUD işlemi, MongoDB'den veri kaldırmaktır ve bu da deleteUser işleviyle yapılır:
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;
}
}
Yukarıdaki deleteOne işlevi, findOne işlevine benzer görünür; çünkü yalnızca _id'ye dayalı bir filtre ölçütü kullanıyoruz. Fark şu ki, herhangi bir eşleşme—bu durumda en fazla bir belge—silinir.
Bu noktada veritabanı mantığı hazır. Bunu tamamlamak için **src/index.ts** dosyasından bağlantı kurmamız gerekiyor:
// 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...
}
Yukarıdaki parçacıkta src/index.ts dosyasının çoğu çıkarıldı. Amaç yalnızca connectToDatabase işlevinin kullanımını ve indekslerin oluşturulmasını göstermektir. Açık olmak gerekirse, bu üç satırı startServer işlevinizin üst kısımlarına bırakın.
Bu noktada, API mantığına odaklanabiliriz.
GraphQL Türlerini, Çözücüleri ve Özel Uygulama Mantığını Tanımlayın
Veritabanımızla çalışmak ve verileri uygulamamızda dolaştırmak için TypeScript türlerini zaten tanımladık. Ancak, API'mizi kullanırken kullanıcının neyle etkileşime girebileceğini belirleyen GraphQL tür tanımlarını oluşturmadık.
src/schema/typeDefs.ts dosyasına şunları ekleyin:
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!
}
;
User türü, müşterinin herhangi bir sorguda talep edebileceği şeyi temsil eder. Bu örnekte User arayüzüyle eşleşiyor; ancak eşleşmek zorunda değil. Örneğin, User arayüzünüzde müşteriye asla geri döndürmek istemediğiniz bir parola gibi veriler olabilir.
Query türü, API'miz içinde çalıştırılabilecek sorgu türlerini tanımlar. Her sorgu bir User veya User dizisi döndürecektir; ancak bu sorgular arasında belirli bir mantığa sahip olabiliriz.
Mutation türü Query'ye benzer; ancak bunlar verileri değiştirmeyi amaçlayan sorgulardır.
GraphQL tür tanımları yerindeyken, uygulamanın çözücü mantığına odaklanabiliriz. Projenin src/resolvers/index.ts dosyasına aşağıdaki kodu ekleyin:
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);
},
},
};
Yukarıdaki çözücüler, tür tanımları dosyasında gördüğümüz sorgular ve mutasyonların bir uzantısıdır.
users sorgusuna göz atın:
users: async (): Promise<User[]> => {
const userService = new UserService();
return await userService.getAllUsers();
},
Bu GraphQL sorgusu, tüm kullanıcıları almak için veritabanı mantığının bir parçası olan UserService'imizi kullanacaktır. User[] yanıtı kullanıcıya gönderilecek; ancak yalnızca kullanıcının talep ettiği ve GraphQL tür tanımlarıyla eşleşen kısımlar gönderilecektir.
Örneğin, istemci şu sorguyu gönderdi diyelim:
query {
users {
name
email
}
}
Yukarıdaki örnekte çalışacak daha fazla alanımız var; ancak istemci yalnızca name ve email alanlarını istiyor. Bu, istemcinin çalıştığı GraphQL tür tanımlarımıza göre ele alındı. Bunu gerçekleşmesini Apollo sağlar.
Aynı kurallar, **src/resolvers/index.ts** dosyamızdaki her sorgu ve mutasyon için geçerli olacaktır.
createUser: async (
_: unknown,
{ name, email, age }: CreateUserInput
): Promise<User> => {
const userService = new UserService();
return await userService.createUser({ name, email, age });
},
createUser tür tanımında, istemcinin name, email ve age alanlarını geçebildiğini gördük. createUser çözücü işlevinde de aynı şeyi yapıyor ve veritabanı servisimizdeki createUser işlevini çağırıyoruz. Yanıt, istemcinin talep ettiği alanlara göre geri döndürülür.
GraphQL API'sini Derleyin ve Çalıştırın
Bu noktada GraphQL API oldukça iyi durumda olmalı. Bu uygulamayı derlemenin ve çalıştırmanın birkaç yolu var.
Örneğin, **package.json** dosyanıza aşağıdakileri ekleyebilirsiniz:
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "tsx src/index.ts",
"dev:watch": "tsx watch src/index.ts",
"watch": "tsc -w"
},
Bu yolu seçtiyseniz, projeyi derlemek için npm run build ve projeyi sunmaya başlamak için npm run start komutlarını çalıştırabilirsiniz. Varsayılan bağlantı noktası 3000'dir ve cURL ya da tercih ettiğiniz herhangi bir araçla test edilebilir.
Sonuç
Az önce, veritabanı olarak MongoDB ile TypeScript kullanarak bir GraphQL API'sinin nasıl oluşturulacağını gördünüz. Bu örnek basit olacak şekilde tasarlanmış olsa da, veritabanımızda CRUD işlemleri yapmak için sorguları ve mutasyonları nasıl inşa edeceğimizi gördük. MongoDB, bir GraphQL API'sinde kullanıldığında mükemmel bir eşleşmedir; çünkü üzerinde çalıştığınız veriler, baştan sona benzer şekilde biçimlendirilmiştir. Örneğin, istemci JSON'a benzeyen bir sorgu çalıştırır. Sorgudan geçen veriler, en az biçimlendirme ve ayarlamayla kullanılabilir ve aynı şekilde veritabanına gönderildiğinde ve veritabanından alındığında da geçerlidir. Deneyim akıcıdır; böylece verilerinizi veritabanını tatmin etmek için manipüle etmeye daha az, kullanıcı deneyimine daha çok odaklanabilirsiniz.
Bu eğitimde herhangi bir noktada takıldıysanız, GitHub'daki bitmiş projeye göz atmayı unutmayın.
SSS
Neden GraphQL kullanmalıyım?
GraphQL harikadır; çünkü bir API'yi bir veritabanını sorgular gibi sorgulayabilir ve karşılığında yalnızca ihtiyacınız olanı isteyebilirsiniz. Bu da istemci için işleri hafif ve verimli kılar.
GraphQL için tek seçenek Apollo mu?
Apollo, GraphQL API'lerini oluşturmayı çok kolaylaştırır; ancak tek seçenek değildir. Yine de diğer seçenekler bu eğitimin kapsamı dışındadır.
Neden GraphQL ile MongoDB kullanmalıyım?
Her ikisi de JSON benzeri veri formatlarıyla çalışır; bu nedenle bilgi veritabanından API'ye ve istemciye akarken veri yapıları arasında sürekli dönüşüm yapmanız gerekmez.
Bir çözücü ne yapar?
Çözücü (resolver), şemanızdaki belirli bir alan için GraphQL'e verilerin nasıl getirileceğini veya değiştirileceğini söyleyen bir işlevdir.
Sorgu (query) ve mutasyon (mutation) arasındaki fark nedir?
Sorgular (query) verileri okuma/getirme içindir (GET istekleri gibi), mutasyonlar ise veri oluşturma, güncelleme veya silme içindir (POST, PUT, DELETE gibi).

Nic Raboy , MongoDB'de Geliştirici İlişkileri Lideridir ve MongoDB'yi projelerine dahil etmelerinde geliştiricilerin başarılı olmasına yardımcı olacak harika içerikler üreten Python, Java, C# ve PHP geliştiricilerinden oluşan bir ekibi yönetir. Golang ve JavaScript konusunda deneyime sahiptir ve sık sık geliştirme maceraları hakkında yazılar yazar.
