Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: GraphQL throws TypeError: Cannot read property 'startToken' of undefined #619

Merged
merged 4 commits into from Aug 31, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions examples/graphql/README.md
Expand Up @@ -46,6 +46,12 @@ npm install
```

5. You can also write your own queries, open page `http://localhost:4000/graphql`
6. You can also test a `graphql-transform-federation`
```shell script
# from this directory
npm run server:federation
npm run client:federation
```

## Useful links

Expand Down
44 changes: 44 additions & 0 deletions examples/graphql/client-federation.js
@@ -0,0 +1,44 @@
'use strict';

const url = require('url');
const http = require('http');
// Construct a schema, using GraphQL schema language

const source = `
{
continents {
code
name
}
}
`;

makeRequest(source).then(console.log);

function makeRequest(query) {
return new Promise((resolve, reject) => {
const parsedUrl = new url.URL('http://localhost:4000/graphql');
const options = {
hostname: parsedUrl.hostname,
port: parsedUrl.port,
path: parsedUrl.pathname,
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
};
const req = http.request(options, (res) => {
const data = [];
res.on('data', (chunk) => data.push(chunk));
res.on('end', () => {
resolve(data.toString());
});
res.on('error', (err) => {
reject(err);
});
});

req.write(JSON.stringify({ query }));
req.end();
});
}
31 changes: 31 additions & 0 deletions examples/graphql/countries-service.js
@@ -0,0 +1,31 @@
'use strict';

const { fetch } = require('cross-fetch');
const { print } = require('graphql');
const { wrapSchema, introspectSchema } = require('@graphql-tools/wrap');
const { transformSchemaFederation } = require('graphql-transform-federation');

const executor = async ({ document, variables }) => {
const query = print(document);
const fetchResult = await fetch('https://countries.trevorblades.com/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ query, variables }),
});
return fetchResult.json();
};

module.exports = async () => {
const schema = wrapSchema({
schema: await introspectSchema(executor),
executor,
});

return transformSchemaFederation(schema, {
Query: {
extend: true,
},
});
};
14 changes: 10 additions & 4 deletions examples/graphql/package.json
Expand Up @@ -6,11 +6,13 @@
"main": "index.js",
"scripts": {
"client": "node ./client.js",
"client:federation": "node ./client-federation.js",
"docker:start": "cd ./docker && docker-compose down && docker-compose up",
"docker:startd": "cd ./docker && docker-compose down && docker-compose up -d",
"docker:stop": "cd ./docker && docker-compose down",
"server:apollo": "node ./server-apollo.js",
"server:express": "node ./server-express.js",
"server:apollo": "node ./server-apollo.js"
"server:federation": "node ./server-federation.js"
},
"repository": {
"type": "git",
Expand All @@ -31,18 +33,22 @@
"url": "https://github.com/open-telemetry/opentelemetry-js/issues"
},
"dependencies": {
"@apollo/gateway": "^0.19.1",
"@graphql-tools/wrap": "^6.0.18",
"@opentelemetry/api": "^1.0.1",
"@opentelemetry/exporter-collector": "^0.24.0",
"@opentelemetry/instrumentation": "^0.24.0",
"@opentelemetry/instrumentation-express": "^0.23.0",
"@opentelemetry/instrumentation-graphql": "^0.23.0",
"@opentelemetry/instrumentation-express": "^0.24.0",
"@opentelemetry/instrumentation-graphql": "^0.24.0",
"@opentelemetry/instrumentation-http": "^0.24.0",
"@opentelemetry/node": "^0.24.0",
"@opentelemetry/tracing": "^0.24.0",
"apollo-server": "^2.18.1",
"cross-fetch": "^3.0.5",
"express": "^4.17.1",
"express-graphql": "^0.11.0",
"graphql": "^15.3.0"
"graphql": "^15.3.0",
"graphql-transform-federation": "^2.1.0"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js#readme",
"devDependencies": {
Expand Down
54 changes: 54 additions & 0 deletions examples/graphql/server-federation.js
@@ -0,0 +1,54 @@
'use strict';

require('./tracer');

const { ApolloServer } = require('apollo-server');
const {
ApolloGateway,
RemoteGraphQLDataSource,
LocalGraphQLDataSource,
} = require('@apollo/gateway');

const getCountriesSchema = require('./countries-service');

const setupGateway = async () => {
const countriesSchema = await getCountriesSchema();

const gateway = new ApolloGateway({
serviceList: [{ name: 'countries', url: 'http://countries' }],

// Experimental: Enabling this enables the query plan view in Playground.
__exposeQueryPlanExperimental: false,

buildService: ({ url }) => {
if (url === 'http://countries') {
return new LocalGraphQLDataSource(countriesSchema);
}
return new RemoteGraphQLDataSource({
url,
});
},
});

return gateway;
};

(async () => {
const gateway = await setupGateway();

const server = new ApolloServer({
gateway,

// Apollo Graph Manager (previously known as Apollo Engine)
// When enabled and an `ENGINE_API_KEY` is set in the environment,
// provides metrics, schema management and trace reporting.
engine: false,

// Subscriptions are unsupported but planned for a future Gateway version.
subscriptions: false,
});

server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
})();
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -27,7 +27,8 @@
"lint": "lerna run lint",
"lint:fix": "lerna run lint:fix",
"lint:examples": "eslint ./examples/**/*.js",
"lint:examples:fix": "eslint ./examples/**/*.js --fix"
"lint:examples:fix": "eslint ./examples/**/*.js --fix",
"lerna:scope": "lerna bootstrap --include-dependents --include-dependencies --scope"
},
"keywords": [
"opentelemetry",
Expand Down
Expand Up @@ -34,7 +34,7 @@ const OPERATION_VALUES = Object.values(AllowedOperationTypes);

export function addSpanSource(
span: api.Span,
loc: graphqlTypes.Location,
loc?: graphqlTypes.Location,
allowValues?: boolean,
start?: number,
end?: number
Expand Down Expand Up @@ -212,14 +212,17 @@ const KindsToBeRemoved: string[] = [
];

export function getSourceFromLocation(
loc: graphqlTypes.Location,
loc?: graphqlTypes.Location,
allowValues = false,
start: number = loc.start,
end: number = loc.end
inputStart?: number,
inputEnd?: number
): string {
let source = '';

if (loc.startToken) {
if (loc?.startToken) {
const start = typeof inputStart === 'number' ? inputStart : loc.start;
const end = typeof inputEnd === 'number' ? inputEnd : loc.end;

let next: graphqlTypes.Token | null = loc.startToken.next;
let previousLine: number | undefined = 1;
while (next) {
Expand Down