اضافه کردن کوئری های پیچیده تر به GraphQL در ExpressJS

اضافه کردن کوئری های پیچیده تر به GraphQL در ExpressJS

اضافه کردن کوئری های پیچیده تر به GraphQL در ExpressJS

در جلسه ی قبل با شیوه ساخت یک سرور ساده با ExpressJS آشنا شدیم. در این جلسه قصد داریم تا در سرور ساخته شده کوئری های پیچیده تری را پیاده سازی کنیم.

تعریف پروژه:

در این قسمت سعی داریم تا پروژه ای برای مدیریت یک لیست از مخاطبین (Contacts) پیاده سازی کنیم. برای این کار از یک فایل model برای ذخیره و بازیابی اطلاعات استفاده می کنیم. پوشه ای به نام model بسازید و در آن فایل contact.js را ایجاد کنید. سپس کدهای زیر را در آن قرار دهید: 

let lastId = 3;
/**
 * id: Number
 * name: String
 * phone: String
 * address: Object
 */
const contacts = [
  {
    id: 1,
    name: 'reza',
    phone: '091234567890',
    address: {
      country: 'Iran',
      city: 'Tehran',
    },
  },
  {
    id: 2,
    name: 'ahmad',
    phone: '091234567890',
    address: {
      country: 'Iran',
      city: 'Isfahan',
    },
  },
];

class Contact {
  /**
   * index all contacts
   */
  static index() {
    return contacts;
  }

  /**
   * store new contact
   * @param {any} contact
   */
  static store(contact) {
    const newContact = {
      ...contact,
      id: lastId++,
    };

    contacts.push(newContact);

    return newContact;
  }

  /**
   * get contact with id
   * @param {string} id
   */
  static getById(id) {
    return contacts.find(c => c.id == id);
  }

  /**
   * delete contact with id
   * @param {string} id
   */
  static deleteById(id) {
    const contactIndex = contacts.findIndex(c => c.id == id);
    const contact = contacts[contactIndex];

    contacts.splice(contactIndex, 1);

    return contact;
  }
}

module.exports = Contact;

در قطعه کد بالا، مدلی به نام Contact تعریف شده است. از آنجایی که GraphQL روی پایگاه داده خاصی پیاده سازی نشده است، می توانید از هر پایگاه داده ای (مثل MongoDB یا MySQL) استفاده کنید. برای راحتی کار در قطعه کد بالا، از یک آرایه برای ذخیره داده ها استفاده شده است (بنابراین دقت داشته باشید با restart شدن پروژه، داده ها از بین خواهند رفت). در کلاس Contact ، چهار عملیات index، store، findById و deleteById تعریف شده است. همچنین هر contact دارای field های id، name، phone و address است.

ساخت نوع (type) برای Contact:

کد زیر را در فایل contact.js در آدرس graphql / types، قرار دهید:

const { GraphQLObjectType, GraphQLID, GraphQLString } = require('graphql');
const AddressType = require('./address');

const ContactType = new GraphQLObjectType({
  name: 'Contact',
  fields: {
    id: {
      type: GraphQLID,
    },
    name: {
      type: GraphQLString,
    },
    phone: {
      type: GraphQLString,
    },
    address: {
      type: AddressType,
    },
  },
});

module.exports = ContactType;

 در قطعه کد بالا، نوع Contact به کمک تابع GraphQLObjectType تعریف شده است. این تابع یک شیء می پذیرد که نیازمند دو property به نام های name و fields است. name، نام نوع و fields، field های نوع را مشخص می کند. هر یک از فیلد های نیز دارای یک type هستند که می تواند یک Scalar type یا یک Custom type باشد. به طور مثال در کد بالا، address یک Custom type است و بقیه field های دارای Scalar type هستند.

برای ساخت نوع Address، فایل address.js را در پوشه ی types بسازید و کدهای زیر را در آن قرار دهید:

const { GraphQLObjectType, GraphQLString } = require('graphql');
const AddressType = new GraphQLObjectType({
  name: 'address',
  fields: {
    country: {
      type: GraphQLString,
    },
    city: {
      type: GraphQLString,
    },
  },
});
module.exports = AddressType;

ساخت کوئری برای index و findById:

حال بیاید برای index و findById کوئری بسازیم. برای این کار، مانند جلسه ی قبل (که کوئری Hello  در آن ساخته شد) فایل Contacts.js را در پوشه ی queries بسازید و سپس کدهای زیر را در آن قرار دهید:

const { GraphQLList } = require('graphql');
const ContactType = require('../types/contact');
const Contact = require('../../models/contact');
const ContactsQuery = {
  type: GraphQLList(ContactType),
  resolve() {
    return Contact.index();
  },
};
module.exports = ContactsQuery;

همان طور که می بینید، یک کوئری برای دریافت لیست Contact ها تعریف کردیم. اگر دقت کنید، از آنجایی که نتیجه ی آن یک لیست است، از تابع GraphQLList استفاده شده است. همچنین این تابع یک ورودی می پذیرد که نوع هر یک از اجزای لیست را مشخص می کند. برای این کوئری از نوع ContactType استفاده شده است چرا که مقادیر این نوع را می گیرد. در متد resolver نیز به کمک مدل Contact، لیست مخاطبین را دریافت می کنیم.

به همین ترتیب، برای دریافت یک Contact می توانیم کوئری دیگری بسازیم. فایل Contact.js را در پوشه  queries بسازید و کدهای زیر را در آن قرار دهید:

const { GraphQLString, GraphQLNonNull } = require('graphql');
const ContactType = require('../types/contact');
const Contact = require('../../models/contact');
const ContactQuery = {
  type: ContactType,
  args: {
    contactId: {
      type: GraphQLNonNull(GraphQLString),
    },
  },
  resolve(parent, args) {
    return Contact.getById(args.contactId);
  },
};
module.exports = ContactQuery;

از آنجایی که این کوئری نیاز به یک ورودی دارد، می توانیم از property به نام args استفاده کرده و ورودی های خود را در آن تعریف کنیم. در مثال بالا، از contactId به عنوان ورودی استفاده شده است. نوع این ورودی نیز GraphQLString است. سپس برای استفاده از آن در متد resolver، از args به عنوان ورودی متد استفاده شده است.

حال برای اضافه کردن کوئری های ساخته شده، فایل Schema.js در پوشه ی graphql را باز کرده و آن را به صورت زیر تغییر دهید:

const { GraphQLSchema, GraphQLObjectType } = require('graphql');
const HelloQuery = require('./queries/Hello');
const ContactsQuery = require('./queries/Contacts');
const ContactQuery = require('./queries/Contact');
const Schema = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'RootQuery',
    fields: {
      hello: HelloQuery,
      contacts: ContactsQuery,
      contact: ContactQuery,
    },
  }),
});
module.exports = Schema;

برنامه را مجددا راه اندازی کرده و وارد مسیر localhost:3000/graphql شوید. حال می توانید کوئری های ساخته شده را در graphiql استفاده کنید:

بسیار عاالی! در جلسه بعد برای ذخیره و حذف یک مخاطب، mutation هایی را به پروژه اضافه خواهیم کرد.

سلامت و شاداب باشید.

نظرات
اگر login نکردی برامون ایمیلت رو بنویس: