
TypeGraphQL v1.0
في 19 أغسطس ، تم إصدار إطار عمل TypeGraphQL ، والذي يبسط العمل مع GraphQL في Typescript. لمدة عامين ونصف ، اكتسب المشروع مجتمعًا قويًا ودعمًا من العديد من الشركات واكتسب شعبية بثقة. بعد أكثر من 650 التزامًا ، لديه أكثر من 5000 نجمة و 400 شوكة على جيثب ، ثمرة العمل الجاد للمطور البولندي ميشال لايتك. في الإصدار 1.0 ، تم تحسين الأداء بشكل كبير ، وتم عزل المخططات والتخلص من التكرار السابق ، وظهرت ميزتان رئيسيتان - التوجيهات والإضافات ، وتم جعل إطار العمل متوافقًا تمامًا مع GraphQL.
ما هو هذا الإطار؟
يشير ميشال إلى تجربته مع GraphQL المجردة ، ويصف عملية التطوير بأنها "مؤلمة" بسبب التكرار والتعقيد في تعديل الكود الحالي:
لا يبدو الأمر عمليًا للغاية ، ومع هذا النهج فإن المشكلة الرئيسية هي التكرار في الكود ، مما يجعل من الصعب مزامنة جميع المعلمات عند كتابته ويضيف مخاطر عند إجراء التغييرات. لإضافة حقل جديد إلى الكيان الخاص بنا ، يتعين علينا تكرار جميع الملفات: تغيير فئة الكيان ، ثم تغيير جزء المخطط والواجهة. إنه نفس الشيء مع بيانات الإدخال أو الوسائط ، فمن السهل أن تنسى تحديث عنصر واحد أو ارتكاب خطأ في نوع واحد.
لمكافحة التكرار وأتمتة كل هذا العمل اليدوي ، تم إنشاء TypeGraphQL. يعتمد على فكرة تخزين جميع المعلومات في مكان واحد ، ووصف مخطط البيانات من خلال الفئات والمصممين. يأخذ إطار العمل أيضًا العمل اليدوي لحقن التبعية ، والتحقق من صحة البيانات والترخيص ، وتفريغ المطور.
مبدأ التشغيل
لنلقِ نظرة على كيفية عمل TypeGraphQL باستخدام واجهة برمجة تطبيقات GraphQL لقاعدة بيانات الوصفات كمثال.
هذا ما يبدو عليه المخطط في SDL:
type Recipe {
id: ID!
title: String!
description: String
creationDate: Date!
ingredients: [String!]!
}
دعنا نعيد كتابتها كصف وصفة:
class Recipe {
id: string;
title: string;
description?: string;
creationDate: Date;
ingredients: string[];
}
دعنا نجهز الطبقة والخصائص بالديكور:
@ObjectType()
class Recipe {
@Field(type => ID)
id: string;
@Field()
title: string;
@Field({ nullable: true })
description?: string;
@Field()
creationDate: Date;
@Field(type => [String])
ingredients: string[];
}
القواعد التفصيلية لوصف الحقول والأنواع في القسم المقابل من التوثيق
ثم سنصف استعلامات وطفرات CRUD المعتادة. للقيام بذلك ، دعنا ننشئ وحدة تحكم RecipeResolver مع RecipeService التي تم تمريرها إلى المنشئ:
@Resolver(Recipe)
class RecipeResolver {
constructor(private recipeService: RecipeService) {}
@Query(returns => Recipe)
async recipe(@Arg("id") id: string) {
const recipe = await this.recipeService.findById(id);
if (recipe === undefined) {
throw new RecipeNotFoundError(id);
}
return recipe;
}
@Query(returns => [Recipe])
recipes(@Args() { skip, take }: RecipesArgs) {
return this.recipeService.findAll({ skip, take });
}
@Mutation(returns => Recipe)
@Authorized()
addRecipe(
@Arg("newRecipeData") newRecipeData: NewRecipeInput,
@Ctx("user") user: User,
): Promise<Recipe> {
return this.recipeService.addNew({ data: newRecipeData, user });
}
@Mutation(returns => Boolean)
@Authorized(Roles.Admin)
async removeRecipe(@Arg("id") id: string) {
try {
await this.recipeService.removeById(id);
return true;
} catch {
return false;
}
}
}
هنا ، يتم استخدام مصممAuthorized () لتقييد الوصول إلى المستخدمين غير المصرح لهم (أو المتميزين بشكل غير كافٍ). يمكنك قراءة المزيد عن التفويض في الوثائق .
حان الوقت لإضافة NewRecipeInput and RecipesArgs:
@InputType()
class NewRecipeInput {
@Field()
@MaxLength(30)
title: string;
@Field({ nullable: true })
@Length(30, 255)
description?: string;
@Field(type => [String])
@ArrayMaxSize(30)
ingredients: string[];
}
@ArgsType()
class RecipesArgs {
@Field(type => Int, { nullable: true })
@Min(0)
skip: number = 0;
@Field(type => Int, { nullable: true })
@Min(1) @Max(50)
take: number = 25;
}
الطولو دقيقةوArrayMaxSize عبارة عن أدوات تزيين من فئة المدقق التي تقوم بالتحقق من صحة الحقل تلقائيًا.
الخطوة الأخيرة في الواقع هي تجميع الدائرة. يتم ذلك عن طريق وظيفة buildSchema:
const schema = await buildSchema({
resolvers: [RecipeResolver]
});
وهذا كل شيء! لدينا الآن مخطط GraphQL يعمل بشكل كامل. في شكل مجمع ، يبدو كما يلي:
type Recipe {
id: ID!
title: String!
description: String
creationDate: Date!
ingredients: [String!]!
}
input NewRecipeInput {
title: String!
description: String
ingredients: [String!]!
}
type Query {
recipe(id: ID!): Recipe
recipes(skip: Int, take: Int): [Recipe!]!
}
type Mutation {
addRecipe(newRecipeData: NewRecipeInput!): Recipe!
removeRecipe(id: ID!): Boolean!
}
هذا مثال على الوظائف الأساسية ، في الواقع ، يمكن لـ TypeGraphQL استخدام مجموعة من الأدوات الأخرى من ترسانة TS. لقد رأيت بالفعل روابط للوثائق :)
ما الجديد في الإصدار 1.0
دعنا نلقي نظرة سريعة على التغييرات الرئيسية في الإصدار:
أداء
تعد TypeGraphQL أساسًا طبقة إضافية من التجريد فوق مكتبة Graphql-js ، وستعمل دائمًا بشكل أبطأ منها. ولكن الآن ، مقارنة بالإصدار 0.17 ، على عينة مكونة من 25000 كائن متداخل ، يضيف الإطار 30 مرة أقل من الحمل - من 500٪ إلى 17٪ مع إمكانية التسريع حتى 13٪. تم وصف بعض طرق التحسين غير التافهة في الوثائق .
عزل الدوائر
في الإصدارات القديمة ، تم بناء المخطط من جميع البيانات الوصفية التي تم الحصول عليها من المصممين. أعادت كل استدعاء لاحق لـ buildSchema نفس المخطط ، الذي تم إنشاؤه من جميع البيانات الوصفية المتوفرة في المتجر. الآن يتم عزل المخططات ويصدر buildSchema فقط الطلبات المرتبطة مباشرة بالمعلمات المحددة. وهذا يعني أنه من خلال تغيير معلمة وحدات الحل فقط ، سنقوم بإجراء عمليات مختلفة على مخططات GraphQL.
التوجيهات والإضافات
توجد طريقتان لإضافة البيانات الوصفية إلى عناصر المخطط: توجيهات GraphQL هي جزء من SDL ويمكن الإعلان عنها مباشرةً في المخطط. يمكنهم أيضًا تغييره وتنفيذ عمليات محددة ، على سبيل المثال ، إنشاء نوع اتصال لترقيم الصفحات. يتم تطبيقها باستخدام الديكورDirective وExtensions وتختلف في نهجها لبناء المخطط. توجيهات التوثيق ، وثائق الامتدادات .
المحولات والحجج لحقول الواجهة
تكمن الحدود الأخيرة للتوافق الكامل مع GraphQL هنا. يمكنك الآن تحديد المحولات لحقول الواجهة باستخدام بناء جملةObjectType:
@InterfaceType()
abstract class IPerson {
@Field()
avatar(@Arg("size") size: number): string {
return `http://i.pravatar.cc/${size}`;
}
}
يتم وصف بعض الاستثناءات هنا .
تحويل المدخلات والمصفوفات المتداخلة
في الإصدارات السابقة ، تم إنشاء مثيل لفئة الإدخال في مستوى التداخل الأول فقط. هذا خلق مشاكل وأخطاء في التحقق من صحتها. ثابت.
خاتمة
خلال فترة التطوير بأكملها ، ظل المشروع مفتوحًا للأفكار والنقد ومفتوح المصدر ومثير للجدل. 99٪ من الكود كتبه ميشال لايتك نفسه ، لكن المجتمع قدم أيضًا مساهمة كبيرة في تطوير TypeGraphQL. الآن ، مع تزايد شعبيتها ودعمها المالي ، يمكن أن تصبح معيارًا حقيقيًا في مجالها. ميكال في جيثب الدقي تويتر
موقع
