如何使用 openapi-to-graphql 在环回 4 中启用 graphql 订阅

How to enable graphql subscription in loopback 4 with openapi-to-graphql

根据标题,我在尝试在我的环回 4 应用程序中启用 graphql 订阅时遇到问题。

这是我到目前为止完成的代码。

index.ts


export async function main(options: ApplicationConfig = {}) {

 const app = new BackendLb4Application(options)
 await app.boot()
 await app.start()
    
 const url = app.restServer.url;

 const oas: Oas3 = <Oas3><unknown>await app.restServer.getApiSpec()
    
   
 const {schema} = await createGraphQLSchema(oas, {
  operationIdFieldNames: true,
  baseUrl: url,
  createSubscriptionsFromCallbacks: true,
    
 })

 const handler = graphqlHTTP( (request:any, response:any, graphQLParams: any) => ({
    schema,
    pretty: true,        
    graphiql: true    
 }))

 app.mountExpressRouter(graphqlPath, handler);
 
 const pubsub = new PubSub()
 const ws = createServer(app);

 ws.listen(PORT, () => {
   new SubscriptionServer(
   {
     execute,
     subscribe,
     schema,
    onConnect: (params: any, socket: any, ctx: any) => {
                console.log(params, 'here on onconnect')
              // Add pubsub to context to be used by GraphQL subscribe field
              return { pubsub }
            }
          },
          {
            server: ws,
            path: '/subscriptions'
          }
        )
      })

 return app

}


这是我的架构

type Subscription {
  """
  
  
  Equivalent to PATCH onNotificationUpdate
  """
  postRequestQueryCallbackUrlApiNotification(secondInputInput: SecondInputInput): String

  """
  
  
  Equivalent to PATCH onNotificationUpdate
  """
  postRequestQueryCallbackUrlOnNotificationUpdate(firstInputInput: FirstInputInput): String
}

这是我的控制器的例子

@patch('/notification-update', {
    operationId: 'notificationUpdate',
    description: '**GraphQL notificationUpdate**',
    callbacks:[ {
      
        onNotificationUpdate: {
          //'{$request.query.callbackUrl}/onNotificationUpdate': {
            post: {
              requestBody: {
                operationId: 'notificationUpdateCallback',
                description: 'rasjad',
                content: {
                  'application/json': {
                    schema: {
                      title: "firstInput",
                      type: 'object',
                      properties: {
                        userData: {
                          type: "string"
                        }
                      }
                    }
                  }
                }
              },
              responses: {
                '200': {
                  description: 'response to subscription',
                }
              }
            }
          },
       // }
    }],
   
    responses: {
      '200': {
        description: 'Notification PATCH success count',
        content: {'application/json': {schema: CountSchema}},
      },
    },
  })

  async updateAll(
    @requestBody({
      content: {
        'application/json': {
          schema: getModelSchemaRef(Notification, {partial: true}),
        },
      },
    })
    notification: Notification,
    @param.where(Notification) where?: Where<Notification>,
  ): Promise<Count> {
    return this.notificationRepository.update(notification, where);
  }

我已经在我的控制器中定义了回调 object,然后它将在我的模式中创建一个订阅。在 graphiql 上进行了测试,但没有成功。

我不知道从这里到哪里去。我需要自定义解析器还是什么?不确定。 如果有人可以提供帮助,我们将不胜感激。

以防万一其他人也想做同样的事情。

我用 Apollo Server 切换 graphqlHTTP 来创建我的 graphql 服务器。

所以我的最终 index.ts 看起来像这样。


export async function main(options: ApplicationConfig = {}) {
 

    const lb4Application = new BackendLb4Application(options)

    await lb4Application.boot()
    await lb4Application.migrateSchema()

    await lb4Application.start()
    
    const url = lb4Application.restServer.url;
    

    const graphqlPath = '/graphql'

    // Get the OpenApiSpec
    const oas: Oas3 = <Oas3><unknown>await lb4Application.restServer.getApiSpec()
    // Create GraphQl Schema from OpenApiSpec
    
    const {schema} = await createGraphQLSchema(oas, {
        strict: false,
        viewer: true,
        baseUrl: url,
        headers: {
            'X-Origin': 'GraphQL'
        },
        createSubscriptionsFromCallbacks: true,

        customResolvers: {
            "lb4-title": {
                "your-path":{
                    patch: (obj, args, context, info) => {
                        const num = Math.floor(Math.random() * 10);
                        pubsub.publish("something", { yourMethodName: {count: num} }).catch((err: any) => {
                            console.log(err)
                        })
                        return {count: 1}
                    }
                }
            }
        },
        customSubscriptionResolvers: {
            "lb4-title" : {
                "yourMethodName": {
                    post: {
                        subscribe: () => pubsub.asyncIterator("something"),
                        resolve: (obj: any, args: any, context, info) => {
                            console.log(obj, 'obj')
                            
                        }
                       
                    }
                }
            }
        }
    
    })
    

   
    const app = express();
   
    const server = new ApolloServer({
        schema,
        plugins: [{
            async serverWillStart() {
              return {
                async drainServer() {
                    subscriptionServers.close();
                }
              };
            }
        }],
       
    })
   

    
    const subscriptionServers = SubscriptionServer.create(
        {
            // This is the `schema` we just created.
            schema,
            // These are imported from `graphql`.
            execute,
            subscribe,
        }, 
        {
            
            server: lb4Application.restServer.httpServer?.server,
            path: server.graphqlPath,
            //path: server.graphqlPath,
        }
    );

   
    
    await server.start();
    server.applyMiddleware({ app, path: "/" });


    lb4Application.mountExpressRouter('/graphql', app);

    
    return lb4Application
}

您还需要像这样在控制器中定义 callbacks 对象。

@patch('/something-update', {
    operationId: 'somethingUpdate',
    description: '**GraphQL somethingUpdate**',
   
    callbacks:[ 
      {
        yourMethodName: {
          post: {
            responses: {
              '200': {
                description: 'response to subscription',
                content: {'application/json': {schema: CountSchema}},
                
              }
            }
          }
        },
      }
    ],

    responses: {
      '200': {
        description: 'Something PATCH success count',
        content: {'application/json': {schema: CountSchema}},
      },
    },
  })
  async updateAll(
    @requestBody({
      content: {
        'application/json': {
          schema: getModelSchemaRef(Something, {partial: true}),
        },
      },
    })
    something: Something,
    @param.where(Something) where?: Where<Something>,
  ): Promise<Count> {
    return this.somethingRepository.updateAll(something, where);
  }

就是这样。您可以从 GraphQL Playground 对其进行测试并试用订阅。

目前,我可以定义 customResolverscustomSubscriptionResolvers,但我很确定我可以从控制器自动化这两个对象。

干杯!