Constraint Directive within federated subgraph

Hey guys,

Currently building out an auth API microservice (Apollo server) behind an Apollo Gateway (Apollo-server-express), and I’m trying to implement some form validation, on a createUser mutation.

After a quick google I came across the graphql-constraints-directive package, and this Apollo blog: GraphQL validation using directives - Apollo GraphQL Blog

Looks like it’s going to do everything I want, so gave it a go. However, I’m struggling to implement it on my auth subgraph, as currently I’m using the buildSubgraphSchema function from @apollo/subgraph to build the schema and make it available to my gateway (this is being done via IntrospectAndCompose on my local machine, but will be done via the managed federations/supergraph in production).

So currently I have this:

const server = new ApolloServer({
    schema: buildSubgraphSchema({ typeDefs, resolvers }),
    validationRules: [depthLimit(7)]
});

and the blog, says to implement it like this:

const typeDefs = `SDL HERE`
const schema = makeExecutableSchema({
  typeDefs, schemaDirectives: { constraint: ConstraintDirective }
})

From what I can understand, both of these are building a final schema. However, I can’t seem to find a good way of combining the two to enable me to use constraints within my schema typeDefs.

I was able to get one implementation where TS didn’t complain and compiled, but then my gateway complained when it tried to compose the supergraph, so obviously my buildSubgraphSchema result was being replaced.

I’ve tried some googling, and can’t really find anything about this specific constraint directive package within a subgraph/supergraph, so wondering if anyone else has any suggestions, or even a working implementation. I’m also open to using a completely different method of form validation if you have a good suggestion - this directive just seems like it would fit perfectly.

Additional context:

This is the error on the gateway when I get the subgraph into a buildable state:
This happens when I build the subgraph schema first, then try to pass that schema to buildExecutableSchema - obviously losing some of the subgraph spec its expecting

Error: Couldn't load service definitions for "OSC-Auth" at http://localhost:4001: Cannot return null for non-nullable field Query._service.
    at /Users/tompearce/Documents/OSC/new-stack/osc/node_modules/@apollo/gateway/src/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.ts:77:15
   ...

If instead, I follow the instructions here for Apollo Server I get 2 errors on the buildSubgraphSchema function
code:

import * as dotenv from 'dotenv';
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
import depthLimit from 'graphql-depth-limit';
import { typeDefs } from './schemas/schema';
import { resolvers } from './resolvers/resolver';
import { buildSubgraphSchema } from '@apollo/subgraph'
import {
    createApolloQueryValidationPlugin,
    constraintDirectiveTypeDefs
} from 'graphql-constraint-directive';
import { makeExecutableSchema } from '@graphql-tools/schema';
dotenv.config();

const schema = makeExecutableSchema({
    typeDefs: [constraintDirectiveTypeDefs, typeDefs],
    resolvers
});
const plugins = [
    createApolloQueryValidationPlugin({
        schema
    })
];
const server = new ApolloServer({
    schema: buildSubgraphSchema({
        schema, // error 1 here
    }),
    plugins, // error 2 here
    validationRules: [depthLimit(7)]
});

async function startServer(server: ApolloServer) {
    const { url } = await startStandaloneServer(server, {
        listen: { port: 4001 }
    });
    console.info(`🚀 Auth Microservice ready at: ${url}`);
}

void startServer(server);

Error 1:

Argument of type '{ schema: GraphQLSchema; }' is not assignable to parameter of type 'DocumentNode | (DocumentNode | GraphQLSchemaModule)[] | LegacySchemaModule'.
  Object literal may only specify known properties, and 'schema' does not exist in type 'DocumentNode | (DocumentNode | GraphQLSchemaModule)[] | LegacySchemaModule'

Error 2:

Type 'PluginDefinition[]' is not assignable to type 'ApolloServerPlugin<BaseContext>[]'.
  Type 'PluginDefinition' is not assignable to type 'ApolloServerPlugin<BaseContext>'.
    Type 'import("/Users/tompearce/Documents/OSC/new-stack/osc/node_modules/apollo-server-plugin-base/dist/index").ApolloServerPlugin<import("/Users/tompearce/Documents/OSC/new-stack/osc/node_modules/apollo-server-types/dist/index").BaseContext>' is not assignable to type 'import("/Users/tompearce/Documents/OSC/new-stack/osc/node_modules/@apollo/server/dist/esm/externalTypes/plugins").ApolloServerPlugin<import("/Users/tompearce/Documents/OSC/new-stack/osc/node_modules/@apollo/server/dist/esm/externalTypes/context").BaseContext>'.
      Types of property 'serverWillStart' are incompatible.
        Type '((service: GraphQLServiceContext) => Promise<void | GraphQLServerListener>) | undefined' is not assignable to type '((service: GraphQLServerContext) => Promise<void | GraphQLServerListener>) | undefined'.
          Type '(service: GraphQLServiceContext) => Promise<void | GraphQLServerListener>' is not assignable to type '(service: GraphQLServerContext) => Promise<void | GraphQLServerListener>'.
            Types of parameters 'service' and 'service' are incompatible.
              Type 'GraphQLServerContext' is missing the following properties from type 'GraphQLServiceContext': schemaHash, serverlessFrameworkts(2322)
constructor.d.ts(38, 5): The expected type comes from property 'plugins' which is declared here on type 'ApolloServerOptions<BaseContext>'

Hi @tom-pearce ,

I have the same problem. did you manage to solve it?

Thanks
Yasar