مقدمه ای بر آموزش Apollo Server

Apollo Server یک کتابخانه است که به شما کمک می کند یک schemaی GraphQL را به یک سرور HTTP در Node.js متصل کنید. استفاده از Apollo Server با همه سرورهای محبوب HTTP مانند Express ، Connect ، Hapi ، Koa ، Restify و Lambda امکان پذیر است. در این آموزش می آموزید که چگونه Apollo Server را با Node.js و Express راه اندازی کنید. بیایید شروع کنیم.

وب سایت پروژه Apollo Server را می توانید در https://www.apollographql.com/servers پیدا کنید:

راه اندازی پروژه

برای ایجاد یک پروژه جدید Node.js، بیایید ابتدا یک دایرکتوری جدید برای پروژه ایجاد کنیم:

$ mkdir node-apollo

وارد دایرکتوری جدید شوید:

$ cd node-apollo

و سپس با استفاده از دستور npm فایل جدید package.json را مقدار دهی اولیه کنید:

$ npm init -y

 

راه اندازی Babel

برای اینکه بتوانیم از ویژگی های ES6 در کد Node.js خود استفاده کنیم، باید کامپایلر Babel را برای پروژه خود تنظیم کنیم. فعال کردن Babel بسیار آسان است، ابتدا باید بسته های babel-cli و babel-preset-env را از طریق NPM نصب کنید:

$ npm install --save-dev babel-cli babel-preset-env

پس از نصب، باید یک فایل .babelrc به پروژه اضافه کنید و محتوای زیر را اضافه کنید:

{
    "presets": ["env"]
  }

اکنون می توانیم از کامپایلر Babel برای پروژه استفاده کنیم.

نصب babel-watch

استارت کردن کامپایلر Babel به صورت دستی پس از هر تغییر کد ناخوشایند است. با استفاده از babel-watch می توانیم این کار را خودکار کنیم و علاوه بر این اطمینان حاصل کنیم که پروسس سرور Node.js نیز مجددا راه اندازی می شود. بیایید babel-watch را به عنوان dependency به پروژه خود اضافه کنیم:

$ npm install babel-watch --save-dev

سپس از babel-watch در فایل package.json خود در بخش scripts به صورت زیر استفاده کنید:

  "scripts": {
    "dev": "babel-watch server.js"
  }

بعداً، وقتی سرور را در فایل server.js پیاده سازی کردیم، این امکان را برای ما فراهم می کند تا با استفاده از دستور زیر سرور را راه اندازی کنیم:

$ npm run dev

سپس این دستور babel-watch را اجرا می کند که سرور Node.js را راه اندازی کرده و مطمئن می شود Babel tarnspiler در حالت watch نیز در حال اجرا است. هر زمان که کد پیاده سازی تغییر می کند، کامپایل به صورت خودکار انجام می شود و سرور Node.js دوباره راه اندازی می شود، بنابراین همه چیز بدون نیاز به انجام مراحل به صورت دستی، به روز می شود.

 

نصب Express و Apollo Server

از آنجا که می خواهیم از فریمورک Express برای پیاده سازی سرور Node.js GraphQL استفاده کنیم، ابتدا package مربوطه را نصب می کنیم:

$ npm install express

علاوه بر این، باید اطمینان حاصل کنیم که dependency های graphql، graphql-tools و apollo-server-express نصب شده اند:

npm install graphql graphql-tools apollo-server-express

 

پیاده سازی سرور

پیاده سازی پایه ای یک سرور Node.js/Express

برای اینکه بتوانیم سرور را پیاده سازی کنیم، ابتدا یک فایل server.js به پروژه خود اضافه می کنیم:

$ touch server.js

 

سپس می توانید این فایل را در ویرایشگر مورد علاقه خودتان باز کرده و کد زیر را اضافه کنید:

import express from 'express';

const app = express();
app.get('/', (req, res) => res.send('Hello World!'));
app.listen(4000, () => console.log(`Express server running on port 4000`));

 

با اجرای دستور زیر، فرآیند سرور را شروع کنید

$ npm run dev

 

بعد این باید بتوانید خروجی زیر را در command line مشاهده کنید:

اگر اکنون در مرورگر به http://localhost:4000 دسترسی دارید، باید ریسپانس زیر را از سرور Node.js/Express دریافت کنید.

 

اضافه کردن endpoint برای GraphQL

