إنتقل إلى المحتوى الرئيسي

تطوير واجهة برمجة تطبيقات GraphQL في Cursor

تطوير واجهة برمجة تطبيقات GraphQL في Cursor

لقد أحدث GraphQL ثورة في كيفية بناء واجهات برمجة التطبيقات من خلال السماح للعملاء بطلب البيانات التي يحتاجونها بالضبط. عند دمجه مع Cursor، وهو محرر IDE مدعوم بالذكاء الاصطناعي، يصبح سير عمل تطوير GraphQL الخاص بك أسرع وأكثر ذكاءً بشكل ملحوظ. يغطي هذا الدليل كل شيء بدءًا من تصميم المخطط وحتى تنفيذ المحللات الجاهزة للإنتاج باستخدام ميزات Cursor المتقدمة.

مقدمة إلى GraphQL في Cursor​

يوفر Cursor بيئة استثنائية لتطوير GraphQL من خلال الإكمال الذكي للكود وتوليد الكود المدعوم بالذكاء الاصطناعي والفهم العميق لعلاقات المخطط. سواء كنت تبني واجهة برمجة تطبيقات جديدة من الصفر أو تحافظ على واحدة موجودة، فإن ميزات Cursor تساعدك على كتابة كود GraphQL أفضل بجهد أقل.

التكامل بين Cursor وأدوات GraphQL يتيح لك:

  • توليد المخططات من أنواع TypeScript تلقائيًا
  • تلقي اقتراحات ذكية لتنفيذات المحللات
  • التحقق من صحة الاستعلامات مقابل مخططك في الوقت الفعلي
  • إعادة هيكلة المخططات الكبيرة بمساعدة الذكاء الاصطناعي
  • توليد التوثيق مباشرة من كودك

قبل الغوص في تفاصيل التنفيذ، تأكد من تثبيت الأدوات التالية في مساحة العمل الخاصة بك:

  • Node.js 18 أو أعلى
  • Cursor IDE (يوصى بالإصدار الأحدث)
  • إضافة عميل GraphQL لاختبار الاستعلامات

إعداد مشروع GraphQL الخاص بك​

المشروع المنظم جيدًا ضروري لتطوير GraphQL القابل للتوسع. يتفوق Cursor في مساعدتك على تنظيم قاعدة الكود الخاصة بك من البداية.

ابدأ بإنشاء دليل مشروع جديد وتهيئته باستخدام مدير الحزم المفضل لديك. افتح Cursor في هذا الدليل وأنشئ هيكل المجلدات التالي:

src/
schema/
typeDefs.ts
resolvers/
index.ts
userResolver.ts
postResolver.ts
prisma/
schema.prisma
server.ts

يفصل هذا الهيكل الاهتمامات بوضوح ويسمح لذكاء Cursor الاصطناعي بفهم الحدود بين تعريفات المخطط ومنطق المحللات ونماذج قاعدة البيانات. عند فتح هذا الهيكل في Cursor، يقوم المحرر تلقائيًا بفهرسة جميع علاقات الأنواع ويقدم اقتراحات عبر الملفات.

قم بتثبيت التبعيات الأساسية لإعداد Apollo Server و Prisma:

npm install @apollo/server graphql
npm install @prisma/client
npm install -D prisma typescript ts-node @types/node

بعد التثبيت، قم بتهيئة Prisma داخل مشروعك. تكامل الطرفية في Cursor يجعل هذا سلسًا، ويمكن للذكاء الاصطناعي المساعدة في تصحيح أي مشكلات في التكوين تنشأ أثناء الإعداد.

تلميح

استخدم الدردشة المضمنة في Cursor لطرح أسئلة حول توافق الحزم. على سبيل المثال، حدد package.json الخاص بك واسأل: "هل هذه التبعيات GraphQL متوافقة مع أحدث إصدار من Apollo Server؟" سيقوم Cursor بتحليل الإصدارات واقتراح التحديثات.

تصميم المخططات بمساعدة الذكاء الاصطناعي​

تصميم المخطط هو أساس أي واجهة برمجة تطبيقات GraphQL. قدرات الذكاء الاصطناعي في Cursor تجعل هذه العملية أكثر بديهية من خلال اقتراح الأنواع والحقول والعلاقات بناءً على متطلبات تطبيقك.

إنشاء تعريفات الأنواع​

