בנה ממשק API משלך באמצעות טכנולוגיות האינטרנט הפופולריות הללו.

GraphQL ו-NestJS יוצרים שותפות מצוינת, ומעניקים לך בסיס איתן לממשקי ה-API שלך ומסגרת קלה לשימוש לבניית יישומי אינטרנט ניתנים להרחבה. השילוב מושלם לבניית אפליקציות מוכנות לייצור, ושניהם הם כלים רלוונטיים מאוד באקוסיסטם הטכנולוגי של ימינו.

גלה עוד על איך אתה יכול לבנות API באמצעות שני המוצרים.

מה זה GraphQL?

GraphQL היא שפת שאילתת נתונים ומניפולציה אתה יכול להשתמש כדי לבנות ממשקי API בצורה יותר מדויקת ותמציתית. GraphQL מספקת תיאור מלא והולם של הנתונים הקיימים ב-API ונותנת כוח ללקוח לקבל את הנתונים המדויקים הדרושים.

GraphQL מספקת תכונות רבות שחסרות ממשקי API של REST, החל משאילתות נתונים מדויקות ועד כלי מפתח טובים יותר, כמו graphiql עוֹרֵך. זה גם מאפשר לך לבקש משאבים מרובים באמצעות בקשה אחת.

מה זה NestJS?

NestJS היא מסגרת פרוגרסיבית של Node.js שבה אתה יכול להשתמש כדי לבנות יישומים ניתנים להרחבה ויעילים בצד השרת. NestJS מספקת תוספים רבים, לצד כלים לפיתוח מהיר וקל כולל תמיכת GraphQL, GRPC, WebSockets וכו'.

NestJS ידועה במערכת האקולוגית בזכות מבנה הפרויקט האופטימלי שלה באמצעות מודולים, בקרים, שירותים וסכמות. ה-CLI המובנה שלו מאפשר לך ליצור ארכיטקטורת API מובנית. אתה יכול להשתמש

instagram viewer
עקרונות הזרקת תלות לשלוט באופן שבו חלקי האפליקציה מתקשרים זה עם זה.

הטמעת GraphQL עם NestJS ו-MongoDB

לפני בניית ממשק API עם NestJS ו-GraphQL, תצטרך לקבל את התלות הנכונות. אתה צריך כדי להתקין את Node.js ו-NestJS, שתוכל להתקין על ידי הפעלה npm i -g @nestjs/cli.

הדוגמה הבאה היא אפליקציה פשוטה המאחסנת מידע על ספרים. הפעל את הפקודה הבאה בטרמינל שלך כדי ליצור יישום NestJS חדש:

קן חדש 

נווט אל ספריית היישום שנוצר () והתקן את התלות שלו עם הפקודה הבאה:

$ npm install --save @nestjs/config @nestjs/graphql graphql-tools graphql \
 @nestjs/apollo apollo-server-express @nestjs/mongoose @types/graphql

ישנן שתי גישות עיקריות לבניית ממשקי API של GraphQL, כלומר:

  1. גישה סכימה ראשונה: שבו אתה מתאר את ה-API בקבצי הגדרות סכימה או SDL, ו-NestJS מייצר הגדרות Typescript המבוססות עליהם.
  2. גישה של קוד ראשון: שבו אתה מגדיר שאילתות, מוטציות ופונקציונליות GraphQL אחרות באמצעות מחלקות Typescript ומעצבים, ו-NestJS מייצר קבצי SDL על סמך אותם.

הדוגמה הבאה מתארת ​​כיצד להשתמש בגישה של קוד ראשון.

ראשית, עליך לאתחל את GraphQL ב- AppModule ו חבר אותו למסד נתונים של MongoDB:

// app.module.ts
יְבוּא { מודול } מ'@nestjs/common';
יְבוּא { GraphQLModule כפי ש NestGraphQLModule } מ'@nestjs/graphql';
יְבוּא { ApolloDriver, ApolloDriverConfig } מ'@nestjs/apollo';
יְבוּא { הצטרף } מ'נָתִיב';
יְבוּא { MongooseModule } מ'@nestjs/mongoose';
יְבוּא { AppController } מ'./app.controller';
יְבוּא { AppService } מ'./app.service';
יְבוּא { ConfigModule, ConfigService } מ'@nestjs/config';
יְבוּא mongodbConfig מ'./config/mongodb.config';

@מודול({
יבוא: [
ConfigModule.forRoot({
טען: [mongodbConfig],
isGlobal: נָכוֹן
}),
NestGraphQLModule.forRootAsync({
נהג: ApolloDriver,
inject: [ConfigService],
useFactory: אסינכרון (configService: ConfigService) => ({
autoSchemaFile: join (process.cwd(), 'src/schema.gql'),
installSubscriptionHandlers: נָכוֹן,
sortSchema: נָכוֹן,
גן שעשועים: נָכוֹן,
באגים: configService.get<בוליאני>("לנפות"),
העלאות: שֶׁקֶר,
}),
}),
MongooseModule.forRootAsync({
inject: [ConfigService],
useFactory: אסינכרון (configService: ConfigService) => ({
uri: configService.get('MONGO_URI')
})
}),
],
בקרים: [AppController],
ספקים: [AppService],
})

יְצוּאמעמד AppModule {}

מודול זה מייבא את GraphQLModule מ @nestjs/graphql וה MongooseModule מ @nestjs/mongoose שעוזר להתחבר ל- MongoDB. ה autoSchemaFile מאפיין מציין את המיקום של קובץ הסכימה שנוצר, ואת ה- sortSchema מאפיין מבטיח שהוא מסדר את השדות בסדר אלפביתי.

הנה מה MongoDB שלך תצורה הקובץ צריך להיראות כך:

יְבוּא { registerAs } מ'@nestjs/config';

/**
 * תצורת חיבור מסד הנתונים של Mongo
 */
יְצוּאבְּרִירַת מֶחדָל registerAs('מונגודב', () => {
const {
MONGO_URI
} = process.env;

לַחֲזוֹר {
אורי: `${MONGO_URI}`,
};
});

הגדרת סכמת GraphQL

לאחר הגדרת חיבורי GraphQL ו-MongoDB, עליך להגדיר שאילתות ומוטציות GraphQL ליצירת סכימה (schema.gql) הקובץ.

כתיבת שאילתות

בתוך ה גישה קוד ראשון, אתה יוצר מודל באמצעות ה ObjectType מְעַצֵב. מאוחר יותר תהפוך את המודל הזה לסוג GraphQL.

לדוגמה:

// book.model.ts
יְבוּא { Field, ObjectType } מ'@nestjs/graphql';
יְבוּא { Prop, Schema, SchemaFactory } מ'@nestjs/mongoose';
יְבוּא { מסמך } מ'נְמִיָה';

יְצוּאסוּג BookDocument = ספר ומסמך;

@ObjectType()
@סכֵימָה()
יְצוּאמעמד ספר {
@שדה()
כותרת: חוּט;

@שדה()
מְחַבֵּר: חוּט;

@שדה()
תאריך פרסום: בוליאני;
}

יְצוּאconst BookSchema = SchemaFactory.createForClass (ספר);

GraphQL, כברירת מחדל, לא יכול להשתמש בסכימות שנוצרו. כדי להפוך אותם לפונקציונליים, אתה צריך שירות פותר המכיל את הפונקציות לביצוע סוגי GraphQL. אתה יכול לעשות זאת עם פותר מְעַצֵב.

// books.resolver.ts
יְבוּא { Resolver, Query, Mutation, Args, ID } מ'@nestjs/graphql';
יְבוּא { ספר } מ'./book.model';
יְבוּא { שירות ספרים } מ'./books.service';