اکنون که سرور اصلی Node.js/Express در حال اجرا است، می توانیم با استفاده از Apollo Server یک endpoint برای GraphQL اضافه کنیم. بنابراین ما باید کد داخل فایل server.js را به شکل زیر تغییر دهیم:

import express from 'express';
import bodyParser from 'body-parser';
import { graphqlExpress } from 'apollo-server-express';

const app = express();

app.use('/graphql', bodyParser.json(), graphqlExpress({}));

app.listen(4000, () => console.log(`Express server running on port 4000`));

ابتدا باید اطمینان حاصل کنیم که graphqlExpress از کتابخانه apollo-server-express ایمپورت شده است. بعد می توانیم با فراخوانی app.use، میان افزار graphqlExpress را به نقطه پایانی graphql/ وصل کنیم. علاوه بر این ما همچنین از میان افزار bodyParser.json استفاده می کنیم.

فراخوانی graphqlExpress به یک شی configuration به عنوان یک پارامتر نیاز دارد. در حال حاضر این شی خالی است. در مراحل زیر از این شی پیکربندی برای تهیه GraphQL middleware با schema و resolvers استفاده می شود.

 

اضافه کردن Endpoint برای GraphiQL

بیایید endpoint دوم GraphiQL را به سرور Express اضافه کنیم. GraphiQL یک GraphQL IDE تعاملی گرافیکی در مرورگر است. با استفاده از این ابزار می توانید مستقیماً درخواستهای خود را در مرورگر بنویسید.


    import express from 'express';
    import bodyParser from 'body-parser';
    import { graphqlExpress, graphiqlExpress } from 'apollo-server-express';

    const app = express();

    app.use('/graphiql', graphiqlExpress({
        endpointURL: '/graphql'
    }));

    app.use('/graphql', bodyParser.json(), graphqlExpress({}));

    app.listen(4000, () => console.log(`Express server running on port 4000`));

برای افزودن GraphiQL endpoint، باید میان افزار graphiqlExpress را از کتابخانه apollo-server-express وارد کنیم. با فراخوانی app.use یکبار دیگر endpoint مربوطه به سرور اضافه می شود:


    app.use('/graphiql', graphiqlExpress({
        endpointURL: '/graphql'
    }));

میان افزار graphiqlExpress به gaphiql endpoint پیوست شده است. شی پیکربندی که به graphiqlExpress منتقل می شود حاوی یک ویژگی است: endpointURL. مقدار این ویژگی باید در GraphQL endpoint ما تنظیم شود که باید همراه GraphiQL استفاده شود.

اگر اکنون می خواهید به لینک http://localhost:4000/graphiql در مرورگر دسترسی پیدا کنید، باید بتوانید رابط کاربری GraphiQL را مشاهده کنید:


در سمت راست، یک پیام خطا دریافت می کنید، مبنی بر اینکه schemaی GraphQL یافت نشد. مرحله بعدی افزودن schemaی GraphQL به سرور است.

اضافه کردن یک Schema

برای پیکربندی صحیح سرور GraphQL ابتدا باید یک schema اضافه کنیم. برای این کار بیایید یک فایل جدید در دایرکتوری پروژه ایجاد کنیم:

 

$ touch schema.js

 

تعریف schema زیر را در داخل آن فایل وارد کنید:


    const typeDefs = [`
        type Course {
            id: Int
            title: String
            author: String
            description: String
            topic: String
            url: String
        }
        type Query {
            allCourses: [Course]
            course(id: Int!): Course
        }
    `];

