Apollo v3 GraphQL Subscription Error: Must provide document - graphql

I'm testing out subscription on Apollo v3 using the example setup on the docs. But I get the above error. I'm not sure what I'm missing.
Here's the complete reproducible code on Github gist
const typeDefs = gql`
type Subscription {
incremented: Int
}
`;
const resolvers = {
Subscription: {
incremented: {
subscribe: () => pubsub.asyncIterator('NUMINCREMENTED'),
},
},
};
(async function () {
const schema = makeExecutableSchema({
typeDefs,
resolvers,
});
const subscriptionServer = SubscriptionServer.create(
{
schema,
execute,
subscribe,
},
{ server: httpServer }
);
const server = new ApolloServer({
schema,
plugins: [
{
async serverWillStart() {
return {
async drainServer() {
subscriptionServer.close();
},
};
},
},
],
});
})();
Here's the error when I try the subscription on Apollo Studio.

I had the same problem. Downgrade apollo-server-express to 3.1.2.
Then everything should work.

Related

Apollo federation can't start gateway

Hello I want to use federation.I followed this tutorial. I can start my subgraph but when I start my gateway, I get this error:
Error: A valid schema couldn't be composed. The following composition errors were found:
Cannot extend type "Query" because it is not defined. Did you mean "User"?
Cannot extend type "Mutation" because it is not defined.
I even extended Query and Mutation but got another error.
my gateway code:
import fastify from "fastify";
import { ApolloServer } from "apollo-server-fastify";
import { ApolloGateway } from "#apollo/gateway";
const PORT = process.env.PORT || 4000;
const IP = "0.0.0.0";
const app = fastify({ trustProxy: true });
const gateway = new ApolloGateway({
serviceList: [{ name: "amazon", url: "http://localhost:4001/graphql" }],
});
(async () => {
try {
const { schema, executor } = await gateway.load();
const server = new ApolloServer({ schema, executor });
server.start().then(() => {
app.register(server.createHandler({ path: "/graphql" }));
app.listen(PORT, IP, (err) => {
if (err) {
console.error(err);
} else {
console.log("Server is ready at port 4000");
}
});
});
} catch (error) {
console.log("dick");
console.log("err", error);
}
})();
my schema in subgraph:
type Query {
getUsers: [User]!
}
type Mutation {
createUser(name: String!): Boolean!
}
type User #key(fields: "id") {
id: ID!
name: String!
}
Most likely you're using graphql version 16. Following https://www.apollographql.com/docs/federation/gateway/ you must use 15 for now (December 2021). Try:
yarn add graphql#15
Another detail you can do on latest versions is simply pass the gateway to ApolloServer, like this:
const server = new ApolloServer({ gateway });

Migrating to 3.5.0 with apollo-server-express

I'm trying to update the version of one of my projects from node 12.x.x to node.14.x.x.
Now I saw the documentation of apollo to migrate to the v3 but it's not clear at all someone know where to start? Is it gonna be easier to make all the apollo part systems from scratch?
Current file that should be updated:
const { ApolloServer } = require('apollo-server-express');
const { makeExecutableSchema } = require('graphql-tools');
const { applyMiddleware } = require('graphql-middleware');
const { gql } = require('apollo-server-express');
const { resolvers, typeDefs } = require('graphql-scalars');
const { types } = require('./typedefs/types');
const { inputs } = require('./typedefs/inputs');
const { queries } = require('./typedefs/queries');
const { mutations } = require('./typedefs/mutations');
const customResolvers = require('./resolvers');
const { permissions } = require('./permissions/permissions');
const graphqlApis = gql`
${types}
${queries}
${inputs}
${mutations}
`;
const schema = makeExecutableSchema({
typeDefs: [...typeDefs, graphqlApis],
resolvers: {
...customResolvers,
...resolvers,
},
});
const server = new ApolloServer({
context: ({ req }) => {
const headers = req.headers || '';
return headers;
},
schema: applyMiddleware(schema, permissions),
});
module.exports = server;
Current error when trying to run: Error: You must 'await server.start()' before calling 'server.applyMiddleware()'
I would simply love to get some solutions/help/insight with it.
As mentioned in the docs, you need to surround your code with an Async function
https://www.apollographql.com/docs/apollo-server/migration/
(async function () {
// ....
})();
Or Like so: ...
define your typeDefs & resolvers first
const typeDefs = "" // your typedefs here
const resolvers = "" // your resolvers here
async function startApolloServer(typeDefs, resolvers) {
// Apollo Express 3.5.x code goes here
// ....
await server.start();
// promise resolve...
}
startApolloServer(typeDefs, resolvers)

