声明式与编程式 GraphQL [英] Declarative vs Programmatically GraphQL

查看:23
本文介绍了声明式与编程式 GraphQL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为新的全栈项目采用 GraphQL,并且我已经研究了许多概念并开始了我的第一个项目.

I´m adopting GraphQL for new fullstack projects and I´ve already studies many of the concepts and started my first projects.

我的问题与使用声明式与编程式 GraphQL 模式定义有关.基本上我在 GraphQL 官方网站 中看到的所有内容都使用声明式方法:您在一个或多个文件中定义架构,例如(感谢 这里的示例):

My question is related to use declarative vs programatically GraphQL schema definition. Basically all I can see in the GraphQL official site uses the declarative approach: you define the schema in one or more files like (thanks to this example here):

type Brand {
  name: String
  logoUrl: String
}
enum Gender {
  MALE
  FEMALE
}
type Image {
  thumbnailUrl: String
  smallUrl: String
  mediumUrl: String
  largeUrl: String
}
type Article {
  id: ID! # non-nullable, is guaranteed to exist on every article
  name: String
  thumbnailUrl: String
  brand: Brand
  genders: [Gender]
  images: [Image]
  recommendations: [Article]
}
type Query {
  Article(id: ID!): Article
  Articles: [Articles]
}

即使对于某种复杂的数据结构,代码也非常干净简洁.

Very clean and concise code even for a somehow complex data structure.

但是我在网络上看到的大多数示例,甚至在我研究过的书籍上都使用编程方法来构建模式,例如:

But most of examples I see on web and even on books that I´ve studied use the programatically approach to build the schema, something like:

import { GraphQLObjectType, GraphQLInputObjectType } from 'graphql';
import {GraphQLNonNull, GraphQLID, GraphQLList } from 'graphql';
import { GraphQLString, GraphQLInt, GraphQLBoolean } from 'graphql';

import { UserType } from '../User/types';
import UserModel from '../../../models/User';

const fields = {
    _id: {
        type: new GraphQLNonNull(GraphQLID)
    },
    name: {
        type: GraphQLString
    },
    phone: {
        type: GraphQLString
    }
 };

const CompanyType = new GraphQLObjectType({
    name: 'Company',
    description: 'Company',
    fields: fields
 })


const Company = {
    type: CompanyType,
    description: 'Get single company',
    args: {
        id: {
            name: 'id',
            type: new GraphQLNonNull(GraphQLID)
        }
    },
    resolve(root, params) {

        params.deleted = false;

        return CompanyModel.find(params).exec();
    }
}

const Companies = {
    type: new GraphQLList(CompanyType),
    description: 'Get all companies',
    resolve(root) {
        const companies = CompanyModel.find({ deleted: false }).exec();
        if (!companies) {
            throw new Error('Error getting companies.')
        }
        return companies;   
    }
}

export default {
    Company,
    Companies
}

我的目标是构建一个大型 SaaS 应用程序,因此架构会变得非常复杂,我担心代码很快就会变得复杂.

My goal is to build a large SaaS application, so the schema will get pretty complex and my worry is that the code gets complex pretty soon.

那么,我应该采用声明式方法、程序化方法还是两种方法的混合?

So, should I go for a declarative approach, a programmatically approach or a mix of two?

这里的最佳做法是什么?

What is the best practices here?

推荐答案

有很多关于这个话题的讨论 此处此处.

There's a good bit of discussion on this topic here and here.

恕我直言,在 GraphQL 模式语言中定义模式的最大优势是可读性.它使您的架构易于阅读和理解,特别是对于可能正在查询端点但实际上并未参与其设计的内部用户.我认为这也使得定义和更改架构更不容易出错.

IMHO, the biggest advantage to defining your schema in GraphQL schema language is the readability. It makes your schema easy to read and understand, especially to internal users who may be querying the endpoint but not actually involved in it's design. I think it also makes defining and changing the schema less error-prone.

另一方面,以编程方式定义架构提供了更大的灵活性.例如,如果您使用 buildSchema,则只能为您的查询和更改传入解析器.如果您只使用默认解析器就可以处理每种类型,那么这会很好地工作——但是当您需要为单个字段定义解析器时会发生什么?

On the other hand, defining the schema programatically offers a lot more flexibility. For example, if you use buildSchema, you're limited to passing in resolvers for just your queries and mutations. This works fine if you're ok with every type just utilizing the default resolver -- but what happens when you need to define resolvers for individual fields?

以编程方式定义架构允许您为您指定的任何类型中的各个字段定义解析器.这不仅有助于转换您从数据库中获取的数据(将 thumbanail_url 转换为 thumbnailUrl 字段),而且如果这些字段需要额外的数据库查询,它除非实际请求该字段,否则防止它们触发,这可以显着提高性能.正如文档所指出的,如果您想自动生成架构,这种方法也很有用.

Defining the schema programatically allows you to define resolvers for individual fields within any of the types you specify. Not only does this help transform the data you're getting back from your database (turning that thumbanail_url into a thumbnailUrl field), but if those fields require additional database queries, it prevents them from firing off unless the field is actually requested, which can be a significant performance boost. As the documentation points out, this approach is also useful if you want to generate the schema automatically.

就我个人而言,这就是为什么我喜欢 graphql-tools makeExecutableSchema.这是一种中间方法,允许您以非常干净的方式定义类型(使用 GraphQL 架构语言),同时在实现解析器时允许有很大的灵活性.

Personally, this is why I love graphql-tools makeExecutableSchema. It's kind of a middle-of-the-road approach, allowing you to define your types in a very clean way (using GraphQL schema language), while allowing for a good bit of flexibility in implementing resolvers.

这篇关于声明式与编程式 GraphQL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