
KetikGraphQL v1.0
Pada 19 Agustus, kerangka TypeGraphQL dirilis, yang menyederhanakan bekerja dengan GraphQL di Typecript. Selama dua setengah tahun, proyek ini mendapatkan komunitas yang solid dan dukungan dari beberapa perusahaan dan dengan percaya diri mendapatkan popularitas. Setelah lebih dari 650 komitmen, ia memiliki lebih dari 5.000 bintang dan 400 cabang di github, hasil kerja keras pengembang Polandia, Michal Litek. Di versi 1.0, kinerja meningkat secara signifikan, skema mendapat isolasi dan menyingkirkan redundansi sebelumnya, dua fitur utama muncul - arahan dan ekstensi, kerangka kerja dibawa ke kompatibilitas penuh dengan GraphQL.
Untuk apa kerangka ini?
Michal, mengacu pada pengalamannya dengan GraphQL telanjang, menyebut proses pengembangan "menyakitkan" karena redundansi dan kompleksitas memodifikasi kode yang ada:
Kedengarannya tidak terlalu praktis, dan dengan pendekatan ini, masalah utamanya adalah redundansi kode, yang membuatnya sulit untuk menyinkronkan semua parameter saat menulisnya dan menambah risiko saat mengubahnya. Untuk menambahkan bidang baru ke entitas kita, kita harus mengulang semua file: ubah kelas entitas, lalu ubah bagian skema dan antarmuka. Sama halnya dengan input data atau argumen, mudah untuk lupa mengupdate satu elemen atau membuat kesalahan dalam satu jenis.
Untuk memerangi redundansi dan mengotomatiskan semua pekerjaan manual ini, TypeGraphQL dibuat. Ini didasarkan pada gagasan menyimpan semua informasi di satu tempat, menggambarkan skema data melalui kelas dan dekorator. Kerangka kerja ini juga melakukan pekerjaan manual injeksi ketergantungan, validasi dan otorisasi data, membongkar pengembang.
Prinsip operasi
Mari kita lihat pekerjaan TypeGraphQL menggunakan contoh API GraphQL untuk database resep.
Seperti inilah skema di SDL:
type Recipe {
id: ID!
title: String!
description: String
creationDate: Date!
ingredients: [String!]!
}
Mari kita tulis ulang sebagai kelas Resep:
class Recipe {
id: string;
title: string;
description?: string;
creationDate: Date;
ingredients: string[];
}
Mari lengkapi kelas dan properti dengan dekorator:
@ObjectType()
class Recipe {
@Field(type => ID)
id: string;
@Field()
title: string;
@Field({ nullable: true })
description?: string;
@Field()
creationDate: Date;
@Field(type => [String])
ingredients: string[];
}
Aturan terperinci untuk mendeskripsikan bidang dan jenis di bagian dokumentasi yang sesuai.
Kemudian kami akan menjelaskan kueri dan mutasi CRUD biasa. Untuk melakukan ini, mari buat pengontrol RecipeResolver dengan RecipeService yang diteruskan ke konstruktor:
@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;
}
}
}
Di sini, dekorator @Authorized () digunakan untuk membatasi akses ke pengguna yang tidak sah (atau kurang memiliki hak istimewa). Anda dapat membaca lebih lanjut tentang otorisasi di dokumentasi .
Saatnya menambahkan NewRecipeInput dan 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;
}
Panjangnya, Mindan @ArrayMaxSize adalah dekorator dari kelas validator yang melakukan validasi bidang secara otomatis.
Langkah terakhir sebenarnya adalah merakit sirkuit. Ini dilakukan oleh fungsi buildSchema:
const schema = await buildSchema({
resolvers: [RecipeResolver]
});
Dan itu dia! Kami sekarang memiliki skema GraphQL yang berfungsi penuh. Dalam bentuk kompilasi, terlihat seperti ini:
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!
}
Ini adalah contoh fungsi dasar, pada kenyataannya, TypeGraphQL dapat menggunakan banyak alat lain dari gudang TS. Anda telah melihat tautan ke dokumentasi :)
Apa yang baru di 1.0
Mari kita lihat sekilas perubahan utama dalam rilis:
Performa
TypeGraphQL pada dasarnya adalah lapisan abstraksi tambahan di atas pustaka graphql-js, dan itu akan selalu berjalan lebih lambat darinya. Tapi sekarang, dibandingkan dengan versi 0.17, pada sampel 25.000 objek bersarang, framework menambahkan overhead 30 kali lebih sedikit - dari 500% menjadi 17% dengan kemungkinan akselerasi hingga 13%. Beberapa metode pengoptimalan non-sepele dijelaskan dalam dokumentasi .
Sirkuit isolasi
Pada versi lama, skema dibuat dari semua metadata yang diperoleh dari dekorator. Setiap panggilan berikutnya ke buildSchema menampilkan skema yang sama, yang dibuat dari semua metadata yang tersedia di toko. Sekarang skema diisolasi dan buildSchema hanya mengeluarkan permintaan yang secara langsung terkait dengan parameter yang diberikan. Artinya, dengan hanya mengubah parameter resolver, kami akan melakukan operasi yang berbeda pada skema GraphQL.
Arahan dan ekstensi
Ada dua cara untuk menambahkan metadata ke elemen skema: Direktif GraphQL adalah bagian dari SDL dan dapat dideklarasikan langsung di skema. Mereka juga dapat mengubahnya dan melakukan operasi tertentu, misalnya, menghasilkan jenis koneksi untuk penomoran halaman. Mereka diterapkan menggunakan dekorator @Directive dan @Extensions dan berbeda dalam pendekatannya terhadap konstruksi skema. Petunjuk Dokumentasi , dokumentasi Ekstensi .
Pengonversi dan Argumen untuk Bidang Antarmuka
Batas terakhir dari kompatibilitas penuh dengan GraphQL terletak di sini. Anda sekarang dapat menentukan konverter untuk bidang antarmuka menggunakan sintaks @ObjectType:
@InterfaceType()
abstract class IPerson {
@Field()
avatar(@Arg("size") size: number): string {
return `http://i.pravatar.cc/${size}`;
}
}
Beberapa pengecualian dijelaskan di sini .
Mengonversi input dan array bersarang
Di versi sebelumnya, sebuah instance dari kelas input dibuat hanya pada tingkat bersarang pertama. Ini menciptakan masalah dan bug dengan validasinya. Tetap.
Kesimpulan
Selama keseluruhan periode pengembangan, proyek ini tetap terbuka untuk ide dan kritik, open source dan pembakar. 99% kode ditulis oleh Michal Litek sendiri, tetapi komunitas juga memberikan kontribusi besar untuk pengembangan TypeGraphQL. Sekarang, dengan meningkatnya popularitas dan dukungan finansial, ini bisa menjadi standar yang benar di bidangnya.
Situs Twitter Michal
Github
Doki
