آموزش مقدماتی GraphQL — از صفر تا صد
در این نوشته قصد داریم به GraphQL بپردازیم، اما اجازه بدهید پیش از آن قدری در مورد API صحبت کنیم. یکی از رایجترین اصطلاحها که امروزه بسیار بررسی میشود API است. افراد زیادی دقیقاً نمیدانند که API چیست. در واقع API اختصاری برای عبارت «رابط برنامهنویسی اپلیکیشن» (Application Programming Interface) است. این مفهوم چنان که نامش برمیآید، رابطی است که افراد مختلف یعنی برنامهنویسان، کاربران، مصرفکنندگان میتوانند با استفاده از دادهها با آن تعامل کنند. API را میتوان یک پیشخدمت دانست که شما از او یک نوشیدنی درخواست میکنید و او نوشیدنی مورد نظرتان را برای شما میآورد.
از زمان آغاز وب مدرن، ساخت API-ها دیگر چنان که قبلاً به نظر میرسید دشوار نبوده است. توسعهدهندگان، غالب افرادی که از API استفاده میکنند را تشکیل میدهند و از آن برای ساخت یک چیز یا صرفاً مصرف دادهها بهره میگیرند. بنابراین API باید تا حد امکان ساده و شهودی باشد. استفاده و یادگیری یک API با طراحی خوب بسیار ساده خواهد بود.
مدتهای مدیدی است که برای ساخت API ها از REST استفاده میشود. REST مشکلاتی نیز با خود همراه دارد. زمانی که API را با طراحی REST میسازید، با مشکلاتی مانند زیر مواجه میشوید:
- نقاط انتهایی زیادی خواهید داشت.
- بادگیری و درک API برای توسعه دهنگان بسیار دشوارتر خواهد بود.
- امکان واکشی اطلاعات کمتر یا بیشتر از حد نیاز وجود دارد.
فیسبوک برای حل این مسائل GraphQL را ساخته است. امروزه به باور بسیاری از توسعهدهندگان GraphQL یکی از بهترین روشهای ساخت API محسوب میشود. در این مقاله با اهمیت GraphQL و این که چرا باید یادگیری آن را آغاز کنید آشنا میشوید. بدین ترتیب با طرز کار GraphQL آشنا میشویم و چگونگی ایجاد یک API قدرتمند، با طراحی مناسب و کارآمد با استفاده از GraphQL را توضیح میدهیم.
احتمالاً قبلاً نام GraphQL به گوشتان خورده است، چون بسیاری از افراد از آن استفاده میکنند. از آنجا که GraphQL اوپنسورس است، جامعه آن به سرعت در حال توسعه است. اینک زمان آن رسیده است که شروع به یادگیری عملی طرز کار GraphQL و همه ویژگیهای خارقالعاده آن بکنیم.
GraphQL چیست؟
GraphQL یک زبان کوئری اوپنسورس است که از سوی فیسبوک توسعه یافته است. این زبان روشی کارآمد برای طراحی، ایجاد و مصرف API-ها در اختیار ما قرار میدهد و GraphQL اساساً یک جایگزین برای REST محسوب میشود.
GraphQL ویژگیهای زیادی مانند موارد زیر دارد:
- شما دادههایی که دوست دارید را مینویسید و دادههایی که دقیقاً میخواهید را به دست میآورید. دیگر نیازی به واکشی اطلاعات بیش از حد نیاز چنان که در REST مرسوم است نداریم.
- GraphQL یک نقطه انتهایی منفرد در اختیار ما قرار میدهد و دیگر نیازی به نسخه 2 یا نسخه 3 برای API یکسان وجود ندارد.
- GraphQL دارای «نوعبندی قوی» (strongly-typed) است و با استفاده از آن میتوان یک کوئری معتبر درون سیستم نوع GraphQL پیش از اجرا ساخت. GraphQL به ساخت API-های قدرتمند کمک میکند.
پس از این مقدمه کوتاه در مورد GraphQL، دلیل قدرت آن و این که چرا محبوبیت زیادی این روزها کسب کرده است، اگر میخواهید اطلاعات بیشتری در مورد آن کسب کنید، پیشنهاد میکنیم به مستندات موجود در وبسایت آن (+) مراجعه کنید.
سرآغاز
هدف اصلی این مقاله آشنا ساختن شما با GraphQL Server نیست و از این رو فعلاً نمیخواهیم زیاد در مورد آن بحث بکنیم. هدف این مقاله آن است که با طرز کار GraphQL در عمل آشنا شوید و از این رو میخواهیم از یک سرور GraphQL بدون نیاز به هیچ پیکربندی به نام Graphpack استفاده کنیم.
برای راهاندازی باید یک پوشه جدید ایجاد کنید. شما میتوانید نام آن را هر چیزی که دوست دارید بگذارید. ما نام آن را graphql-server میگذاریم. پنجره ترمینال را باز کرده و دستور زیر را در آن وارد کنید:
mkdir graphql-server
اینک باید npm یا yarn را روی سیستم خود نصب داشته باشید. اگر نمیدانید این دو چه هستند باید بگوییم که npm یا yarn نرمافزارهای مدیریت بسته برای زبان برنامهنویسی جاوا اسکریپت هستند.. در مورد Node.js نرمافزار مدیریت بسته پیشفرض npm است. درون پوشهای که ایجاد کردهاید دستور زیر را وارد کنید:
npm init –y
در صورتی که از yarn استفاده میکنید، دستور زیر را وارد کنید:
yarn init
npm یک فایل به نام package.json برای شما ایجاد میکند و همه وابستگیهایی که نصب کردهاید و دستورهای شما در آن قرار میگیرند.
بنابراین اکنون قصد داریم Graphpack یعنی تنها وابستگی مورد نیاز که در ادامه استفاده خواهیم کرد را نصب کنیم. Graphpack امکان ایجاد سرور GraphQL بدون هیچ گونه پیکربندی را فراهم میکند. از آنجا که ما تازه شروع به کار با GraphQL کردهایم این وضعیت به ما کمک میکند که به کار خود ادامه دهیم و در مورد پیکربندی سرور خود نگرانی نداشته باشیم.
در پنجره ترمینال درون پوشه root آن را به صورت زیر نصب کنید:
npm install --save-dev graphpack
اگر از yarn استفاده میکنید میتوانید با استفاده از دستور زیر، آن را نصب کنید:
yarn add --dev graphpack
پس از این که Graphpack نصب شد، به اسکریپتهای موجود در فایل package.json مراجعه کنید و کد زیر را در آن وارد نمایید:
1"scripts": {
2 "dev": "graphpack",
3 "build": "graphpack build"
4}
ما قصد داریم یک پوشه به نام src ایجاد کنیم و این تنها پوشهای خواهد بود که در کل سرور داریم. در ادامه درون پوشه src فایلی به نام schema.graphql ایجاد کنید. درون این فایل کد زیر را قرار دهید:
1type Query {
2 hello: String
3}
ما همه schema مربوط به GraphQL را در این فایل schema.graphql قرار میدهیم. اگر نمیدانید schema چیست، جای نگرانی نیست، چون در ادامه آن را توضیح خواهیم داد. اینک درون پوشه src یک فایل دوم ایجاد کنید. این فایل را resolvers.js نامگذاری کنید و درون فایل دوم کد زیر را قرار بدهید:
1import { users } from "./db";
2
3const resolvers = {
4 Query: {
5 hello: () => "Hello World!"
6 }
7};
8
9export default resolvers;
فایل resolvers.js دستورالعملهای تبدیل یک عملیات GraphQL به دادهها را تعیین میکند. در نهایت درون پوشه src یک فایل سوم به نام db.js ایجاد کنید و کد زیرا را درون آن قرار دهید:
1export let users = [
2 { id: 1, name: "John Doe", email: "john@gmail.com", age: 22 },
3 { id: 2, name: "Jane Doe", email: "jane@gmail.com", age: 23 }
4];
ما در این راهنما از یک پایگاه داده واقعی استفاده نمیکنیم. از این رو این فایل db.js به عنوان یک پایگاه داده برای ما عمل میکند و صرفاً مقاصد آموزشی دارد. اکنون پوشه src باید دارای ساختار زیر باشد:
src
|--db.js
|--resolvers.js
|--schema.graphql
در ادامه اگر دستور npm run dev را اجرا کنیم یا اگر با استفاده از yarn دستور yarn dev را اجرا کنید باید این خروجی را در ترمینال ببینید:
اینک میتوانید به آدرس localhost:4000 بروید. این بدان معنی است که ما آماده شروع هستیم و میتوانیم نخستین کوئریها، جهشها (mutation) و اشتراکهای (subscription) خود را در GraphQL داشته باشیم.
GraphQL Playground یک IDE قدرتمند است که برای توسعه بهتر GraphQL استفاده میشود. اگر میخواهید در مورد آن اطلاعات بستری کسب کنید به این آدرس (+) مراجعه کنید.
اسکیما (Schema)
GraphQL نوع زبان خاص خود را دارد که برای نوشتن اسکیما (شِما نیز تلفظ میشود.) استفاده میشود. این ساختار اسکیمای قابل خواندن از سوی انسان به نام «زبان تعریف اسکیما» (Schema Definition Language) با به اختصار SDL نامیده میشود. مهم نیست که از چه فناوری استفاده میکنید، در هر صورت SDL یکسان خواهد بود. در واقع میتوان از آن در هر زبان یا فریمورک مورد نظر استفاده کرد. زبان اسکیما بسیار مفید است، زیرا درک این که API شما چه انواعی خواهد داشت، ساده است. بدین ترتیب صرفاً با نگاه کردن به API میتوان آن را درک کرد.
انواع (Types)
انواع، یکی از مهمترین خصوصیتهای GraphQL هستند. انواع، شیءهای خاصی هستند که چگونگی نمایش API را تعیین میکنند. برای نمونه اگر یک اپلیکیشن شبکه اجتماعی میسازید، API شامل انواعی مانند Posts, Users, Likes و Groups خواهد داشت.
انواع، دارای فیلد هستند و فیلدها نوع خاصی از دادهها را باز میگردانند. برای مثال، ما قصد داریم یک نوع USER بسازیم که میتواند فیلدهایی مانند name, email و age داشته باشد. این فیلدها میتوانند هر چیزی باشند و همواره نوع خاصی از دادهها را به صورت Int, Float, String, Boolean, ID، لیستی از انواع شیء یا انواع شیء سفارشی بازمیگردانند. بنابراین اینک برای این که نخستین نوع خود را بنویسیم باید به فایل schema.graphql مراجعه کنیم و کوئری نوع را که قبلاً در آن به صورت زیر وجود دارد عوض کنیم:
1type User {
2 id: ID!
3 name: String!
4 email: String!
5 age: Int
6}
هر user باید یک ID داشته باشد و از این رو یک نوع ID برای آن تعیین میکنیم. user همچنین باید یک name و email داشته باشد و از این رو یک نوع String به آن میدهیم. همچنین یک age داریم که نوع int برای آن تعیین میکنیم. میبینید که همه چیز کاملاً ساده است.
اما شاید بپرسید آن علامت (!) در انتهای هر خط به چه معنی است؟ علامت تعجب به این معنی است که فایلها به صورت non-nullable هستند، یعنی هر فیلد باید در کوئریهای مختلف مقداری را بازگرداند و نمیتواند تهی باشد. تنها فیلد nullable که در نوع User خواهیم داشت به صورت age خواهد بود.
در GraphQL با سه مفهوم عمده سر و کار داریم:
- کوئریها: روشی که با آن دادهها را از سرور میگیریم.
- جهشها (Mutations ): روشی که برای اصلاح دادهها روی سرور و دریافت مجدد دادهها استفاده میکنیم (create, update, delete).
- اشتراکها (Subscriptions ): روشی که یک اتصال همزمان را روی سرور حفظ میکنیم.
در ادامه قصد داریم همه آنها را برای شما توضیح دهیم. کار خود را با کوئریها آغاز میکنیم.
کوئریها
اگر بخواهیم به زبان ساده توضیح دهیم، کوئری همان روش دریافت دادهها از سرور است. یکی از زیباترین چیزها در مورد کوئریها در GraphQL این است که میتوانید صرفاً همان دادههایی را که میخواهید دریافت کنید. نه بیشتر و نه کمتر. این وضعیت تأثیر مثبت زیادی روی API ها دارد و دیگر لازم نیست اطلاعاتی بیش از حد یا کمتر از حد موردنیاز را چنان که در REST API شاهد بودیم، واکشی کنیم.
ما میخواهیم نخستین کوئری خود را در GraphQL بسازیم. همه کوئریهای ما درون این نوع انجام خواهند یافت. بنابراین برای شروع به schema.graphql میرویم و یک نوع جدید به نام Query ایجاد میکنیم:
1type Query {
2 users: [User!]!
3}
همه چیز بسیار ساده است: کوئری Users یک آرایه از یک یا چند کاربر (Users) را به ما بازمیگرداند. این کوئری نمیتواند مقدار تهی بازگرداند، زیرا در انتهای آن از (!) استفاده شده است و این بدان معنی است که این یک کوئری non-nullable است. این کوئری همواره باید یک مقداری بازگشت دهد.
همچنین میتوانیم یک کاربر خاص را نیز بازگشت دهیم. به این منظور باید یک کوئری جدید به نام user ایجاد کنیم. درون نوع Query کد زیر را قرار دهید:
1user(id: ID!): User!
اینک نوع Query باید به صورت زیر باشد:
1type Query {
2 users: [User!]!
3 user(id: ID!): User!
4}
همان طور که شاهد هستید، ما با استفاده از کوئریها در GraphQL میتوانیم آرگومان نیز ارسال کنیم. در این حالت، جهت کوئری زدن برای یک user خاص میتوانیم ID آن را ارسال کنیم. اما ممکن است تعجب کنید که GraphQL از کجا میداند که دادهها را از کجا باید دریافت کند؟ ما فایل resolvers.js را به همین منظور ایجاد کردهایم. این فایل به GraphQL اعلام میکند که دادهها را چگونه و از کجا واکشی کند. ابتدا به فایل resolvers.js میرویم و db.js را که کمی پیشتر ایجاد کردیم ایمپورت میکنیم. فایل resolvers.js اینک به صورت زیر در آمده است:
1import { users } from "./db";
2
3const resolvers = {
4 Query: {
5 hello: () => "Hello World!"
6 }
7};
8
9export default resolvers;
اکنون باید نخستین کوئری خود را ایجاد کنیم. به فایل resolvers.js خود بروید و تابع hello را جایگزین کنید. اکنون نوع کوئری شما باید چیزی مانند زیر باشد:
1import { users } from "./db";
2
3const resolvers = {
4 Query: {
5 user: (parent, { id }, context, info) => {
6 return users.find(user => user.id === id);
7 },
8 users: (parent, args, context, info) => {
9 return users;
10 }
11 }
12};
13
14export default resolvers;
در ادامه طرز کار آن را توضیح میدهیم:
هر resolve کننده کوئری چهار آرگومان دارد. در تابع user ما باید id را به صورت یک آرگومان ارسال کنیم و سپس user خاص را که با id ارسال شده مطابقت دارد بازگشت دهیم. میبینید که بسیار ساده است.
در تابع users صرفاً باید آرایه users را که هم اینک وجود دارد بازگشت دهیم. این تابع در واقع همه کاربران را به ما بازمیگرداند. سپس باید بررسی کنیم که آیا کوئریهای ما به درستی کار میکنند یا نه. به localhost:4000 بروید و کد زیر را قرار دهید:
1query {
2 users {
3 id
4 name
5 email
6 age
7 }
8}
کد فوق باید همه کاربران را بازگشت دهد. همچنین اگر میخواهید کاربر خاصی را دریافت کنید از کد زیر استفاده کنید:
1query {
2 user(id: 1) {
3 id
4 name
5 email
6 age
7 }
8}
اینک باید شروع به یادگیری جهشها بکنیم. جهشها یکی از مهمترین ویژگیهای GraphQL محسوب میشوند.
جهشها (Mutations)
جهشها در GraphQL روش مورد نیاز برای اصلاح دادهها روی سرور و دریافت مجدد آنها هستند. جهش را در GraphQL میتوانید معادلی برای GUD یعنی سه دستور (ایجاد، بهروزرسانی و حذف) در REST تصور کنید.
ما قصد داریم نخستین جهش نوع خود را در GraphQL بسازیم و همه جهشهای ما درون این نوع پایان مییابند. بنابراین برای شروع کار به schema.graphql میرویم و یک نوع جدید به نام mutation مینویسیم:
1type Mutation {
2 createUser(id: ID!, name: String!, email: String!, age: Int): User!
3 updateUser(id: ID!, name: String, email: String, age: Int): User!
4 deleteUser(id: ID!): User!
5}
همان طور که میبینید ما میخواهیم سه جهش داشته باشیم:
- createUser: ما باید یک ID, name, email و age ارسال کنیم. این جهش یک کاربر به ما بازگشت میدهد.
- updateUser: ما باید یک ID و یک name, email یا age جدید ارسال کنیم و این جهش یک کاربر جدید به ما بازگشت میدهد.
- deleteUser: ما باید یک ID ارسال کنیم و این جهش یک کاربر جدید به ما بازگشت میدهد.
اینک به فایل resolvers.js میرویم و زیر شیء Query یک شیء mutation جدید مانند زیر میسازیم:
1Mutation: {
2 createUser: (parent, { id, name, email, age }, context, info) => {
3 const newUser = { id, name, email, age };
4
5 users.push(newUser);
6
7 return newUser;
8 },
9 updateUser: (parent, { id, name, email, age }, context, info) => {
10 let newUser = users.find(user => user.id === id);
11
12 newUser.name = name;
13 newUser.email = email;
14 newUser.age = age;
15
16 return newUser;
17 },
18 deleteUser: (parent, { id }, context, info) => {
19 const userIndex = users.findIndex(user => user.id === id);
20
21 if (userIndex === -1) throw new Error("User not found.");
22
23 const deletedUsers = users.splice(userIndex, 1);
24
25 return deletedUsers[0];
26 }
27}
اینک فایل resolvers.js باید به صورت زیر در آمده باشد:
1import { users } from "./db";
2
3const resolvers = {
4 Query: {
5 user: (parent, { id }, context, info) => {
6 return users.find(user => user.id === id);
7 },
8 users: (parent, args, context, info) => {
9 return users;
10 }
11 },
12 Mutation: {
13 createUser: (parent, { id, name, email, age }, context, info) => {
14 const newUser = { id, name, email, age };
15
16 users.push(newUser);
17
18 return newUser;
19 },
20 updateUser: (parent, { id, name, email, age }, context, info) => {
21 let newUser = users.find(user => user.id === id);
22
23 newUser.name = name;
24 newUser.email = email;
25 newUser.age = age;
26
27 return newUser;
28 },
29 deleteUser: (parent, { id }, context, info) => {
30 const userIndex = users.findIndex(user => user.id === id);
31
32 if (userIndex === -1) throw new Error("User not found.");
33
34 const deletedUsers = users.splice(userIndex, 1);
35
36 return deletedUsers[0];
37 }
38 }
39};
40
41export default resolvers;
سپس بررسی میکنیم که آیا جهشهای ما به درستی کار میکنند یا نه. به این منظور به آدرس localhost:4000 بروید و کد زیر را در آن قرار دهید:
1mutation {
2 createUser(id: 3, name: "Robert", email: "robert@gmail.com", age: 21) {
3 id
4 name
5 email
6 age
7 }
8}
اینک باید یک کاربر جدید بازگشت یابد. اگر میخواهید جهشهای جدیدی ایجاد کنید، توصیه میکنیم که حتماً این را به عنوان یک تمرین انجام دهید. سعی کنید برخی کاربرهایی را که ایجاد کرده بودید حذف کنید و درستی عملکرد آن را تست کنید. در نهایت شروع به یادگیری در مورد اشتراکها میکنیم و دلیل قدرتمندی زیاد آنها را توضیح میدهیم.
اشتراکها (Subscriptions)
همان طور که پیشتر گفتیم، اشتراکها روشی هستند که برای نگهداشتن یک اتصال همزمان با سرور استفاده میشوند. این بدان معنی است که هر زمان یک رویداد در سرور رخ میدهد و هر رویدادی که فراخوانی شود، سرور دادههای متناظر را به کلاینت میفرستد. با کار کردن با اشتراکها میتوانید اپلیکیشن را همواره بهروز نگهدارید و آخرین تغییرات را بین کاربران مختلف نمایش دهید.
یک اشتراک مقدماتی به صورت زیر است:
1subscription {
2 users {
3 id
4 name
5 email
6 age
7 }
8}
شاید با خود بگویید که تا حدود زیادی شبیه به کوئری است و واقعاً هم چنین است؛ اما طرز کار آن متفاوت است. زمانی که چیزی روی سرور بهروزرسانی میشود، سرور کوئری GraphQL اشاره شده در اشتراک را اجرا خواهد کرد و یک نتیجه جدیداً بهروز شده را به کلاینت ارسال میکند. ما در این مقاله قصد نداریم از اشترکها استفاده کنیم؛ اما اگر میخواهید در مورد آنها بیشتر بدانید میتوانید به این آدرس (+) مراجعه کنید.
سخن پایانی
همان طور که در این مطلب مشاهده کردید، GraphQL یک فناوری جدید است که واقعاً قدرتمند محسوب میشود. این فناوری قدرت واقعی برای ساخت API-های بهتر و با طراحی مناسب را در اختیار ما قرار میدهد. به همین دلیل است که پیشنهاد میکنیم هم اینک یادگیری آن را آغاز کنید، چون این فناوری در نهایت جایگزین REST خواهد شد.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای برنامهنویسی
- آموزش REST API در وردپرس برای کار با داده های پایگاه داده
- مجموع آموزشهای طراحی و توسعه پروژه های وب
- API چیست؟ — به زبان ساده
- آموزش REST API در Laravel (لاراول) با بسته Passport
- راهنمای تست API و نکاتی برای مبتدیان (SOAP و REST) – به زبان ساده
- API چیست و API های باز چگونه اینترنت را تغییر میدهند؟
==
این پاراگراف دارای یک یا چند باگ داخل مقاله بود :
پس از این مقدمه کوتاه در مورد GraphQL، دلیل قدرت آن و این که چرا محبوبیت زیادی این روزها کسب کرده است، اگر میخواهید دارید اطلاعات بیشتری در مورد آن کسب کنید، پیشنهاد میکنید به مستندات موجود در وبسایت آن (+) مراجعه کنید.
با سلام و احترام؛
صمیمانه از همراهی شما با مجله فرادرس و ارائه بازخورد سپاسگزاریم.
این مورد اصلاح شد.
برای شما آرزوی سلامتی و موفقیت داریم.
سلام
این کویری خطا میده
query {
user(id: 1) {
id
name
email
age
}
}
با سلام و احترام؛
صمیمانه از همراهی شما با مجله فرادرس و ارائه بازخورد سپاسگزاریم.
بسته به اینکه چه خطایی دریافت میشود، شیوه رفع مشکل متفاوت است. میتوان متن خطا را در موتورهای جستجو وارد و نتایج را بررسی کرد. وبسایتهای پرسش و پاسخ مختلفی در وب برای رفع مشکلات برنامه نویسی وجود دارند که مهمترین و محبوبترین آنها سایت Stack Overflow است. در اکثر مواقع خطاهایی که برنامه نویسان با آنها مواجه میشوند قبلاً برای دیگران اتفاق افتادهاند و در وبسایتهای پرسش و پاسخ در مورد آنها پرسشهایی مطرح شدهاند.
خطایابی یا دیباگ کردن یکی از مهارتهای برنامه نویسی به حساب میآید و لازم است برنامه نویسان بتوانند خطاهای موجود در کدها را بیابند و آنها را رفع کنند تا برنامه بدون مشکل اجرا شود و خروجی دهد. در خصوص یادگیری نحوه خطایابی در برنامه نویسی میتوانید از دوره آموزشی رایگان زیر استفاده کنید:
برای شما آرزوی سلامتی و موفقیت داریم.
سلام ممنون از آموزش خوبتون…