خبر و ترفند روز

خبر و ترفند های روز را اینجا بخوانید!

استفاده از NestJS و MongoDB برای ساخت GraphQL API

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 ساخت یافته ایجاد کنید. شما می توانید از اصول تزریق وابستگی برای کنترل نحوه ارتباط بخش های یک برنامه با یکدیگر استفاده کنید.

پیاده سازی GraphQL با NestJS و MongoDB

قبل از ساختن یک API با NestJS و GraphQL، باید وابستگی‌های مناسبی در دسترس داشته باشید. شما باید Node.js و NestJS را نصب کنید که می توانید با اجرای npm i -g @nestjs/cli نصب کنید.

مثال زیر یک برنامه ساده است که اطلاعات مربوط به کتاب ها را ذخیره می کند. برای ایجاد یک برنامه NestJS جدید، دستور زیر را در ترمینال خود اجرا کنید:

nest new <app-name>

به دایرکتوری برنامه تولید شده () بروید و وابستگی های آن را با دستور زیر نصب کنید:

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

دو رویکرد اصلی برای ساخت GraphQL API وجود دارد که عبارتند از:

  1. رویکرد Schema-first: جایی که API را در فایل های تعریف طرحواره یا SDL توصیف می کنید و NestJS بر اساس آنها تعاریف Typescript را ایجاد می کند.
  2. رویکرد Code-first: جایی که کوئری‌ها، جهش‌ها و سایر قابلیت‌های GraphQL را با استفاده از کلاس‌های Typescript و دکوراتورها تعریف می‌کنید و NestJS فایل‌های SDL را بر اساس آنها تولید می‌کند.
مطلب مرتبط:   نحوه انتشار رویدادها برای برقراری ارتباط بین اجزای Vue

مثال زیر نحوه استفاده از رویکرد کد اول را توضیح می دهد.

ابتدا باید GraphQL را در AppModule خود مقداردهی کنید و آن را به پایگاه داده MongoDB متصل کنید:

// app.module.ts
import { Module } from '@nestjs/common';
import { GraphQLModule as NestGraphQLModule } from '@nestjs/graphql';
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { join } from 'path';
import { MongooseModule } from '@nestjs/mongoose';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule, ConfigService } from '@nestjs/config';
import mongodbConfig from './config/mongodb.config';

@Module({
  imports: [
     ConfigModule.forRoot({
       load: [mongodbConfig],
       isGlobal: true
    }),
    NestGraphQLModule.forRootAsync<ApolloDriverConfig>({
      driver: ApolloDriver,
      inject: [ConfigService],
      useFactory: async (configService: ConfigService) => ({
        autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
        installSubscriptionHandlers: true,
        sortSchema: true,
        playground: true,
        debug: configService.get<boolean>("DEBUG"),
        uploads: false,
      }),
    }),
    MongooseModule.forRootAsync({
      inject: [ConfigService],
      useFactory: async (configService: ConfigService) => ({
        uri: configService.get('MONGO_URI')
      })
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})

export class AppModule {}

این ماژول GraphQLModule را از @nestjs/graphql و MongooseModule را از @nestjs/mongoose وارد می کند که به اتصال به MongoDB کمک می کند. ویژگی autoSchemaFile مکان فایل طرحواره تولید شده را مشخص می کند و خاصیت sortSchema تضمین می کند که فیلدها را بر اساس حروف الفبا مرتب می کند.

در اینجا فایل پیکربندی MongoDB شما باید چگونه باشد:

import { registerAs } from '@nestjs/config';

/**
 * Mongo database connection config
 */
export default registerAs('mongodb', () => {
  const {
    MONGO_URI
  } = process.env;

  return {
    uri: `${MONGO_URI}`,
  };
});

تعریف طرحواره GraphQL

پس از راه‌اندازی اتصالات GraphQL و MongoDB، باید کوئری‌ها و جهش‌های GraphQL را برای تولید یک فایل طرحواره (schema.gql) تعریف کنید.

نوشتن پرس و جو

در رویکرد کد اول، شما یک مدل با استفاده از دکوراتور ObjectType ایجاد می کنید. بعداً این مدل را به یک نوع GraphQL تبدیل خواهید کرد.

برای مثال:

// book.model.ts
import { Field, ObjectType } from '@nestjs/graphql';
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type BookDocument = Book & Document;

@ObjectType()
@Schema()
export class Book {
    @Field()
    title: string;

    @Field()
    author: string;

    @Field()
    publishedDate: boolean;
}

export const BookSchema = SchemaFactory.createForClass(Book);

GraphQL، به طور پیش فرض، نمی تواند از طرحواره های ایجاد شده استفاده کند. برای کاربردی کردن آنها، به یک سرویس Resolver نیاز دارید که حاوی توابع برای اجرای انواع GraphQL باشد. می توانید این کار را با Decorator Resolver انجام دهید.

// books.resolver.ts
import { Resolver, Query, Mutation, Args, ID } from '@nestjs/graphql';
import { Book } from './book.model';
import { BookService } from './books.service';

@Resolver(() => Book)
export class BookResolver {
    constructor(private readonly bookService: BookService) { }

    @Query(() => [Book])
    async books(): Promise<Book[]> {
        return this.bookService.findAll();
    }

    @Query(() => Book)
    async book(@Args('id', { type: () => ID }) id: string): Promise<Book> {
        return this.bookService.findOne(id);
    }
}

می توانید BookService وارد شده در بالا را به صورت زیر پیاده سازی کنید:

// books.service.ts
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Book, BookDocument } from './book.model';

@Injectable()
export class BookService {
    constructor(@InjectModel(Book.name) private bookModel: Model<BookDocument>) { }

    async findAll(): Promise<Book[]> {
        return this.bookModel.find().exec();
    }

    async findOne(id: string): Promise<Book> {
        return this.bookModel.findById(id).exec();
    }
}

همچنین باید BookResolver را به لیست ارائه دهندگان در books.module.ts اضافه کنید.

import { Module } from "@nestjs/common";
import { MongooseModule } from "@nestjs/mongoose";
import { BookService } from './books.service';
import { BookResolver } from './books.resolver';
import { Book, BookSchema } from './book.model';

@Module({
    providers: [
        BookService,
        BookResolver
    ],
    imports: [MongooseModule.forFeature([
        {
            name: Book.name,
            schema: BookSchema,
        },
    ]),
  ],
})

export class BooksModule {}

کار با جهش

در حالی که از یک کوئری برای بازیابی داده ها در GraphQL استفاده می کنید، جهش ها داده ها را در پایگاه داده ایجاد یا به روز می کنند. برای ایجاد جهش، باید داده های کاربران را بپذیرید. دکوراتور InputType که یک کلاس را به نوع ورودی GraphQL تبدیل می کند، در اینجا مفید است.

// book.input.ts
import { InputType, Field } from '@nestjs/graphql';

@InputType()
export class BookInput {
    @Field()
    title: string;

    @Field()
    author: string;

    @Field()
    publishedDate: boolean
}

اکنون می توانید books.resolver.ts را به شکل زیر به روز کنید:

import { Resolver, Query, Mutation, Args, ID } from '@nestjs/graphql';
import { Book } from './book.model';
import { BookService } from './books.service';
import { BookInput } from './book.input';

@Resolver(() => Book)
export class BookResolver {
    constructor(private readonly bookService: BookService) { }

    @Mutation(() => Book)
    async createBook(@Args('input') input: BookInput): Promise<Book> {
        return this.bookService.create(input);
    }

    @Mutation(() => Book)
    async updateBook(
        @Args('id', { type: () => ID }) id: string,
        @Args('input') input: BookInput,
    ): Promise<Book> {
        return this.bookService.update(id, input);
    }

    @Mutation(() => Book)
    async deleteBook(@Args('id', { type: () => ID }) id: string): Promise<Book> {
        return this.bookService.delete(id);
    }
}

و books.service.ts مانند این:

import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Book, BookDocument } from './book.model';

@Injectable()
export class BookService {
    constructor(@InjectModel(Book.name) private bookModel: Model<BookDocument>) { }

    async create(book: Book): Promise<Book> {
        const newBook = new this.bookModel(book);
        return newBook.save();
    }

    async update(id: string, book: Book): Promise<Book> {
        return this.bookModel.findByIdAndUpdate(id, book, { new: true }).exec();
    }

    async delete(id: string): Promise<Book> {
        return this.bookModel.findByIdAndDelete(id).exec();
    }
}

دکوراتور @Mutation یک تابع را به عنوان یک نوع جهش علامت‌گذاری می‌کند و تزئین‌کننده @Args هر ورودی ارسال شده به تابع را می‌گیرد.

مطلب مرتبط:   چگونه با استفاده از پایتون یک بازی سنگ، کاغذ، قیچی بسازیم

در نهایت، باید BooksModule را به AppModule وارد کنید تا کاربردی شود. همانطور که در زیر مشاهده می کنید، باید BooksModule را به forRootAsync منتقل کنید.

import { BooksModule } from './books/books.module';
/**
 * other imports
*/

@Module({
  imports: [
     ConfigModule.forRoot({
       load: [mongodbConfig],
       isGlobal: true
    }),
    NestGraphQLModule.forRootAsync<ApolloDriverConfig>({
      driver: ApolloDriver,
      inject: [ConfigService],
      useFactory: async (configService: ConfigService) => ({
        autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
        installSubscriptionHandlers: true,
        sortSchema: true,
        playground: true,
        debug: configService.get<boolean>("DEBUG"),
        uploads: false,
      }),
    }),
    MongooseModule.forRootAsync({
      inject: [ConfigService],
      useFactory: async (configService: ConfigService) => ({
        uri: configService.get('MONGO_URI')
      })
    }),
    BooksModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})

export class AppModule {}

می توانید کد را با اجرای npm run start:dev در ترمینال خود آزمایش کنید و برنامه شما باید با موفقیت در پورت 3000 شروع شود.

localhost:3000/graphql را در مرورگر خود باز کنید تا رابط Graphiql را نشان دهید که در آن می توانید پرس و جوها و جهش ها را آزمایش کنید. در اینجا یک مثال است که یک پرس و جو را نشان می دهد:

مثال پرس و جو در graphQL

و در اینجا نمونه ای از یک جهش وجود دارد:

نمونه درخواست جهش graphiql

با NestJS و GraphQL APIهای کارآمد بسازید

ساخت یک GraphQL API در NestJS با MongoDB با استفاده از Mongoose شامل تعریف یک طرح برای GraphQL API، یک طرح برای مدل Mongoose، یک سرویس برای تعامل با پایگاه داده، و یک Resolver برای نگاشت عملیات GraphQL به روش‌های سرویس است.

NestJS دارای عملکرد داخلی برای ساخت APIها است، از جمله دکوراتورها برای تعریف مسیرها، محافظ برای محافظت از آنها و میان افزارها برای رسیدگی به درخواست ها و پاسخ ها. همچنین از پایگاه داده های دیگری مانند PostgreSQL، MySQL و SQLite و همچنین کتابخانه های دیگر GraphQL مانند Apollo و TypeGraphQL پشتیبانی می کند.

مطلب مرتبط:   چگونه یک برنامه مدیریت فایل ساده در فرم های ویندوز بسازیم