ابدأ بتعريف أنواعك الأساسية في src/schema/typeDefs.ts. يوفر Cursor إكمالًا تلقائيًا ذكيًا لصيغة SDL (لغة تعريف المخطط) الخاصة بـ GraphQL، بما في ذلك المقاييس المضمنة والتوجيهات والأنواع المخصصة.

export const typeDefs = `#graphql
type User {
id: ID!
email: String!
name: String
posts: [Post!]!
createdAt: String!
updatedAt: String!
}

type Post {
id: ID!
title: String!
content: String!
published: Boolean!
author: User!
createdAt: String!
updatedAt: String!
}

type Query {
users: [User!]!
user(id: ID!): User
posts: [Post!]!
post(id: ID!): Post
}

type Mutation {
createUser(email: String!, name: String): User!
createPost(title: String!, content: String!, authorId: ID!): Post!
publishPost(id: ID!): Post!
deletePost(id: ID!): Post!
}
`;

عند كتابة تعريفات الأنواع في Cursor، يتعرف المحرر على صيغة GraphQL ويقدم اقتراحات واعية بالسياق. يفهم الذكاء الاصطناعي العلاقات بين الأنواع ويمكنه اقتراح الحقول المفقودة عند تعريف كيان جديد.

توليد المخططات من نماذج Prisma​

أحد أقوى سير العمل في Cursor هو توليد مخططات GraphQL مباشرة من نماذج Prisma الخاصة بك. بعد تعريف مخطط قاعدة البيانات الخاص بك في prisma/schema.prisma، يمكنك استخدام دردشة الذكاء الاصطناعي في Cursor لتحويل هذه النماذج إلى تعريفات أنواع GraphQL.

إليك مثال على مخطط Prisma:

generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

