dotellie/apollo-metrics

Incompatible with apollo-server-plugin-base 0.7.1

SpComb opened this issue · 3 comments

Building with apollo-metrics 1.0.1 against a project using apollo-server-plugin-base 0.7.1 results in a TypeScript compile error due to the changes in didEncounterErrors requestContext:

[ERROR] TSError: ⨯ Unable to compile TypeScript:
[ERROR] src/server/server.ts(124,9): error TS2322: Type 'ApolloServerPlugin<Record<string, any>>' is not assignable to type 'PluginDefinition'.
[ERROR]   Type 'import("/build/graphql/node_modules/apollo-server-plugin-base/dist/index").ApolloServerPlugin<Record<string, any>>' is not assignable to type 'import("/build/graphql/node_modules/apollo-server-core/node_modules/apollo-server-plugin-base/dist/index").ApolloServerPlugin<Record<string, any>>'.
[ERROR]     The types returned by 'requestDidStart(...)' are incompatible between these types.
[ERROR]       Type 'void | import("/build/graphql/node_modules/apollo-server-plugin-base/dist/index").GraphQLRequestListener<Record<string, any>>' is not assignable to type 'void | import("/build/graphql/node_modules/apollo-server-core/node_modules/apollo-server-plugin-base/dist/index").GraphQLRequestListener<Record<string, any>>'.
[ERROR]         Type 'GraphQLRequestListener<Record<string, any>>' is not assignable to type 'void | GraphQLRequestListener<Record<string, any>>'.
[ERROR]           Type 'import("/build/graphql/node_modules/apollo-server-plugin-base/dist/index").GraphQLRequestListener<Record<string, any>>' is not assignable to type 'import("/build/graphql/node_modules/apollo-server-core/node_modules/apollo-server-plugin-base/dist/index").GraphQLRequestListener<Record<string, any>>'.
[ERROR]             Types of property 'didEncounterErrors' are incompatible.
[ERROR]               Type '(requestContext: WithRequired<GraphQLRequestContext<Record<string, any>>, "source" | "metrics" | "errors">) => ValueOrPromise<void>' is not assignable to type '(requestContext: WithRequired<GraphQLRequestContext<Record<string, any>>, "metrics" | "errors">) => ValueOrPromise<void>'.
[ERROR]                 Types of parameters 'requestContext' and 'requestContext' are incompatible.
[ERROR]                   Type 'WithRequired<GraphQLRequestContext<Record<string, any>>, "metrics" | "errors">' is not assignable to type 'WithRequired<GraphQLRequestContext<Record<string, any>>, "source" | "metrics" | "errors">'.
[ERROR]                     Type 'WithRequired<GraphQLRequestContext<Record<string, any>>, "metrics" | "errors">' is not assignable to type 'Required<Pick<GraphQLRequestContext<Record<string, any>>, "source" | "metrics" | "errors">>'.
[ERROR]                       Property 'source' is optional in type 'GraphQLRequestContext<Record<string, any>> & Required<Pick<GraphQLRequestContext<Record<string, any>>, "metrics" | "errors">>' but required in type 'Required<Pick<GraphQLRequestContext<Record<string, any>>, "source" | "metrics" | "errors">>'.

Workaround

Seems to build fine when forcing the transitive dependency to the newer version:

  "resolutions": {
    "apollo-metrics/apollo-server-plugin-base": "^0.7.1",
    "apollo-metrics/apollo-tracing": "^0.9.1"
  },
tlaak commented

The above did not work for me. I had to import the ApolloServerPlugin and do a type cast. There must be a type conflict.

import { register } from 'prom-client';
import createMetricsPlugin from 'apollo-metrics';
// This type works
import { ApolloServerPlugin } from 'apollo-server-plugin-base';

const apolloMetricsPlugin = createMetricsPlugin(
  register,
) as ApolloServerPlugin<Record<string, string>>;

This happens in "apollo-server-plugin-base": "^0.9.0" as well

Not only the typings are incompatible now. Also the latest prom-client returns a Promise when calling register.metrics(). As express does not handle promises, it won't work. Also I got compilation errors, where the default export of this plugin was not found with current Typescript version.

What I did, was to copy the sourecode and integrate it locally to my project.

My metrics handler looks like this:

app.get("/metrics", async (_, res) => {
    let data = await register.metrics()
    res.header('Content-Type', 'text/plain')
    res.send(data)
  });