How to run a mutation in ApolloServer using the GraphQL Playground?

I'm using node.js, express and apollo-server-express. With the following code:
const express = require('express');
const { ApolloServer, gql } = require('apollo-server-express');
const typeDefs = gql`
type Book { title: String author: String }
type Query { books: [Book] }
type Mutation { change_title(new_title: String): Book }
`;
const books = [
{ title: 'The Awakening', author: 'Kate Chopin', },
{ title: 'City of Glass', author: 'Paul Auster', },
];
const resolvers = {
Query: { books: () => books, },
Mutation: {
change_title: (parent, args) => {
books[0].title = args.new_title
return books[0]
}
}
};
const server = new ApolloServer({ typeDefs, resolvers, });
const app = express();
server.applyMiddleware({ app });
app.listen({ port: 4000 }, () =>
console.log(`Server ready at http://localhost:4000${server.graphqlPath}`)
);
When I enter the mutation in the GraphQL Playground, like so:
{
change_title(new_title: "Something") {
title
}
}
I get the following error: "Cannot query field "change_title" on type "Query"."
My goal is to be able to run mutations. If I should be doing it another way or if there's eror, please let me know. Thanks!
GraphQL playground treats all types as queries unless otherwise specified.
mutation {
change_title(new_title: "Something") {
title
}
}

Running Subscriptions on GraphiQL using express-graphql, graphql, graphql-subscriptions and graphql-subscriptions-ws

I'm fairly new to GraphQL and currently familiarizing myself by making a quiz application using React on the front-end.
At the moment, I'm busy with my back-end. After successfully setting up queries and mutations, I am finding it difficult to get subscriptions working. When using GraphiQL, I am getting null as an output instead of "Your subscription data will appear here..."
Queries and the mutation for adding the quiz works.
The entry point of my server, app.js:
const express = require("express");
const mongoose = require("mongoose");
const { graphqlHTTP } = require("express-graphql");
const schema = require("./graphql/schema");
const cors = require("cors");
const port = 4000;
//Subscriptions
const { createServer } = require("http");
const { SubscriptionServer } = require("subscriptions-transport-ws");
const { execute, subscribe } = require("graphql");
const subscriptionsEndpoint = `ws://localhost:${port}/subscriptions`;
const app = express();
app.use(cors());
mongoose.connect("mongodb://localhost/quizify", {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true,
useFindAndModify: false
});
mongoose.connection.once("open", () => console.log("connected to database"));
app.use("/graphql", graphqlHTTP({
schema,
graphiql: true,
subscriptionsEndpoint,
}));
const webServer = createServer(app);
webServer.listen(port, () => {
console.log(`GraphQL is now running on http://localhost:${port}`);
//Set up the WebSocket for handling GraphQL subscriptions.
new SubscriptionServer({
execute,
subscribe,
schema
}, {
server: webServer,
path: '/subscriptions',
});
});
Below is from the schema definitions, schema.js:
const { graphqlHTTP } = require("express-graphql");
const graphql = require("graphql");
const { PubSub } = require("graphql-subscriptions");
const pubsub = new PubSub();
//Import of Mongoose Schemas:
const Quiz = require("../models/quiz");
const {
GraphQLObjectType,
GraphQLList,
GraphQLSchema,
GraphQLNonNull,
GraphQLID,
GraphQLString,
GraphQLBoolean
} = graphql;
const QuizType = new GraphQLObjectType({
name: "Quiz",
fields: () => ({
id: { type: GraphQLID },
title: { type: GraphQLString },
questions: {
type: new GraphQLList(QuestionType),
resolve(parent, args) {
return Question.find({ quizId: parent.id });
}
},
creator: {
type: UserType,
resolve(parent, args) {
return User.findById(parent.creatorId);
}
}
})
});
const NEW_QUIZ_ADDED = "new_quiz_added";
const Subscription = new GraphQLObjectType({
name: "Subscription",
fields: {
quizAdded: {
type: QuizType,
subscribe: () => {
pubsub.asyncIterator(NEW_QUIZ_ADDED);
},
},
}
});
const Mutation = new GraphQLObjectType({
name: "Mutation",
fields: {
createQuiz: {
type: QuizType,
args: {
title: { type: new GraphQLNonNull(GraphQLString) },
creatorId: { type: new GraphQLNonNull(GraphQLID) }
},
resolve(parent, args) {
const newQuiz = new Quiz({ //Quiz imported from Mongoose schema.
title: args.title,
creatorId: args.creatorId,
});
pubsub.publish(NEW_QUIZ_ADDED, { quizAdded }); //NEW_QUIZ_ADDED - a constant defined above for easier referencing.
return newQuiz.save();
}
},
},
});
module.exports = new GraphQLSchema({
query: RootQuery,
mutation: Mutation,
subscription: Subscription,
});
I've looked around, however I'm not finding an method that works for this kind of site. I know it might sound like a simple problem. Any assistance would be greatly appreciated!