model User {
id String @id @default(uuid())
email String @unique
name String?
posts Post[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

model Post {
id String @id @default(uuid())
title String
content String
published Boolean @default(false)
authorId String
author User @relation(fields: [authorId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

حدد مخطط Prisma في Cursor واستخدم ميزة دردشة الذكاء الاصطناعي مع موجه مثل: "قم بتوليد تعريفات أنواع GraphQL المقابلة لنماذج Prisma هذه، بما في ذلك أنواع Query و Mutation." سينتج Cursor صيغة SDL دقيقة تعكس هيكل قاعدة البيانات الخاصة بك.

warning

راجع دائمًا المخططات المولدة بالذكاء الاصطناعي لمتطلبات منطق الأعمال التي قد لا يتم التقاطها في نماذج قاعدة البيانات. يفهم الذكاء الاصطناعي الهيكل ولكنه قد يفوت قواعد التحقق الخاصة بالمجال أو المقاييس المخصصة التي يتطلبها تطبيقك.

تنفيذ المحللات في Cursor​

المحللات هي المكان الذي تنبض فيه واجهة برمجة تطبيقات GraphQL بالحياة. تكامل TypeScript في Cursor يجعل كتابة المحللات الآمنة من حيث النوع أكثر إنتاجية بشكل ملحوظ.

كتابة محللات آمنة من حيث النوع​

أنشئ ملفات المحلل الخاصة بك مع دعم TypeScript الكامل. يفهم Cursor العلاقة بين مخططك وأنواع المحللات، ويقدم إكمالًا تلقائيًا للكائنات الأصلية والوسائط والسياق.

import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

export const userResolver = {
Query: {
users: async () => {
return await prisma.user.findMany({
include: { posts: true },
});
},

user: async (_: unknown, { id }: { id: string }) => {
return await prisma.user.findUnique({
where: { id },
include: { posts: true },
});
},
},

User: {
posts: async (parent: { id: string }) => {
return await prisma.post.findMany({
where: { authorId: parent.id },
});
},
},

Mutation: {
createUser: async (
_: unknown,
{ email, name }: { email: string; name?: string }
) => {
return await prisma.user.create({
data: { email, name },
});
},
},
};

يوفر IntelliSense في Cursor معلومات نوع دقيقة لوسائط المحلل بناءً على تعريفات المخطط الخاصة بك. عند التمرير فوق المعلمات أو قيم الإرجاع، ترى أنواع GraphQL الدقيقة المعينة إلى TypeScript.

استخدام الذكاء الاصطناعي لتوليد محللات معقدة​

بالنسبة لمنطق المحللات المعقد الذي يتضمن تحويل البيانات أو التجميع أو استدعاءات واجهة برمجة تطبيقات الطرف الثالث، فإن توليد الذكاء الاصطناعي في Cursor لا يقدر بثمن. حدد جزءًا من مخططك واطلب من Cursor توليد تنفيذ المحلل المقابل.

على سبيل المثال، بالنظر إلى تعريف المخطط المتقدم هذا:

type Query {
searchPosts(query: String!, filters: PostFilters): SearchResult!
}

input PostFilters {
publishedOnly: Boolean
dateFrom: String
dateTo: String
authorIds: [ID!]
}

type SearchResult {
posts: [Post!]!
totalCount: Int!
hasMore: Boolean!
}

يمكنك توجيه Cursor بـ: "نفذ محللًا لـ searchPosts يقوم بالتصفية وفقًا للمعايير المقدمة، ويدعم الترقيم بحد افتراضي قدره 20، ويعيد العدد الإجمالي وعلامة hasMore." سيقوم الذكاء الاصطناعي بتوليد تنفيذ كامل باستخدام واجهة برمجة تطبيقات التصفية الخاصة بـ Prisma.

searchPosts: async (
_: unknown,
{
query,
filters,
}: {
query: string;
filters?: {
publishedOnly?: boolean;
dateFrom?: string;
dateTo?: string;
authorIds?: string[];
};
},
context: { userId?: string }
) => {
const limit = 20;
const where: any = {
OR: [
{ title: { contains: query, mode: 'insensitive' } },
{ content: { contains: query, mode: 'insensitive' } },
],
};

if (filters?.publishedOnly) {
where.published = true;
}

if (filters?.dateFrom || filters?.dateTo) {
where.createdAt = {};
if (filters.dateFrom) where.createdAt.gte = new Date(filters.dateFrom);
if (filters.dateTo) where.createdAt.lte = new Date(filters.dateTo);
}

if (filters?.authorIds?.length) {
where.authorId = { in: filters.authorIds };
}

const [posts, totalCount] = await Promise.all([
prisma.post.findMany({
where,
take: limit,
include: { author: true },
}),
prisma.post.count({ where }),
]);

return {
posts,
totalCount,
hasMore: totalCount > limit,
};
},
تلميح

عند توليد محللات معقدة، راجع دائمًا استعلامات Prisma بحثًا عن مشاكل N+1. غالبًا ما يولد الذكاء الاصطناعي في Cursor تنفيذات أساسية قد لا تتضمن أنماط DataLoader لتحميل الدفعات للكيانات ذات الصلة.

تكامل Apollo Server​

ربط مخططك ومحللاتك بـ Apollo Server مباشر بمساعدة Cursor. يساعدك المحرر في تكوين الخادم بأنواع TypeScript مناسبة وبرمجيات وسيطة.

إعداد الخادم​

أنشئ ملف server.ts الخاص بك مع تكوين Apollo Server 4:

import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
import { typeDefs } from './schema/typeDefs';
import { resolvers } from './schema/resolvers';

interface MyContext {
token?: string;
userId?: string;
}

const server = new ApolloServer<MyContext>({
typeDefs,
resolvers,
});

const { url } = await startStandaloneServer(server, {
listen: { port: 4000 },
context: async ({ req }): Promise<MyContext> => {
const token = req.headers.authorization || '';
// أضف منطق المصادقة هنا
return { token };
},
});

console.log(`Server ready at: ${url}`);

يوفر Cursor إكمالًا تلقائيًا لواجهات برمجة تطبيقات Apollo Server ويساعدك في الحفاظ على الكتابة الصحيحة في جميع أنحاء التكوين. يمكن للذكاء الاصطناعي أيضًا اقتراح أنماط البرمجيات الوسيطة للمصادقة والتسجيل ومعالجة الأخطاء.

إضافة مقاييس وتوجيهات مخصصة​

غالبًا ما تتطلب واجهات برمجة تطبيقات GraphQL المتقدمة مقاييس مخصصة لأنواع البيانات المتخصصة. يساعدك Cursor في تنفيذها بأمان كامل من حيث النوع.

import { GraphQLScalarType, Kind } from 'graphql';

export const dateScalar = new GraphQLScalarType({
name: 'Date',
description: 'Custom Date scalar',
serialize(value: unknown) {
if (value instanceof Date) {
return value.toISOString();
}
throw Error('GraphQL Date Scalar serializer expected a Date object');
},
parseValue(value: unknown) {
if (typeof value === 'string') {
return new Date(value);
}
throw new Error('GraphQL Date Scalar parser expected a string');
},
parseLiteral(ast) {
if (ast.kind === Kind.STRING) {
return new Date(ast.value);
}
return null;
},
});

عند تعريف المقاييس المخصصة، يضمن خادم لغة TypeScript في Cursor أن دوال التسلسل والتحليل الخاصة بك تتعامل مع الأنواع الصحيحة، مما يمنع أخطاء وقت التشغيل.

أفضل ممارسات تكامل Prisma​

مزيج Prisma و GraphQL في Cursor يخلق تجربة تطوير قوية متكاملة. يغطي هذا القسم أفضل الممارسات لدمج هذه التقنيات بفعالية.

توليد أنواع Prisma Client​

بعد تعديل مخطط Prisma الخاص بك، قم بتشغيل أمر التوليد. يلتقط تكامل الطرفية في Cursor المخرجات، وإذا كانت هناك أخطاء، يمكن للذكاء الاصطناعي مساعدتك في إصلاح مشكلات صيغة المخطط.

npx prisma generate

تتكامل أنواع Prisma Client المولدة بسلاسة مع IntelliSense في Cursor. عند كتابة المحللات، تحصل على إكمال تلقائي كامل لحقول النموذج وخيارات التصفية واستعلامات العلاقات.

التعامل مع العلاقات باستخدام DataLoader​

لتجنب مشكلة استعلام N+1 في محللات GraphQL، قم بدمج DataLoader في مشروع Cursor الخاص بك. يمكن للذكاء الاصطناعي مساعدتك في إعداد دوال تحميل الدفعات التي سينفذها Prisma بكفاءة.

import DataLoader from 'dataloader';
import { PrismaClient, User } from '@prisma/client';

const prisma = new PrismaClient();

export const createUserLoader = () => {
return new DataLoader<string, User | null>(async (userIds) => {
const users = await prisma.user.findMany({
where: { id: { in: [...userIds] } },
});

const userMap = new Map(users.map((user) => [user.id, user]));
return userIds.map((id) => userMap.get(id) || null);
});
};

في سياق الخادم الخاص بك، قم بتهيئة المحملات وتمريرها إلى المحللات:

interface MyContext {
userLoader: ReturnType<typeof createUserLoader>;
postLoader: ReturnType<typeof createPostLoader>;
}

const { url } = await startStandaloneServer(server, {
listen: { port: 4000 },
context: async (): Promise<MyContext> => {
return {
userLoader: createUserLoader(),
postLoader: createPostLoader(),
};
},
});
warning

يجب إنشاء مثيلات DataLoader لكل طلب لتجنب مشكلات التخزين المؤقت بين المستخدمين المختلفين. يقترح الذكاء الاصطناعي في Cursor أحيانًا أنماط المفرد للمحملات؛ تحقق دائمًا من أن تنفيذك ينشئ مثيلات جديدة لكل طلب GraphQL.

توليد الاستعلامات بالذكاء الاصطناعي واختبارها​

أحد الميزات البارزة في Cursor هي قدرته على توليد واختبار استعلامات GraphQL بناءً على مخططك. هذا يسرع كل من سير عمل التطوير وتصحيح الأخطاء.

توليد الاستعلامات من المخطط​

حدد تعريفات الأنواع الخاصة بك في Cursor واطلب من الذكاء الاصطناعي توليد استعلامات وطفرات نموذجية. هذا مفيد بشكل خاص لمطوري الواجهة الأمامية الذين يحتاجون إلى فهم سطح واجهة برمجة التطبيقات المتاح.

بالنسبة لمخطط User و Post أعلاه، قد يولد Cursor:

query GetUserWithPosts($userId: ID!) {
user(id: $userId) {
id
email
name
posts {
id
title
published
createdAt
}
}
}

mutation CreateNewPost($title: String!, $content: String!, $authorId: ID!) {
createPost(title: $title, content: $content, authorId: $authorId) {
id
title
author {
id
name
}
}
}

هذه الاستعلامات المولدة محددة النوع بالكامل ومتحقق من صحتها مقابل مخططك، مما يقلل من احتمالية أخطاء تكامل الواجهة الأمامية.

اختبار المحللات بالاستعلامات المولدة​

استخدم الذكاء الاصطناعي في Cursor لتوليد مجموعات اختبار شاملة لمحللاتك. حدد دالة محلل ووجه: "قم بتوليد اختبارات Jest لهذا المحلل بما في ذلك استدعاءات Prisma الوهمية والحالات الحدية."

import { userResolver } from './userResolver';
import { PrismaClient } from '@prisma/client';

jest.mock('@prisma/client', () => {
const mockPrisma = {
user: {
findMany: jest.fn(),
findUnique: jest.fn(),
create: jest.fn(),
},
};
return { PrismaClient: jest.fn(() => mockPrisma) };
});

describe('User Resolver', () => {
const prisma = new PrismaClient();

beforeEach(() => {
jest.clearAllMocks();
});

it('should return all users with their posts', async () => {
const mockUsers = [
{ id: '1', email: '[email protected]', posts: [] },
{ id: '2', email: '[email protected]', posts: [] },
];
(prisma.user.findMany as jest.Mock).mockResolvedValue(mockUsers);

const result = await userResolver.Query.users();

expect(prisma.user.findMany).toHaveBeenCalledWith({
include: { posts: true },
});
expect(result).toEqual(mockUsers);
});

it('should return a single user by id', async () => {
const mockUser = { id: '1', email: '[email protected]', posts: [] };
(prisma.user.findUnique as jest.Mock).mockResolvedValue(mockUser);

const result = await userResolver.Query.user(null, { id: '1' });

expect(prisma.user.findUnique).toHaveBeenCalledWith({
where: { id: '1' },
include: { posts: true },
});
expect(result).toEqual(mockUser);
});
});

معالجة الأخطاء والتحقق من الصحة​

تتطلب واجهات برمجة تطبيقات GraphQL القوية معالجة شاملة للأخطاء. يساعدك Cursor في تنفيذ أنماط خطأ متسقة عبر محللاتك.

فئات الأخطاء المخصصة​

قم بتعريف فئات أخطاء مخصصة توسع أنواع أخطاء GraphQL الخاصة بـ Apollo:

import { GraphQLError } from 'graphql';

export class AuthenticationError extends GraphQLError {
constructor(message: string = 'Not authenticated') {
super(message, {
extensions: { code: 'UNAUTHENTICATED', http: { status: 401 } },
});
}
}

export class ValidationError extends GraphQLError {
constructor(message: string) {
super(message, {
extensions: { code: 'VALIDATION_FAILED', http: { status: 400 } },
});
}
}

export class NotFoundError extends GraphQLError {
constructor(resource: string) {
super(`${resource} not found`, {
extensions: { code: 'NOT_FOUND', http: { status: 404 } },
});
}
}

استخدم هذه الأخطاء في محللاتك مع دعم الإكمال التلقائي من Cursor:

user: async (_: unknown, { id }: { id: string }) => {
const user = await prisma.user.findUnique({
where: { id },
include: { posts: true },
});

if (!user) {
throw new NotFoundError('User');
}

return user;
},
تلميح

أنشئ إضافة خطأ لـ Apollo Server تسجل الأخطاء وتنسقها للعميل. يمكن لـ Cursor توليد هذه الإضافة بناءً على فئات الأخطاء المخصصة الخاصة بك.

الخاتمة​

تطوير واجهات برمجة تطبيقات GraphQL في Cursor يجمع بين قوة IDE الحديث والمساعدة الذكية بالذكاء الاصطناعي. من تصميم المخطط إلى تنفيذ المحللات والاختبار والنشر، يبسط Cursor كل جانب من جوانب تطوير GraphQL.

النقاط الرئيسية من هذا الدليل:

  • استخدم الذكاء الاصطناعي في Cursor لتوليد المخططات من نماذج Prisma وأنواع TypeScript
  • استفد من تكامل TypeScript لتطوير محللات آمنة من حيث النوع
  • نفذ أنماط DataLoader لمنع استعلامات N+1
  • قم بتوليد الاختبارات والاستعلامات تلقائيًا من تعريفات المخطط الخاصة بك
  • حافظ على معالجة أخطاء متسقة مع فئات الأخطاء المخصصة

مع استمرارك في البناء باستخدام GraphQL و Cursor، جرب ميزات دردشة الذكاء الاصطناعي لإعادة هيكلة المخططات الكبيرة وتحسين استعلامات قاعدة البيانات وتوليد التوثيق. مزيج الخبرة البشرية والمساعدة بالذكاء الاصطناعي ينتج واجهات برمجة تطبيقات قوية وعالية الأداء وقابلة للصيانة.