Graphql with Azure functions

2019-04-02 04:35发布

问题:

is there a way to implement Graphql via azure functions and nodejs. For example, something like - https://www.npmjs.com/package/graphql-server-lambda

回答1:

Apollo provides Azure Function Integration for GraphQL:

apollo-server-azure-functions

Here is the sample provided on their github repo:

const server = require("apollo-server-azure-functions");
const graphqlTools = require("graphql-tools");

const typeDefs = `
  type Random {
    id: Int!
    rand: String
  }

  type Query {
    rands: [Random]
    rand(id: Int!): Random
  }
`;

const rands = [{ id: 1, rand: "random" }, { id: 2, rand: "modnar" }];

const resolvers = {
  Query: {
    rands: () => rands,
    rand: (_, { id }) => rands.find(rand => rand.id === id)
  }
};

const schema = graphqlTools.makeExecutableSchema({
  typeDefs,
  resolvers
});

module.exports = function run(context, request) {
  if (request.method === "POST") {
    server.graphqlAzureFunctions({
        endpointURL: '/api/graphql'
    })(context, request);
  } else if (request.method === "GET") {
    return server.graphiqlAzureFunctions({
        endpointURL: '/api/graphql'
    })(context, request);
  }
};


回答2:

So I got this working using Apollo and Azure Functions. There is a mistake in the example for apollo-server-azure-functions, and a minor error in that wrapper library that returns string and not JSON data. You also need to install graphql-tools separately.

In the example code the schema object is created, but not added to the parameters passed to Apollo server. The working code is below. I've just added schema to the options passed.

const server = require("apollo-server-azure-functions");
const graphqlTools = require("graphql-tools");

const typeDefs = `
  type Random {
    id: Int!
    rand: String
  }

  type Query {
    rands: [Random]
    rand(id: Int!): Random
  }
`;

const rands = [{ id: 1, rand: "random" }, { id: 2, rand: "modnar" }];

const resolvers = {
  Query: {
    rands: () => rands,
    rand: (_, { id }) => rands.find(rand => rand.id === id)
  }
};

const schema = graphqlTools.makeExecutableSchema({
  typeDefs,
  resolvers
});

module.exports = function run(context, req) {
  if (req.method === 'POST') {
    server.graphqlAzureFunctions({
      endpointURL: '/api/graphql',
      schema: schema
    })(context, req);
  } else if (req.method === 'GET') {
    return server.graphiqlAzureFunctions({
      endpointURL: '/api/graphql',
      schema: schema
    })(context, req);
  }
};

Just doing this change you will start to get data back from your endpoint, but unfortunately it will not be of type application/json. For that a small change needs to be made to apollo-server-azure-functions to convert the body from string to JSON. I've submitted a PR for this to happen, but not sure when they will get to it.

If you're not patient, you can create your own wrapper function with the code below which will work with the example above and return JSON not a string.

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var apollo_server_core_1 = require("apollo-server-core");
var GraphiQL = require("apollo-server-module-graphiql");
function graphqlAzureFunctions(options) {
    if (!options) {
        throw new Error('Apollo Server requires options.');
    }
    if (arguments.length > 1) {
        throw new Error("Apollo Server expects exactly one argument, got " + arguments.length);
    }
    return function (httpContext, request) {
        var queryRequest = {
            method: request.method,
            options: options,
            query: request.method === 'POST' ? request.body : request.query,
        };
        if (queryRequest.query && typeof queryRequest.query === 'string') {
            queryRequest.query = JSON.parse(queryRequest.query);
        }
        return apollo_server_core_1.runHttpQuery([httpContext, request], queryRequest)
            .then(function (gqlResponse) {
            var result = {
                status: 200,
                headers: { 'Content-Type': 'application/json' },
                body: JSON.parse(gqlResponse),
            };
            httpContext.res = result;
            httpContext.done(null, result);
        })
            .catch(function (error) {
            var result = {
                status: error.statusCode,
                headers: error.headers,
                body: error.message,
            };
            httpContext.res = result;
            httpContext.done(null, result);
        });
    };
}
exports.graphqlAzureFunctions = graphqlAzureFunctions;
function graphiqlAzureFunctions(options) {
    return function (httpContext, request) {
        var query = request.query;
        GraphiQL.resolveGraphiQLString(query, options, httpContext, request).then(function (graphiqlString) {
            httpContext.res = {
                status: 200,
                headers: {
                    'Content-Type': 'text/html',
                },
                body: graphiqlString,
            };
            httpContext.done(null, httpContext.res);
        }, function (error) {
            httpContext.res = {
                status: 500,
                body: error.message,
            };
            httpContext.done(null, httpContext.res);
        });
    };
}
exports.graphiqlAzureFunctions = graphiqlAzureFunctions;

For this to work you will need to install apollo-server-core and apollo-server-module-grapiql as dependencies via npm.



回答3:

There's no native support for this, but there's nothing preventing you from creating a GraphQL schema that calls into Azure Functions.

However, there are some community offerings in the space like scaphold which work to integrate Azure Functions / serverless providers with GraphQL:

https://docs.scaphold.io/custom-logic/