local state management for graphql vue apollo

I am trying to make local state management with vue apollo, but even after following the docs I am getting no result. There is no error in the console so I am not sure what is wrong.
Here is my setup:
// main.js file the initializing part
const client = new ApolloClient({
link: ApolloLink.from([
errorLink,
authMiddleware,
link,
]),
cache,
typeDefs,
resolvers,
connectToDevTools: true,
});
// resolvers file
import gql from 'graphql-tag';
import { todoItemsQuery } from './task.queries';
export const typeDefs = gql`
type Item {
id: ID!
text: String!
done: Boolean!
}
type Mutation {
changeItem(id: ID!): Boolean
deleteItem(id: ID!): Boolean
addItem(text: String!): Item
}
`;
export const resolvers = {
Mutation: {
checkItem: (_, { id }, { cache }) => {
const data = cache.readQuery({ query: todoItemsQuery });
console.log('data res', data);
const currentItem = data.todoItems.find(item => item.id === id);
currentItem.done = !currentItem.done;
cache.writeQuery({ query: todoItemsQuery, data });
return currentItem.done;
},
},
};
//queries file
import gql from 'graphql-tag';
export const todoItemsQuery = gql`
{
todoItems #client {
id
text
done
}
}
`;
export const checkItemMutation = gql`
mutation($id: ID!) {
checkItem(id: $id) #client
}
`;
// component where I call it
apollo: {
todoItems: {
query: todoItemsQuery
}
},
checkItem(id) {
this.$apollo
.mutate({
mutation: checkItemMutation,
variables: { id }
})
.then(({ data }) => {
console.log("CACHE", data);
});
},
I get empty todoItems, no errors.
Please let me know what am I missing, I am not grasping some concept I think, and if there is a way to use vuex with apollo then I can do that too.
Foreword: I'm not an Apollo specialist, just starting to use it.
Just in case, these thoughts may help you. If they don't, well, I'm sorry.
In main.js: Apollo documentation provides a slightly different set up when using Apollo Boost (https://www.apollographql.com/docs/link/links/state/#with-apollo-boost). Just in case, this is how I have set up my implementation so far.
import VueApollo from 'vue-apollo'
import ApolloClient from 'apollo-boost';
import { InMemoryCache } from 'apollo-cache-inmemory';
const cache = new InMemoryCache();
Vue.use(VueApollo)
const apolloClient = new ApolloClient({
//...whatever you may already have,
clientState: {
// "defaults" is your initial state - if empty, I think it might error out when your app launches but is not hydrated yet.
defaults: {
todoItems: [],
}
cache,
typeDefs: {...yourTypeDefs},
resolvers: {...yourResolvers},
},
});
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
});
In your typeDefs: I can not see a Query Type for your todoItems:
type Query {
todoItemsQuery: [Item]
}
In your component: my own implementation was not working until I added an update method to the apollo request:
apollo: {
todoItems: {
query: todoItemsQuery,
update: data => data.todoItems
}
},

Resources