Deploy a GraphQL API as an Azure Function
In this article, learn how to deploy a GraphQL API to Azure in an Azure Function.
This sample demonstrates using the Apollo server in an Azure function to receive a GraphQL query and return the result.
{
hello
}
The server responds with JSON:
{
"hello": "Hello from GraphQL backend"
}
Prepare your development environment
Make sure the following are installed on your local developer workstation:
- An Azure account with an active subscription which you own. Create an account for free.
- Node.js 14 and npm - installed to your local machine.
- Visual Studio Code - installed to your local machine.
- Visual Studio Code extensions:
- Azure Functions extension for Visual Studio Code.
Clone and run the Azure Function GraphQL sample code
Open a terminal window and
cdto the directory where you want to clone the sample code.Clone the sample code repository:
git clone https://github.com/Azure-Samples/js-e2e-azure-function-graphql-hello.gitOpen that directory in Visual Studio Code:
cd js-e2e-azure-function-graphql-hello && code .Install the project dependencies:
npm installRun the sample:
npm start
Query local Azure Function with GraphQL using GraphQL playground
The npm package apollo-server-azure-functions includes a GraphQL playground that you can use to test your GraphQL API. Use this playground to test the GraphQL API locally.
Open browser to
http://localhost:7071/api/graphqlEnter query
{hello}View response
{"data":{"hello":"Hello from GraphQL backend"}}
Query Azure Function with GraphQL using cURL
In VS Code, open an integrated terminal.
Enter the cURL command:
curl 'http://localhost:7071/api/graphql' \ -H 'content-type: application/json' \ --data-raw '{"query":"{hello}"}'View the response
{"data":{"hello":"Hello from GraphQL backend"}}
Create your Azure Function resource from VS Code
In VS Code, select the Azure explorer.
In the Azure Functions section, select the Azure subscription to create the Azure Function resource in, then right-click to select Create Function App in Azure.
Complete the prompts:
Prompt Enter Enter a globally unique name for the new function app. Enter a unique name, which is used as the subdomain of the URL, such as YOURALIAS-azure-function-graphql-hello.Select a runtime stack. Node.js 14 LTS Select a location for new resources. Select a geographic location close to you. VS Code notifies you when the deployment completes.
Deploy your GraphQL API from VS Code
In VS Code, still in the Azure explorer, find your new Azure Function resource under your subscription.
Right-click the resource and select Deploy to Function App.
Select output window from the notification to watch the deployment.
When the deployment completes, continue to the next section.
Query your GraphQL API with cURL
In VS Code, open an integrated terminal.
Change the cURL command from using your local function to your remove function. Change the URL in the following command to use your Azure Function URL:
curl 'https://diberry-azure-function-graphql-hello.azurewebsites.net/api/graphql' \ -H 'content-type: application/json' \ --data-raw '{"query":"{hello}"}' |The API responds with:
{"data":{"hello":"Hello from our GraphQL backend!"}}
Review the code
The code used in this article requires the npm package apollo-server-azure-functions to resolve your GraphQL query.
The code for this query is in the ./graphql/index.ts file.
import { ApolloServer, gql} from "apollo-server-azure-functions";
// Construct a schema, using GraphQL schema language
const typeDefs = gql`
type Query {
hello: String
}
`;
// Provide resolver functions for your schema fields
const resolvers = {
Query: {
hello: () => "Hello from our GraphQL backend!",
},
};
// @ts-ignore
const server = new ApolloServer({ typeDefs, resolvers, debug: true,playground: true});
export default server.createHandler({
cors: {
origin: '*'
},
});
The highlighted lines are described in the following table:
| Line | Description |
|---|---|
const typeDefs = gql |
Define the GraphQL schema the API supports. |
const resolvers |
Define the handlers for the GraphQL schema (known as resolvers in GraphQL). hello, from our schema, is given a resolver function to return data from the API: () => "Hello from our GraphQL backend!". |
const server = new ApolloServer({ typeDefs, resolvers }); |
Create an Azure Function version of the Apollo server with the typeDefs, resolvers, and the playground. |
Troubleshooting graphql API
Use the following troubleshooting guide to resolve any issues.
| Issue | Possible fix |
|---|---|
| cURL command doesn't return anything | In VS Code, expand the Azure Function resource in the Azure explorer. Under the Files node, make sure all your local files have been moved to the remote location and the /dist folder has been generated. If the files are not present, redeploy the app and watch the deployment output for any errors. If the files do exist, run the cURL command again, adding --verbose to the end of the command to see what status code is returned. |
| API doesn't return anything - but the code is correct. | The Azure Function returns the Apollo server's results if the ./graphql/function.json correctly states the name of the return binding as $return. If you played with the function.json file, make sure the http binding name is reset to the value of $return. Another possible issue is if you changed authLevel, also found in the function.json file from anonymous to another value, you need to either change the value back to anonymous or correctly pass in the authentication when you use the API. |
Did you run into an issue not described in the preceding table? Open an issue to let us know.
Design a second API to allow create, update, and read API endpoints
Consider a new API with the following endpoint to manage messages:
/api/mymessages/getMessage/api/mymessages/getMessages/api/mymessages/createMessage/api/mymessages/updateMessage
A single data element has a unique identifer, content, and author data. Internal to the Azure Function, that looks like
{"79e4c338-162d-4c1e-a6f0-320bd78a7817": {
"author": "dina",
"content": "good morning"
}
}
The resolver can reshape the data returned from the API to look like:
[
{
"id":"79e4c338-162d-4c1e-a6f0-320bd78a7817",
"author": "dina",
"content": "good morning"
}
]
If the query only requests certain fields such as id and content, the Apollo server prunes the data instead of the resolver:
[
{
"id":"79e4c338-162d-4c1e-a6f0-320bd78a7817",
"content": "good morning"
}
]
The key is that the resolver can reshape the data and the Apollo server can prune the data to match the query.
Add second GraphQL API to Azure Function
In VS Code, select View, then select the Command Palette.
Search for and select Azure Functions: Create Function.
Complete the prompts:
Prompt Enter Select a template for your function HTTP trigger Provide a function name mymessages Authorization Anonymous
Add code for new GraphQL API
In the
./mymessages/index.ts, replace the entire file with the following code:import { ApolloServer, gql} from "apollo-server-azure-functions"; import { uuid } from 'uuidv4'; const database = { [uuid()] :{"author": "dina", "content": "good morning"} }; const typeDefs = gql` input MessageInput { content: String author: String } type Message { id: ID! content: String author: String } type Query { getMessage(id: ID!): Message, getMessages:[Message] } type Mutation { createMessage(input: MessageInput): Message updateMessage(id: ID!, input: MessageInput): Message } `; class Message { id: any; content: string; author: string; constructor(id: String, {content, author}) { this.id = id; this.content = content; this.author = author; } } const resolvers = { Mutation: { createMessage: (_, {input}) => { const id = uuid(); database[id] = input; return new Message(id, input); }, updateMessage: (_, {id, input}) => { if (!database[id]) { throw new Error('no message exists with id ' + id); } database[id] = input; return new Message(id, input); }, }, Query: { getMessage: (_, {id}) => { if (!database[id]) { throw new Error('no message exists with id ' + id); } return new Message(id, database[id]); }, getMessages: (_, ) => { let arr = []; for (var key in database) { if (database.hasOwnProperty(key)) { arr.push({ id: key, author: database[key].author, content: database[key].content }); } } return arr; }, } }; // @ts-ignore const server = new ApolloServer({ typeDefs, resolvers, playground: true}); export default server.createHandler({ cors: { origin: '*' }, });In the
./mymessages/function.jsonfile, change the second name object to use$returnso that the Apollo server can return functionality correctly through the Azure Function:{ "type": "http", "direction": "out", "name": "$return" }In the VS Code integrated terminal, build and start the function:
npm run build && npm startOpen the playground in a browser
http://localhost:7071/api/mymessages.Enter and run each of the following GraphQL queries in the playground. The
idvalue you see will be different from theidvalues listed below because these values are randomly generated.Purpose Query Result Get all messages {getMessages{id, author, content}}{"data": {"getMessages": [{"id": "d8732ed5-26d8-4975-98a5-8923e320a77f","author": "dina", "content": "good morning"}]}}Add one messages mutation{createMessage(input:{author: "John Doe",content: "Oh happy day"}){id}}{"data": {"createMessage": {"id": "33febdf6-e618-4884-ae4d-90827280d2b2"}}}Get one message {getMessage(id: "33febdf6-e618-4884-ae4d-90827280d2b2"){id, content, author}}{"data": {"getMessage": {"id": "33febdf6-e618-4884-ae4d-90827280d2b2","content": "Oh happy day", "author": "John Doe"}}}Update one message mutation{ updateMessage (id: "33febdf6-e618-4884-ae4d-90827280d2b2",input:{author: "John Doe", content: "another great day..." }){id, content, author}}{"data": {"updateMessage": {"id": "33febdf6-e618-4884-ae4d-90827280d2b2","content": "another great day...","author": "John Doe"}}}To deploy to your cloud-based Azure Function, repeat the deployment steps.