web-dev-qa-db-fra.com

Apollo-client fonctionne-t-il sur node.js?

J'ai besoin d'une bibliothèque client graphql pour fonctionner sur node.js pour certains tests et certains mashups de données - pas en capacité de production. J'utilise apollo partout ailleurs (react-apollo, apollo's graphql-server-express). Mes besoins sont assez simples.

Est apollo-client un choix viable? Je ne trouve aucun exemple ou document sur son utilisation sur le nœud - si vous en connaissez, partagez-le.

Ou peut-être devrais-je/peux-je utiliser le client graphql de référence sur le nœud?

28
Ed Staub

Apollo Client devrait très bien fonctionner sur Node. Vous n'avez qu'à installer cross-fetch car cela suppose que fetch existe.

Voici une implémentation TypeScript complète d'Apollo Client fonctionnant sur Node.js.

import ApolloClient from "apollo-boost";
import gql from "graphql-tag";
import { InsertJob } from "./graphql-types";
import 'cross-fetch/polyfill';

const client = new ApolloClient({
  uri: "http://localhost:3000/graphql"
});


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));
11
André Pena

Si quelqu'un recherche une version 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);
})

Voici une implémentation simple du nœud js.

Le client 'graphiql' est assez bon pour les activités de développement.

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
});
2
sarang

En réponse au commentaire de @YakirNa:

Je ne peux pas parler des autres besoins que j'ai décrits, mais j'ai fait pas mal de tests. J'ai fini par faire tous mes tests en cours.

La plupart des tests finissent par être des tests de résolveur, ce que je fais via un gabarit qui appelle la fonction graphql de la bibliothèque graphql avec une requête de test, puis valide la réponse.

J'ai également une couche de test de bout en bout (presque) qui fonctionne au niveau de la gestion http de l'express. Il crée une fausse requête HTTP et vérifie la réponse en cours. Tout cela fait partie du processus serveur; rien ne passe sur le fil. J'utilise cela à la légère, principalement pour tester l'authentification JWT et d'autres comportements au niveau de la demande qui sont indépendants du corps de la requête graphql.

1
Ed Staub

Je me heurtais à votre même question, car je voulais créer un service middleware pour préparer les données de graphQL vers une application frontale finale, pour avoir:

  • représentation des données optimisée (et interface de données de sortie standard)
  • temps de réponse plus rapide

en supposant que le serveur graphQL est fourni par un fournisseur externe, donc pas de propriété du modèle de données, directement avec GQL

Je ne voulais donc pas implémenter GraphQL Apolloclient directement dans un framework frontal comme React/Angular, Vuejs ... mais gérer les requêtes via Nodejs au backend d'un REST API.

Voici donc l'encapsuleur de classe pour Apolloclient que j'ai pu assembler (en utilisant TypeScript):

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',
                },
            }
        });
    }
}   

Après ce constructeur, je lance des requêtes comme:

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

Comme vous l'avez peut-être remarqué:

  • Je devais injecter fetch sur Httplink

  • J'ai dû configurer des en-têtes d'autorisation pour accéder au point de terminaison graphQL du fournisseur externe

  • J'ai utilisé IntrospectionFragmentMatcher afin d'utiliser des fragments dans mes requêtes, ainsi que le type de schéma de construction ("fragmentTypes.json" avec un script init)

Publier ceci pour simplement ajouter mon expérience et peut-être plus d'informations pour la question. J'attends également avec impatience des commentaires et des points d'amélioration pour ce wrapper.

0
koalaok