@פותר(() => סֵפֶר)
יְצוּאמעמד BookResolver {
בַּנַאִי(פְּרָטִי bookService לקריאה בלבד: BookService) { }

@שאילתא(() => [סֵפֶר])
אסינכרון ספרים(): הַבטָחָה {
לַחֲזוֹרזֶה.bookService.findAll();
}

@שאילתא(() => סֵפֶר)
אסינכרון סֵפֶר(@Args('תְעוּדַת זֶהוּת', { סוּג: () => אני עשיתי: חוּט): הַבטָחָה {
לַחֲזוֹרזֶה.bookService.findOne (מזהה);
}
}

אתה יכול ליישם את BookService, מיובא לעיל, כדלקמן:

// books.service.ts
יְבוּא { הזרקה } מ'@nestjs/common';
יְבוּא { InjectModel } מ'@nestjs/mongoose';
יְבוּא { דגם } מ'נְמִיָה';
יְבוּא { ספר, BookDocument } מ'./book.model';

@ניתן להזרקה()
יְצוּאמעמד BookService {
בַּנַאִי(@InjectModel(Book.name) פְּרָטִי ספר דגם: דגם) { }

אסינכרון מצא הכל(): הַבטָחָה {
לַחֲזוֹרזֶה‎.bookModel.find().exec();
}

אסינכרון findOne (מזהה: חוּט): הַבטָחָה {
לַחֲזוֹרזֶה.bookModel.findById (id).exec();
}
}

אתה גם צריך להוסיף את BookResolver לרשימת הספקים ב books.module.ts.

יְבוּא { מודול } מ"@nestjs/common";
יְבוּא { MongooseModule } מ"@nestjs/mongoose";
יְבוּא { שירות ספרים } מ'./books.service';
יְבוּא { BookResolver } מ'./books.resolver';
יְבוּא { ספר, BookSchema } מ'./book.model';

@מודול({
ספקים: [
BookService,
BookResolver
],
ייבוא: [MongooseModule.forFeature([
{
שם: Book.name,
סכימה: BookSchema,
},
]),
],
})

יְצוּאמעמד BooksModule {}

עבודה עם מוטציות

בזמן שאתה משתמש בשאילתה כדי לאחזר נתונים ב-GraphQL, מוטציות יוצרות או מעדכנות נתונים במסד הנתונים. כדי ליצור מוטציות, עליך לקבל נתונים ממשתמשים. ה סוג קלט decorator, שהופך מחלקה לסוג קלט GraphQL, שימושי כאן.

// book.input.ts
יְבוּא { InputType, Field } מ'@nestjs/graphql';

@סוג קלט()
יְצוּאמעמד BookInput {
@שדה()
כותרת: חוּט;

@שדה()
מְחַבֵּר: חוּט;

@שדה()
תאריך פרסום: בוליאני
}

כעת תוכל לעדכן books.resolver.ts להיראות כך:

יְבוּא { Resolver, Query, Mutation, Args, ID } מ'@nestjs/graphql';
יְבוּא { ספר } מ'./book.model';
יְבוּא { שירות ספרים } מ'./books.service';
יְבוּא { BookInput } מ'./book.input';

@פותר(() => סֵפֶר)
יְצוּאמעמד BookResolver {
בַּנַאִי(פְּרָטִי bookService לקריאה בלבד: BookService) { }

@מוּטָצִיָה(() => סֵפֶר)
אסינכרון createBook(@Args('קֶלֶט') קלט: BookInput): הַבטָחָה {
לַחֲזוֹרזֶה.bookService.create (קלט);
}

@מוּטָצִיָה(() => סֵפֶר)
אסינכרון updateBook(
@Args('תְעוּדַת זֶהוּת', { סוּג: () => אני עשיתי: חוּט,
@Args('קֶלֶט') קלט: BookInput,
): הַבטָחָה {
לַחֲזוֹרזֶה.bookService.update (מזהה, קלט);
}

@מוּטָצִיָה(() => סֵפֶר)
אסינכרון מחק ספר(@Args('תְעוּדַת זֶהוּת', { סוּג: () => אני עשיתי: חוּט): הַבטָחָה {
לַחֲזוֹרזֶה.bookService.delete (מזהה);
}
}

ו books.service.ts ככה:

יְבוּא { הזרקה } מ'@nestjs/common';
יְבוּא { InjectModel } מ'@nestjs/mongoose';
יְבוּא { דגם } מ'נְמִיָה';
יְבוּא { ספר, BookDocument } מ'./book.model';

@ניתן להזרקה()
יְצוּאמעמד BookService {
בַּנַאִי(@InjectModel(Book.name) פְּרָטִי ספר דגם: דגם) { }

אסינכרון ליצור (ספר: ספר): הַבטָחָה {
const ספר חדש = חָדָשׁזֶה.bookModel (ספר);
לַחֲזוֹר newBook.save();
}

אסינכרון עדכון (מזהה: חוּט, ספר ספר): הַבטָחָה {
לַחֲזוֹרזֶה.bookModel.findByIdAndUpdate (מזהה, ספר, { חָדָשׁ: נָכוֹן }).exec();
}

אסינכרוןלִמְחוֹק(תְעוּדַת זֶהוּת: חוּט): הַבטָחָה {
לַחֲזוֹרזֶה.bookModel.findByIdAndDelete (id).exec();
}
}

ה @מוּטָצִיָה decorator מסמן פונקציה כסוג מוטציה ואת @Args decorator תופס כל קלט המועבר לפונקציה.

לבסוף, עליך לייבא את BooksModule לְתוֹך AppModule כדי להפוך אותו לפונקציונלי. כדאי גם לעבור את BooksModule ל עבור RootAsync כפי שנראה להלן.

יְבוּא { BooksModule } מ'./books/books.module';
/**
 *יבוא אחר
*/

@מודול({
יבוא: [
ConfigModule.forRoot({
טען: [mongodbConfig],
isGlobal: נָכוֹן
}),
NestGraphQLModule.forRootAsync({
נהג: ApolloDriver,
inject: [ConfigService],
useFactory: אסינכרון (configService: ConfigService) => ({
autoSchemaFile: join (process.cwd(), 'src/schema.gql'),
installSubscriptionHandlers: נָכוֹן,
sortSchema: נָכוֹן,
גן שעשועים: נָכוֹן,
באגים: configService.get<בוליאני>("לנפות"),
העלאות: שֶׁקֶר,
}),
}),
MongooseModule.forRootAsync({
inject: [ConfigService],
useFactory: אסינכרון (configService: ConfigService) => ({
uri: configService.get('MONGO_URI')
})
}),
BooksModule,
],
בקרים: [AppController],
ספקים: [AppService],
})

יְצוּאמעמד AppModule {}

אתה יכול לבדוק את הקוד על ידי ריצה npm run start: dev בטרמינל שלך, והיישום שלך אמור להתחיל בהצלחה ביציאה 3000.

לִפְתוֹחַ מארח מקומי: 3000/graphql בדפדפן שלך כדי להציג את גרפיקל ממשק שבו אתה יכול לבדוק שאילתות ומוטציות. הנה דוגמה שמציגה שאילתה:

והנה דוגמה למוטציה:

בנה ממשקי API יעילים עם NestJS ו-GraphQL

בניית GraphQL API ב-NestJS עם MongoDB באמצעות Mongoose כרוכה בהגדרת סכימה עבור GraphQL API, סכימה עבור מודל Mongoose, שירות לאינטראקציה עם מסד הנתונים, ופותר למיפוי פעולות GraphQL לשירות שיטות.

ל-NestJS פונקציונליות מובנית לבניית ממשקי API, כולל מעצבים להגדרת מסלולים, שומרים להגנה עליהם ותוכנות ביניים לטיפול בבקשות ותגובות. הוא תומך גם במסדי נתונים אחרים כמו PostgreSQL, MySQL ו- SQLite, כמו גם ספריות GraphQL אחרות כמו Apollo ו- TypeGraphQL.