این schema شامل یک type عادی به نام Course و دو نوع query به نام های  allCourses و course است. نوع Course در مجموع از شش ویژگی تشکیل شده است. از queryهای تعریف شده می توان برای بازیابی همه دوره های موجود (از طریق کوئری allCourses یا بازیابی فقط یک دوره با ID (از طریق کوئری course) استفاده کرد.

اضافه کردن Resolverها

مورد بعدی که باید اضافه کنیم resolver ها هستند. Resolvers توابعی هستند که به یک query یا mutation اختصاص داده می شوند و حاوی منطقی هستند که برای بازیابی و برگرداندن داده های مربوطه لازم است. بیایید فایل دیگری را به دایرکتوری اضافه کنیم:

 

$ touch resolvers.js

 

بعد کد زیر را در فایل تازه ایجاد شده وارد کنید:


    var coursesData = [
        {
            id: 1,
            title: 'The Complete Node.js Developer Course',
            author: 'Andrew Mead, Rob Percival',
            description: 'Learn Node.js by building real-world applications with Node, Express, MongoDB, Mocha, and more!',
            topic: 'Node.js',
            url: 'https://codingthesmartway.com/courses/nodejs/'
        },
        {
            id: 2,
            title: 'Node.js, Express & MongoDB Dev to Deployment',
            author: 'Brad Traversy',
            description: 'Learn by example building & deploying real-world Node.js applications from absolute scratch',
            topic: 'Node.js',
            url: 'https://codingthesmartway.com/courses/nodejs-express-mongodb/'
        },
        {
            id: 3,
            title: 'JavaScript: Understanding The Weird Parts',
            author: 'Anthony Alicea',
            description: 'An advanced JavaScript course for everyone! Scope, closures, prototypes, this, build your own framework, and more.',
            topic: 'JavaScript',
            url: 'https://codingthesmartway.com/courses/understand-javascript/'
        }
    ];

    const resolvers = {
        Query: {
            allCourses: () => {
                return coursesData;
            },
            course: (root, {id}) => {
                return coursesData.filter(course => {
                    return course.id === id;
                })[0];
            }
        }
    }

    export default resolvers;

اول از همه ما در حال تعیین یک آرایه coursesData با سه نمونه رکورد هستیم که به عنوان data store استفاده خواهد شد.

بعلاوه کد حاوی شی resolvers است که شامل اختصاص دو arrow function به کوئری ها است. تابعی که به کوئری allCourses اختصاص داده شده است، فقط وظیفه بازگرداندن آرایه coursesData را دارد. تابع اختصاص داده شده به کوئری course استفاده از روش فیلتر آرایه coursesData برای بازیابی course با ID درخواستی و سپس بازگرداندن این دوره است.

 شی resolvers سرانجام export می شود تا بتوانیم دوباره آن را در پرونده schema.js وارد کنیم:


    import { makeExecutableSchema } from 'graphql-tools';
    import resolvers from './resolvers';

    const typeDefs = [`
        ...
    `];

    const schema = makeExecutableSchema({
        typeDefs,
        resolvers
    });

    export default schema;

اکنون تعریف schema (typeDefs) و شی resolvers هر دو در دسترس هستند تا بتوان از تابع makeExecutableSchema فراخوانی کرد تا این schema برای تنظیم endpoint سرور GraphQL با Apollo Server قابل استفاده باشد.

بنابراین makeExecutableSchema ابتدا از کتابخانه graphql-tools وارد (import) می شود. این تابع با یک پارامتر فراخوانی می شود: یک شی شامل typeDefs و resolvers. نتیجه اجرا شده ی schema در schema ذخیره می شود و export می شود، بنابراین می توانیم از آن در server.js با استفاده از دستور import زیر در این فایل استفاده کنیم:

import schema from './schema';

اکنون می توانیم schema را به شی پیکربندی (configuration) که به فراخوان middleware (میان افزار) graphqlExpress منتقل شده است، پاس بدهیم:

app.use('/graphql', bodyParser.json(), graphqlExpress({schema}));

با پیوستن schema به endpoint، اکنون پیکربندی سرور را کامل کردیم. بیایید این endpoint را با استفاده از GraphiQL در مرحله بعدی آزمایش کنیم.

اجرای Query ها

بازیابی کلیه دوره ها

با باز کردن GraphiQL در مرورگر با استفاده از لینک http://localhost:4000/graphiql  و وارد کردن کوئری GraphQL زیر می توانیم لیست کامل دوره ها را بازیابی کنیم:


    {
        allCourses{
            id
            title
            author
            description
            topic
            url
        }
    }

نتیجه باید مطابق با آنچه در تصویر زیر می بینید مطابقت داشته باشد:

بازیابی یک دوره با ID

در مرحله بعدی، بیایید از query دوم خود استفاده کنیم و دوره خود را با ID آن انتخاب کنیم:


    {
        course(id: 1){
            id
            title
            author
            description
            topic
            url
        }
    }

در نتیجه شما باید بتوانید دوره دارای ID با مقدار ۱ را در قسمت خروجی مشاهده کنید:

 

سعید نصیری
سعید نصیری

من برنامه نویس لاراول، PHP و طراح سایت هستم. برنامه نویسی موبایل و تولید اپلیکیشن های موبایل نیز بخش دیگری از توانایی های فردی من هست. تقریبا ده دوازده سالی تجربه مستمر در زمینه طراحی سایت دارم و نزدیک به یک سال هم میشه که در برنامه نویسی موبایل وارد شده ام.

× در حال پاسخ به: