apollo-client 在 node.js 上工作吗?

Does apollo-client work on node.js?

我需要一个 graphql 客户端库 到 运行 在 node.js 上进行一些测试和一些数据混搭 - 不在生产能力中。我在其他任何地方都使用 apollo(react-apollo,apollo 的 graphql-server-express)。我的需求很简单。

apollo-client 是一个可行的选择吗?我找不到在节点上使用它的示例或文档 - 如果您知道,请分享。

或者我 should/can 在节点上使用参考 graphql 客户端?

这里是简单的node js实现。

'graphiql' 客户端足以进行开发活动。

1. run npm install
2. start server with "node server.js"
3. hit "http://localhost:8080/graphiql"  for graphiql client

server.js

var graphql = require ('graphql').graphql  
var express = require('express')  
var graphQLHTTP = require('express-graphql')  

var Schema = require('./schema')  

// This is just an internal test
var query = 'query{starwar{name, gender,gender}}'  
graphql(Schema, query).then( function(result) {  
  console.log(JSON.stringify(result,null," "));
});

var app = express()  
  .use('/', graphQLHTTP({ schema: Schema, pretty: true, graphiql: true }))
  .listen(8080, function (err) {
    console.log('GraphQL Server is now running on localhost:8080');
  });

schema.js

//schema.js
var graphql = require ('graphql');  
var http = require('http');

var StarWar = [  
  { 
    "name": "default",
    "gender": "default",
    "mass": "default"
  }
];

var TodoType = new graphql.GraphQLObjectType({  
  name: 'starwar',
  fields: function () {
    return {
      name: {
        type: graphql.GraphQLString
      },
      gender: {
        type: graphql.GraphQLString
      },
      mass: {
        type: graphql.GraphQLString
      }
    }
  }
});



var QueryType = new graphql.GraphQLObjectType({  
  name: 'Query',
  fields: function () {
    return {
      starwar: {
        type: new graphql.GraphQLList(TodoType),
        resolve: function () {
          return new Promise(function (resolve, reject) {
            var request = http.get({
              hostname: 'swapi.co',
              path: '/api/people/1/',
              method: 'GET'
            }, function(res){
                    res.setEncoding('utf8');
                    res.on('data', function(response){
                    StarWar = [JSON.parse(response)];
                    resolve(StarWar)

                    console.log('On response success:' , StarWar);
                });
            });

            request.on('error', function(response){
                    console.log('On error' , response.message);
                });

            request.end();                      
          });
        }
      }
    }
  }
});

module.exports = new graphql.GraphQLSchema({  
  query: QueryType
});

回复@YakirNa 的评论:

我不能说我描述的其他需求,但我已经做了相当多的测试。我最终完成了所有过程中的测试。

大多数测试最终都是解析器测试,我通过一个夹具来完成,该夹具使用测试查询调用 graphql 库的 graphql 函数,然后验证响应。

我还有一个(几乎)端到端测试层,它在 express 的 http 处理级别工作。它创建一个伪造的 HTTP 请求并验证进程中的响应。这一切都在服务器进程中;什么都没有通过电线。我很少使用它,主要用于测试 JWT 身份验证和其他独立于 graphql 请求主体的请求级行为。

Apollo Client 在 Node.js 上应该可以正常工作。您只需安装 cross-fetch.

这是在 Node.js 上工作的 Apollo Client 的完整 TypeScript 实现。

import { ApolloClient, gql, HttpLink, InMemoryCache } from "@apollo/client";

import { InsertJob } from "./graphql-types";
import fetch from "cross-fetch";

const client = new ApolloClient({
  link: new HttpLink({ uri: process.env.PRODUCTION_GRAPHQL_URL, fetch }),
  cache: new InMemoryCache(),
});


client.mutate<InsertJob.AddCompany, InsertJob.Variables>({
  mutation: gql`mutation insertJob($companyName: String!) {
      addCompany(input: { displayName: $companyName } ) {
          id
      }
  }`,
  variables: {
    companyName: "aaa"
  }
})
  .then(result => console.log(result));

如果有人正在寻找 JavaScript 版本:

require('dotenv').config();
const gql = require('graphql-tag');
const ApolloClient = require('apollo-boost').ApolloClient;
const fetch = require('cross-fetch/polyfill').fetch;
const createHttpLink = require('apollo-link-http').createHttpLink;
const InMemoryCache = require('apollo-cache-inmemory').InMemoryCache;
const client = new ApolloClient({
    link: createHttpLink({
        uri: process.env.API,
        fetch: fetch
    }),
    cache: new InMemoryCache()
});

client.mutate({
    mutation: gql`
    mutation popJob {
        popJob {
            id
            type
            param
            status
            progress
            creation_date
            expiration_date
        }
    }
    `,
}).then(job => {
    console.log(job);
})

我 运行 遇到了你同样的问题,因为我想创建一个中间件服务来准备从 graphQL 到最终前端应用程序的数据, 有 :

  • 优化数据表示(和标准输出数据接口)
  • 更快的响应时间

假设 graphQL 服务器由外部提供商提供,因此没有数据模型的所有权,直接使用 GQL

