-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a750507
commit 814db56
Showing
9 changed files
with
339 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
* | ||
!dist | ||
!dist/**/* | ||
dist/**/*.test.* | ||
!package.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# graphql-server-lambda | ||
|
||
This is the Azure Functions integration for the Apollo community GraphQL Server. [Read the docs.](http://dev.apollodata.com/tools/apollo-server/index.html) | ||
|
||
|
||
## Example: | ||
|
||
```js | ||
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); | ||
} | ||
}; | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
{ | ||
"name": "apollo-server-azure-functions", | ||
"version": "1.1.0", | ||
"description": "Node.js GraphQl server for Azure Functions", | ||
"main": "dist/index.js", | ||
"scripts": { | ||
"compile": "tsc", | ||
"prepublish": "npm run compile" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/apollographql/apollo-server/tree/master/packages/apollo-server-azure-functions" | ||
}, | ||
"keywords": [ | ||
"GraphQL", | ||
"Apollo", | ||
"Server", | ||
"Azure", | ||
"Functions" | ||
], | ||
"author": "Ulrik Strid <[email protected]>", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/apollographql/apollo-server/issues" | ||
}, | ||
"homepage": "https://github.com/apollographql/apollo-server#readme", | ||
"dependencies": { | ||
"apollo-server-core": "^1.0.2", | ||
"apollo-server-module-graphiql": "^1.0.5" | ||
}, | ||
"devDependencies": { | ||
"azure-functions-typescript": "0.0.1", | ||
"@types/graphql": "^0.10.1", | ||
"apollo-server-integration-testsuite": "^1.0.5" | ||
}, | ||
"peerDependencies": { | ||
"graphql": "^0.9.0 || ^0.10.1" | ||
}, | ||
"typings": "dist/index.d.ts", | ||
"typescript": { | ||
"definition": "dist/index.d.ts" | ||
} | ||
} |
89 changes: 89 additions & 0 deletions
89
packages/apollo-server-azure-functions/src/azureFunctionsApollo.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import { | ||
AzureFunctionsHandler, | ||
graphqlAzureFunctions, | ||
graphiqlAzureFunctions, | ||
} from './azureFunctionsApollo'; | ||
import testSuite, { | ||
schema as Schema, | ||
CreateAppOptions, | ||
} from 'apollo-server-integration-testsuite'; | ||
import { expect } from 'chai'; | ||
import { GraphQLOptions } from 'apollo-server-core'; | ||
import 'mocha'; | ||
import * as url from 'url'; | ||
|
||
function createFunction(options: CreateAppOptions = {}) { | ||
let route, callback, context; | ||
let handler: AzureFunctionsHandler; | ||
|
||
options.graphqlOptions = options.graphqlOptions || { schema: Schema }; | ||
if (options.graphiqlOptions) { | ||
route = '/graphiql'; | ||
handler = graphiqlAzureFunctions(options.graphiqlOptions); | ||
} else { | ||
route = '/graphql'; | ||
handler = graphqlAzureFunctions(options.graphqlOptions); | ||
} | ||
|
||
return function(req, res) { | ||
if (!req.url.startsWith(route)) { | ||
res.statusCode = 404; | ||
res.end(); | ||
return; | ||
} | ||
|
||
let body = ''; | ||
req.on('data', function(chunk) { | ||
body += chunk; | ||
}); | ||
req.on('end', function() { | ||
let urlObject = url.parse(req.url, true); | ||
const request = { | ||
method: req.method, | ||
originalUrl: req.url, | ||
query: urlObject.query, | ||
headers: req.headers, | ||
body: body, | ||
rawbody: body, | ||
}; | ||
|
||
context = { | ||
done: function(error, result) { | ||
res.statusCode = result.status; | ||
for (let key in result.headers) { | ||
if (result.headers.hasOwnProperty(key)) { | ||
res.setHeader(key, result.headers[key]); | ||
} | ||
} | ||
|
||
if (error) { | ||
res.error = error; | ||
} | ||
|
||
res.write(result.body); | ||
res.end(); | ||
}, | ||
}; | ||
|
||
handler(context, request); | ||
}); | ||
}; | ||
} | ||
|
||
describe('azureFunctionsApollo', () => { | ||
it('throws error if called without schema', function() { | ||
expect(() => graphqlAzureFunctions(undefined as GraphQLOptions)).to.throw( | ||
'Apollo Server requires options.', | ||
); | ||
}); | ||
|
||
it('throws an error if called with more than one argument', function() { | ||
expect(() => (<any>graphqlAzureFunctions)({}, {})).to.throw( | ||
'Apollo Server expects exactly one argument, got 2', | ||
); | ||
}); | ||
}); | ||
|
||
describe('integration:Azure Functions', () => { | ||
testSuite(createFunction); | ||
}); |
126 changes: 126 additions & 0 deletions
126
packages/apollo-server-azure-functions/src/azureFunctionsApollo.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import { | ||
IHttpContext, | ||
IFunctionRequest, | ||
HttpStatusCodes, | ||
} from 'azure-functions-typescript'; | ||
import { GraphQLOptions, runHttpQuery } from 'apollo-server-core'; | ||
import * as GraphiQL from 'apollo-server-module-graphiql'; | ||
|
||
export interface AzureFunctionsGraphQLOptionsFunction { | ||
(context: IHttpContext): GraphQLOptions | Promise<GraphQLOptions>; | ||
} | ||
|
||
export interface AzureFunctionsHandler { | ||
(context: IHttpContext, request: IFunctionRequest): void; | ||
} | ||
|
||
export interface IHeaders { | ||
'content-type'?: string; | ||
'content-length'?: HttpStatusCodes | number; | ||
'content-disposition'?: string; | ||
'content-encoding'?: string; | ||
'content-language'?: string; | ||
'content-range'?: string; | ||
'content-location'?: string; | ||
'content-md5'?: Buffer; | ||
'expires'?: Date; | ||
'last-modified'?: Date; | ||
[header: string]: any; | ||
} | ||
|
||
export interface AzureFunctionsGraphiQLOptionsFunction { | ||
(context: IHttpContext, request: IFunctionRequest): | ||
| GraphiQL.GraphiQLData | ||
| Promise<GraphiQL.GraphiQLData>; | ||
} | ||
|
||
export function graphqlAzureFunctions( | ||
options: GraphQLOptions | AzureFunctionsGraphQLOptionsFunction, | ||
): AzureFunctionsHandler { | ||
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 (httpContext: IHttpContext, request: IFunctionRequest) => { | ||
const 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 runHttpQuery([httpContext, request], queryRequest) | ||
.then(gqlResponse => { | ||
const result = { | ||
status: 200, | ||
headers: { 'Content-Type': 'application/json' }, | ||
body: gqlResponse, | ||
}; | ||
|
||
httpContext.res = result; | ||
|
||
httpContext.done(null, result); | ||
}) | ||
.catch(error => { | ||
const result = { | ||
status: error.statusCode, | ||
headers: error.headers, | ||
body: error.message, | ||
}; | ||
|
||
httpContext.res = result; | ||
|
||
httpContext.done(null, result); | ||
}); | ||
}; | ||
} | ||
|
||
/* This Azure Functions Handler returns the html for the GraphiQL interactive query UI | ||
* | ||
* GraphiQLData arguments | ||
* | ||
* - endpointURL: the relative or absolute URL for the endpoint which GraphiQL will make queries to | ||
* - (optional) query: the GraphQL query to pre-fill in the GraphiQL UI | ||
* - (optional) variables: a JS object of variables to pre-fill in the GraphiQL UI | ||
* - (optional) operationName: the operationName to pre-fill in the GraphiQL UI | ||
* - (optional) result: the result of the query to pre-fill in the GraphiQL UI | ||
*/ | ||
|
||
export function graphiqlAzureFunctions( | ||
options: GraphiQL.GraphiQLData | AzureFunctionsGraphiQLOptionsFunction, | ||
) { | ||
return (httpContext: IHttpContext, request: IFunctionRequest) => { | ||
const query = request.query; | ||
|
||
GraphiQL.resolveGraphiQLString(query, options, httpContext, request).then( | ||
graphiqlString => { | ||
httpContext.res = { | ||
status: 200, | ||
headers: { | ||
'Content-Type': 'text/html', | ||
}, | ||
body: graphiqlString, | ||
}; | ||
|
||
httpContext.done(null, httpContext.res); | ||
}, | ||
error => { | ||
httpContext.res = { | ||
status: 500, | ||
body: error.message, | ||
}; | ||
|
||
httpContext.done(null, httpContext.res); | ||
}, | ||
); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
export { | ||
AzureFunctionsHandler, | ||
IHeaders, | ||
AzureFunctionsGraphQLOptionsFunction, | ||
AzureFunctionsGraphiQLOptionsFunction, | ||
graphqlAzureFunctions, | ||
graphiqlAzureFunctions, | ||
} from './azureFunctionsApollo'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"extends": "../../tsconfig", | ||
"compilerOptions": { | ||
"rootDir": "./src", | ||
"outDir": "./dist", | ||
"typeRoots": [ | ||
"node_modules/@types" | ||
], | ||
"types": [ | ||
"@types/node" | ||
] | ||
}, | ||
"exclude": [ | ||
"node_modules", | ||
"dist" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters