Apollo-server: Partially private schema (hide types and from introspection)

Created on 26 Nov 2018  路  9Comments  路  Source: apollographql/apollo-server

I'm not sure if this belongs here or upstream, but in both cases it's something that could be part of Apollo.

I have parts of my schema I'd like to hide from the "general public". As an example, I might have ways to get an order, product information, etc. but I'd like to also have order-specific error logs only available to users with an admin authentication level.

Actually making the schema "aware" of the user authentication would probably be too complex, but generally hiding a part of it would make using the introspection feature easier for users.

Here's a GitHub conversation specifically about this: https://github.com/graphql/graphql-js/issues/113

My suggestion would be to simply provide Apollo Server developers a "hook" where they can transform the schema before returning it to users, effectively allowing them to remove parts of it. Something like:

const function schemaFilter(schema) {
    delete schema.logs;
    delete schema.order.logs;
}

new ApolloServer({ schemaFilter });

This would not involve much new complexity while allowing complex use cases, if needed by the developer.

I quickly looked at where such a filter could be hooked into and couldn't find anything obvious, so if there is interest, pointers would also be appreciated.

鉀诧笍 feature

Most helpful comment

There needs to be a @private directive resolver that hides stuff from the introspecter

All 9 comments

Our team also has a need for such functionality. We also want to enable account-based introspection capabilities.

I think one possible place to add this would be here:
https://github.com/apollographql/apollo-server/blob/master/packages/apollo-server-core/src/requestPipeline.ts#L304

Similar to how formatResponse works we could have a config option like formatSchema which would allow use to alter the schema before it's used to generate the response. Something like:

  async function execute(
    document: DocumentNode,
    operationName: GraphQLRequest['operationName'],
    variables: GraphQLRequest['variables'],
  ): Promise<ExecutionResult> {
    const executionArgs: ExecutionArgs = {
->    schema: config.formatSchema ? config.formatSchema(schema, { context: requestContext.context }) : config.schema,
      document,
      rootValue:
        typeof config.rootValue === 'function'
          ? config.rootValue(document)
          : config.rootValue,
      contextValue: requestContext.context,
      variableValues: variables,
      operationName,
      fieldResolver: config.fieldResolver,
    };

    const executionDidEnd = extensionStack.executionDidStart({
      executionArgs,
    });

    try {
      return graphql.execute(executionArgs);
    } finally {
      executionDidEnd();
    }
  }

Since I haven't seen anyone solve that problem yet, I will dig into it myself. Cheers

There needs to be a @private directive resolver that hides stuff from the introspecter

There needs to be a @private directive resolver that hides stuff from the introspecter

UP!

Something as straightforward as this would be incredible:

directive @hidden(reason: String = "Private resource") on FIELD_DEFINITION | OBJECT | INPUT_OBJECT

type Query {
  ping: String! @hidden
}

I just attempted with graphql-tools but adding to the field variable doesn't matter since the Introspection query isn't trying to return a isHidden field so my modifications don't get picked up 馃う鈥嶁檪

@ftatzky:

Our team also has a need for such functionality. We also want to enable account-based introspection capabilities.

I assume you mean in a similar fashion to how graphcms.com operates? My guess is these guys (a) don't use Apollo-Server and (b) they just match the GraphQL API specification to their own tech, and therefore depending on API keys / headers / hostname they're able to return a unique GraphQL parser & introspection results per account.

Here's a way to do it @christianrondeau: https://gist.github.com/abrkn/2edb028da330a875c1598250a1a8d8e5

We're using it for https://sideshift.ai/graphql to hide internal types. I might publish this as an npm module in the future.

@abrkn that's a very nice (and simple) solution, to simply overwrite the introspection query in express! Thanks for sharing it!

@abrkn that's a very nice (and simple) solution, to simply overwrite the introspection query in express! Thanks for sharing it!

It should be reasonably simple to allow compiled typeDefs as input and use directives.

@christianrondeau I've published a version that uses directives: https://github.com/sideshift/apollo-server-restrict-introspection

It's a pretty rough first version, open to PRs.

Was this page helpful?
0 / 5 - 0 ratings