graphql-nexus / nexus

Code-First, Type-Safe, GraphQL Schema Construction
https://nexusjs.org
MIT License
3.4k stars 274 forks source link

run schema-first apollo-server and nexus in parallel #350

Open Schubidu opened 4 years ago

Schubidu commented 4 years ago

Currently my Apollo server runs with the schema-first approach. I want to migrate to the Nexus step by step, so that both have to run in parallel for a while.

Weakky commented 4 years ago

Hey @Schubidu,

Here's a small example showing how to get both schema-first and nexus working together

import { makeSchema, objectType } from "nexus";
import { ApolloServer, makeExecutableSchema } from "apollo-server";
import { join } from "path";

const schemaFirstSchema = makeExecutableSchema({
  typeDefs: `
    type User {
      id: ID!
      name: String!
    }
  `,
  resolvers: {
    User: {
      id: () => 1,
      name: () => "John"
    }
  }
});

const Post = objectType({
  name: "Post",
  definition(t) {
    t.id("id");
    t.field("authorId", {
      type: "User",
      resolve(parent) {
        return root.id;
      }
    });
  }
});

const schema = makeSchema({
  types: [schemaFirstSchema.getTypeMap(), Post],
  outputs: {
    schema: join(__dirname, "schema.graphql"),
    typegen: join(__dirname, "typegen.ts")
  }
});

new ApolloServer({
  schema
})
  .listen()
  .then(({ url }) => console.log(`Running at ${url}`));
Schubidu commented 4 years ago

Thanks, I'll try your example, but a documentation about it would be helpful.

Schubidu commented 4 years ago

@Weakky I adapted your example to my structure and fixed a bug. You need to merge both schemas, otherwise the introspection only includes the nexus-schema.


import { makeSchema, objectType } from "nexus";
import { ApolloServer, makeExecutableSchema, mergeSchemas } from "apollo-server";
import { importSchema } from 'graphql-import';
import { join } from "path";
import { resolvers } from './resolvers';
import * as typeDefs from './typeDefs';

// loading the "old" schema
const schemaFirstTypeDefs = (importSchema('src/schema.graphql') as unknown) as DocumentNode;

const schemaFirstSchema = makeExecutableSchema({
  typeDefs: schemaFirstTypeDefs,
  resolvers: (resolvers as unknown) as IResolvers,
});

const schema = makeSchema({
  types: [schemaFirstSchema.getTypeMap(), ...Object.values(typeDefs)],
  outputs: {
    schema: join(__dirname, 'schema-gen.graphql'),
    typegen: join(__dirname, 'typegen.ts'),
  },
});

const schema = makeSchema({
  types: [schemaFirstSchema.getTypeMap(), ...Object.values(typeDefs)],
  outputs: {
    schema: join(__dirname, "schema-gen.graphql"),
    typegen: join(__dirname, "typegen.ts")
  }
});

new ApolloServer({
  schema: 
})
  .listen()
  .then(({ url }) => console.log(`Running at ${url}`));
czystyl commented 4 years ago

@Schubidu Could you paste an example with more context? I wanted to do the same thing on my project. From you example, I see that you have const schema done twice with the same parameters.

bs1180 commented 4 years ago

Although the code sample posted above by @Weakky works for querying, the introspection query used by graphql-code-generator didn't work properly. I had to merge the schemas like this:

// existing apollo schema
const apolloSchema = makeExecutableSchema({
  typeDefs: schema,
  resolvers
});

// createPayment is single new Nexus mutation
const nexusSchema = makeSchema({
  types: [apolloSchema.getTypeMap(), createPayment]
});

const mergedSchema = mergeSchemas({ schemas: [apolloSchema, nexusSchema] });

However, now enums with an internal value don't work 🙀 eg.

enum Status {
  Active = 1
}

Error is thrown: `Expected a value of type \"Status\" but received: "Active".