所以我不想直接在 React / Angular、Vuejs 等前端框架中实现 GraphQL Apolloclient...而是通过 REST API 后端的 Nodejs 管理查询。

所以这是我能够assemble(使用打字稿)的 Apolloclient 的 class 包装器:

import ApolloClient from "apollo-client";
import { ApolloLink } from 'apollo-link'
import { HttpLink } from 'apollo-link-http'
import { onError } from 'apollo-link-error'
import fetch from 'node-fetch'
import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'
import introspectionQueryResultData from '../../fragmentTypes.json';
import { AppConfig } from 'app-config';


const config: AppConfig = require('../../../appConfig.js');

export class GraphQLQueryClient {
    protected apolloClient: any;

    constructor(headers: { [name: string]: string }) {
        const api: any = {
            spaceId: config.app.spaceId,
            environmentId: config.app.environmentId,
            uri: config.app.uri,
            cdnApiPreviewToken: config.cdnApiPreviewToken,
        };
        // console.log(JSON.stringify(api));
        const ACCESS_TOKEN = api.cdnApiPreviewToken;
        const uri = api.uri;

        console.log(`Apollo client setup to query uri: ${uri}`);

        const fragmentMatcher = new IntrospectionFragmentMatcher({
            introspectionQueryResultData
        });

        this.apolloClient = new ApolloClient({
            link: ApolloLink.from([
                onError(({ graphQLErrors, networkError }:any) => {
                    if (graphQLErrors) {
                        graphQLErrors.map((el:any) =>
                            console.warn(
                                el.message || el
                            )
                        )
                        graphQLErrors.map(({ message, locations, path }:any) =>
                            console.warn(
                                `[GraphQL error - Env ${api.environmentId}]: Message: ${message}, Location: ${JSON.stringify(locations)}, Path: ${path}`
                            )
                        )
                    }
                    if (networkError) console.log(`[Network error]: ${networkError}`)
                }),
                new HttpLink({
                    uri,
                    credentials: 'same-origin',
                    headers: {
                        Authorization: `Bearer ${ACCESS_TOKEN}`
                    },
                    fetch
                })
            ]),
            cache: new InMemoryCache({ fragmentMatcher }),
            // fetchPolicy as network-only avoids using the cache.
            defaultOptions: {
                watchQuery: {
                    fetchPolicy: 'network-only',
                    errorPolicy: 'ignore',
                },
                query: {
                    fetchPolicy: 'network-only',
                    errorPolicy: 'all',
                },
            }
        });
    }
}   

在此构造函数之后,我 运行 查询如下:

let response = await this.apolloClient.query({ query: gql`${query}` });

您可能已经注意到:

  • 我需要在 Httplink 上注入 fetch

  • 我必须设置授权 headers 才能访问外部提供商 graphQL 端点

  • 我使用了 IntrospectionFragmentMatcher 以便在我的查询中使用 Fragments 以及构建模式类型("fragmentTypes.json" 使用初始化脚本)

发布这个只是为了增加我的经验,也许还有更多关于这个问题的信息。 也期待对此包装器的评论和改进点。

较新的 Apollo 版本提供了一种更简单的方法来执行此操作,如 Apollo docs 中所述,请查看“独立”部分。基本上可以简单地使用 ApolloLink 来执行查询或突变。

以下是撰写本文时文档中示例代码的副本,node-fetch 用法作为 createHttpLink 的配置。查看文档以获取有关如何使用这些工具的更多详细信息。

import { execute, makePromise } from 'apollo-link';
import { createHttpLink } from 'apollo-link-http';
import gql from 'graphql-tag';
import fetch from 'node-fetch';

const uri = 'http://localhost:4000/graphql';
const link = createHttpLink({ uri, fetch });

const operation = {
  query: gql`query { hello }`,
  variables: {} //optional
  operationName: {} //optional
  context: {} //optional
  extensions: {} //optional
};

// execute returns an Observable so it can be subscribed to
execute(link, operation).subscribe({
  next: data => console.log(`received data: ${JSON.stringify(data, null, 2)}`),
  error: error => console.log(`received error ${error}`),
  complete: () => console.log(`complete`),
})

// For single execution operations, a Promise can be used
makePromise(execute(link, operation))
  .then(data => console.log(`received data ${JSON.stringify(data, null, 2)}`))
  .catch(error => console.log(`received error ${error}`))

您可以使 apollo-client 工作,但这不是此用例的最佳选择。

试试 graphql-request

Minimal GraphQL client supporting Node and browsers for scripts or simple apps

每个 npmjs 的功能:

  • 最简单轻量级的 GraphQL 客户端
  • Promise-based API(与异步/等待一起使用)
  • 打字稿支持
  • 同构(适用于 Node/浏览器)

示例:

    import { request, gql } from 'graphql-request'
 
    const query = gql`
      {
        Movie(title: "Inception") {
          releaseDate
          actors {
            name
          }
        }
      }
`
 
request('https://api.graph.cool/simple/v1/movies', query).then((data) => console.log(data))

我与这个包裹没有任何关系。