|
| 1 | +import * as path from 'path'; |
| 2 | +import * as express from 'express'; |
| 3 | +import * as graphqlHTTP from 'express-graphql'; |
| 4 | +import {red, green, blue} from 'chalk'; |
| 5 | +import fetch from 'node-fetch'; |
| 6 | +import { Kind, print, introspectionQuery, buildClientSchema, visit, TypeInfo, visitWithTypeInfo } from 'graphql'; |
| 7 | + |
| 8 | +const coverage = {}; |
| 9 | +const originUrl = process.argv[2]; |
| 10 | +if (!originUrl) throw Error('Specify URL as the 1st argument!'); |
| 11 | + |
| 12 | +(async () => { |
| 13 | + const introspection = await graphqlFetch({query: introspectionQuery}); |
| 14 | + if (introspection.errors) throw Error(JSON.stringify(introspection.errors, null, 2)); |
| 15 | + const schema = buildClientSchema(introspection.data), app = express(); |
| 16 | + const formatErrorFn = (err) => err; |
| 17 | + app.use('/graphql', graphqlHTTP({ schema, execute, graphiql: true, formatErrorFn })); |
| 18 | + app.get('/coverage-map', (_, res) => res.status(200).json(coverage)); |
| 19 | + app.use('/coverage', express.static(path.join(__dirname, 'static'))); |
| 20 | + const port = 9003; |
| 21 | + app.listen(port); |
| 22 | + console.log(`\n${green('✔')} Your GraphQL Fake API is ready to use 🚀 \n |
| 23 | + ${blue('❯')} Coverage Graph:\t http://localhost:${port}/coverage |
| 24 | + ${blue('❯')} GraphQL API:\t http://localhost:${port}/graphql`); |
| 25 | +})() |
| 26 | + .catch(error => console.error(red(error.stack))); |
| 27 | + |
| 28 | +async function graphqlFetch(body) { |
| 29 | + const res = await fetch(originUrl, { |
| 30 | + method: 'POST', |
| 31 | + body: JSON.stringify(body), |
| 32 | + headers: { "content-type": 'application/json' }, |
| 33 | + }); |
| 34 | + if (!res.ok) |
| 35 | + throw Error(`${res.status} ${res.statusText}\n${await res.text()}`); |
| 36 | + return res.json(); |
| 37 | +} |
| 38 | + |
| 39 | +async function execute({schema, document, variableValues: variables, operationName}) { |
| 40 | + const typeInfo = new TypeInfo(schema); |
| 41 | + visit(document, visitWithTypeInfo(typeInfo, { |
| 42 | + [Kind.FIELD]: () => { |
| 43 | + const typeName = typeInfo.getParentType().name; |
| 44 | + const fieldName = typeInfo.getFieldDef().name; |
| 45 | + if (typeName.startsWith('__') || fieldName.startsWith('__')) return; |
| 46 | + coverage[`${typeName}::${fieldName}`] = true; |
| 47 | + }, |
| 48 | + })); |
| 49 | + return await graphqlFetch({ query: print(document), variables, operationName }); |
| 50 | +} |
0 commit comments