Skip to content

Commit

Permalink
fix: GraphQL throws TypeError: Cannot read property 'startToken' of u…
Browse files Browse the repository at this point in the history
…ndefined (#619)

Co-authored-by: Daniel Dyla <dyladan@users.noreply.github.com>
  • Loading branch information
obecny and dyladan committed Aug 31, 2021
1 parent f0fa800 commit 5fb3313
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 12 deletions.
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,
},
});
};
18 changes: 12 additions & 6 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.2",
"@opentelemetry/exporter-collector": "^0.25.0",
"@opentelemetry/instrumentation": "^0.25.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.25.0",
"@opentelemetry/sdk-trace-node": "^0.25.0",
"@opentelemetry/sdk-trace-base": "^0.25.0",
"@opentelemetry/node": "^0.25.0",
"@opentelemetry/tracing": "^0.25.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 @@ -30,7 +30,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
13 changes: 8 additions & 5 deletions plugins/node/opentelemetry-instrumentation-graphql/src/utils.ts
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

0 comments on commit 5fb3313

Please sign in to comment.