如何在Postgraphile mutations中使用Node.js?

kcwpcxri  于 2023-06-05  发布在  Node.js
关注(0)|答案(2)|浏览(339)

我正在制作一个应用程序,显示不同用户的信息,这是从第三方API。我在PostgreSQL中用多个表以自己的格式保存这些信息,以跟踪数据的任何更改并提供更改历史(* 第三方API仅提供当前数据 *)。
我想使用GraphQL,特别是Postgraphile来简化后端开发。但是有一个用例我找不到用Postgraphile实现的方法。下面是我想要实现的:
1.用户希望查看更新的信息

  1. GraphQL mutation query被发送到服务器,类似这样:
mutation UpdateUserData($userid: Int) {
    updateUser(id: $userid) {
        field1,
        field2,
        relatedObjects {
            field3,
            filed3
        }
    }
}

1.服务器向第三方服务器发出API请求,处理数据,进行一些计算并更新数据库
1.请求的字段将返回给客户端
我知道这种类型的custom mutations can be implemented with database functionsPL/pgSQLPLV8,但他们不能使http请求和我已经有了大部分的数据处理逻辑在Typescript,所以想使用它。

有没有办法创建一个自定义的mutation,它将调用JavaScript函数,该函数可以访问我已经创建的Node.js模块、接口和类?

我认为有一个解决方案可行:
1.在我的服务器上调用REST端点,如/update_user?id=$userid
1.从第三方API加载用户数据并更新数据库
1.客户端接收响应,如Update successful
1.调用普通GraphQL查询来获取数据
有没有更好的方法来满足这个用例?

kpbwa7wx

kpbwa7wx1#

这一部分在文档中有点隐藏,但用JavaScript编写的添加突变的最简单方法是makeExtendSchemaPlugin
在这里,你可以用SDL定义类型定义,用JS实现解析器。

vawmfj5a

vawmfj5a2#

我想要的是在前端使用非常方便的Postgraphile查询,并在我选择的框架中使用我选择的ORM编写我的后端逻辑,并有自己的工作流程(所以makeExtendSchemaPlugin不是and选项),但是重用Postgraphile返回类型的变化。
一般来说,我依赖Postgraphile作为我的应用程序的graphql服务器,并通过stitching Postgraphile schema和我的mutations schema将mutations放在它的schema下,并将mutations resolver委托给Postgraphile schema。additionalGraphQLContextFromRequest为我的解析器提供了DI容器,所以它们有办法调用业务服务。makeProcessSchemaPlugin是缝合发生的地方。codegen生成类型,所以当schema+resolvers+services不加起来时,typescript会抱怨。
以下是我的设置:

- postgraphile.ts
- postgraphile.graphql
- types.ts
- services
  - base.graphql
  - document
    - service.ts
    - schema.graphql
    - resolver.ts
  - user
    - service.ts
    - schema.graphql
    - resolver.ts
  - ... other domains

postgraphile.tsset up as library

export const setupPostgraphile = () => postgraphile(connString, schema, {
    additionalGraphQLContextFromRequest: async (req) => {
        // get DI cradle I previously set up in Fastify and put to resolvers context
        return {
            cradle: (req._fastifyRequest as FastifyRequest).server.cradle
        } as AppResolverContext;
    },
    appendPlugins: [
      MutationResolversSchemaPlugin
    ]
});

const MutationResolversSchemaPlugin = makeProcessSchemaPlugin((schema) => {
    // save schema file ourselves instead of using postgraphile plugin because
    // after stiching it will have duplicates of our types giving
    // '...type tried to redefine...' errors
    if (!isProd) {
        writeFileSync('./postgraphile.graphql', printSchema(schema));
    }

    const mutationResolvers: MutationResolvers<AppResolverContext> = {
        ...documentResolvers(schema),
        ...userResolvers(schema),
        // all other resolvers
    };

    return stitchSchemas({
        subschemas: [schema],
        // do NOT include postgraphile.schema, it will nullify Postgraphile resolvers
        typeDefs: loadFilesSync<GraphQLSchema>('./services/**/*.graphql'),
        resolvers: {
            Mutation: mutationResolvers
        }
    });
});

document/schema.graphql,注意Document是来自postgraphile.graphql的Postgraphile类型

input DocumentInput {
    title: String
}

extend type Mutation {
    createDocument(doc: DocumentInput!): Document!
}

document/resolver.ts,类型Query和QueryDocumentArgs来自codegen:

export const documentResolvers: AppMutationsSubresolver<
    'createDocument'
> = (postgraphileSchema) => ({
    createDocument: {
        selectionSet: '{ id }',
        resolve: async (parent, args, context, info) => {
            const result = await context.cradle.documentService.createDocument(args.doc);

            return delegateToSchema({
                schema: postgraphileSchema,
                operation: 'query',
                fieldName: 'document' as keyof Query['document'],
                args: {id: result.id} as QueryDocumentArgs,
                context,
                info
            });
        }
    }
});

document/service.ts

export class DocumentService {
    // DI setting up bla bla bla
    
    async createDocument(dto: DocumentUpdateDTO) {
        // my perfectly normal service code
        ...

        await this.em.flush();

        // return something which holds 'id' of created object, it will be used
        // to query from Postgraphile
        return serialize(doc); 
    }
}

postgraphile.graphql只是一个用于IDE完成的Postgraphile模式(原始的,没有我的突变)的转储。
types.ts具有IDe责任,例如当我忘记了一些突变或misspel一些类型时,类型来自codegen:

export type AppResolverContext = {
    cradle: AppCradle; // my DI container type, I use awilix
}

// shorthand type for resolvers
export type AppMutationsSubresolver<
    MutationsSubset extends keyof MutationResolvers<AppResolverContext>
> = (postgraphileSchema: GraphQLSchema) => Pick<MutationResolvers<AppResolverContext>, MutationsSubset>

base.graphql

type Mutation

最后,从前端进行这样的突变 * 实际上是可行的 *,将结果重定向到功能齐全的Postgraphile类型:

mutation {
  createDocument(doc: {name: "ololo"}) {
    id, name
  }
}
  • Graphql infra最近变得非常棒。*

似乎有一个很好的替代方法:而不是stiching,做一个类型合并网关,让你的变化模式在Postgraphile类型之后返回存根类型名称,并指导模式stiching如何通过ID合并Postgraphile类型。我想保持事情明确和非网关,并没有尝试它。

相关问题