I am new to Graphql, express, and Apollo.
Expected result: I am trying to consume data from JSON file data and get results in the studio.
Actual Result: Getting "null" data instead.
I am attaching my code snippets and problems below
Refer the following:
Let me show you the code:
directory structure:
MOCK_DATA.json
I am just keeping data small for testing the concept.
[{
"name": "Leanne Graham",
"username": "Bret"
},
{
"name": "Rohit Sharma",
"username": "rohituid"
}]
index.js
As per my understanding, The significance of the file is wiring up the express middle wire with the Apollo server. Tried to make this file in a way that it will be hardly touched.
Other than that, I have the async function was required to fix Apollo Server await server.start bug .
I am creating apollo server
const { ApolloServer } = require("apollo-server-express");
const { typeDefs } = require("./Schema/TypeDefs");
const { resolver } = require("./Schema/Resolver");
const express = require("express");
const app = express();
const PORT = 3001;
async function createApolloServer() {
//passing into apollo constructor
const server = new ApolloServer({
typeDefs,
resolver
});
//instantiatiating the apollo server
await server.start();
//this will install the apollo server on express app
server.applyMiddleware({ app });
}
createApolloServer();
//console.log(resolver);
app.listen(PORT, () => {
console.log('Server is running on : http://localhost:3001/graphql');
Schema:
TypeDefs.js
const { ApolloServer, gql } = require("apollo-server");
//below is known as tagged template literal
const typeDefs = gql`
type User {
name: String
username: String
}
#Queries -like get in REST World
type Query {
getAllUsers: [User]
}
`;
//console.log(typeDefs);
module.exports = { typeDefs };
Resolver.js
const userData = require("../MOCK_DATA.json");
//const userData = require("../FakeData.js");
// this is resolver map -> javascript object
//using arrow function
/*
below arrow function equivalent to using function like:
function getAllUsers() {
return userData;
}
*/
const resolver = {
Query: {
getAllUsers: ()=> {
return userData;
}
},
};
//console.log(userData);
module.exports = { resolver };
I am trying to start my nestJs server and It keeps giving me this error:
UnhandledPromiseRejectionWarning: Error: You must await server.start() before calling server.applyMiddleware()
at ApolloServer
I'm not even sure where to debug from as I am still very new at NestJs and GraphQL.
This is a known bug with an open issue and a merged PR to fix it. For now, you can downgrade to apollo-server-express#^2
A complete working code is:
const express = require("express");
const { ApolloServer } = require("apollo-server-express");
const http = require("http");
const app = express();
const typeDefs = `
type Query{
totalPosts: Int!
}
`;
const resolvers = {
Query: {
totalPosts: () => 100,
},
};
let apolloServer = null;
async function startServer() {
apolloServer = new ApolloServer({
typeDefs,
resolvers,
});
await apolloServer.start();
apolloServer.applyMiddleware({ app });
}
startServer();
const httpserver = http.createServer(app);
app.get("/rest", function (req, res) {
res.json({ data: "api working" });
});
app.listen(4000, function () {
console.log(`server running on port 4000`);
console.log(`gql path is ${apolloServer.graphqlPath}`);
});
I faced this issue when upgrading Ben Awad's Graphql-Next-Typeorm[...] stack, simply adding an await to server start fixed the warnings
const apolloServer = new ApolloServer({
introspection: true,
schema: await buildSchema({
resolvers: [__dirname + '/resolvers/**/*.js'],
validate: false
}),
context: ({ req, res }) => ({
req,
res,
redis: redisClient
}),
formatError
});
// added this line
await apolloServer.start();
apolloServer.applyMiddleware({
app,
cors: false
});
For Apollo Server Express 3.0 and above, you need to define an async function that takes in typeDefs and resolvers parameters, then assign the server to the same Apollo initialization as before as shown here
async function startApolloServer(typeDefs, resolvers){
const server = new ApolloServer({typeDefs, resolvers})
const app = express();
await server.start();
server.applyMiddleware({app, path: '/graphql'});
app.listen(PORT, () => {
console.log(`Server is listening on port ${PORT}${server.graphqlPath}`);
})
}
startApolloServer(typeDefs, resolvers);
downgrading is not the option (at least anymore)
here is the solution =>
https://javascriptsu.wordpress.com/2021/08/02/apollo-error-must-await-server-start/
const server = new ApolloServer({ typeDefs, resolvers });
const app = express();
server.start().then(res => {
server.applyMiddleware({ app });
app.listen({ port: 3000 }, () =>
console.log("nice")
)
})
You can put everything in an async function and execute the function in your server(app,index...).js. You may also check the npm package.
https://www.npmjs.com/package/apollo-server-express
For example:
const express = require('express')
, http = require('http')
, path = require('path');
const { ApolloServer } = require('apollo-server-express');
async function startExpressApolloServer() {
const { typeDefs } = require('./graphql/schemas/schema');
const { resolvers } = require('./graphql/resolvers/resolver');
const server = new ApolloServer({ typeDefs, resolvers });
await server.start();
const app = express();
server.applyMiddleware({ app, path: '/api/graphql' });
await new Promise(resolve => app.listen({ port: 3001 }, resolve));
console.log(`Server ready at http://localhost:3001${server.graphqlPath}`);
return { server, app };
}
startExpressApolloServer();
I had the same type of problem. I was using TypeScript, Express, ApolloServer. What I did-
async function a(){
const server = new ApolloServer({ typeDefs, resolvers });
await server.start();
server.applyMiddleware({ app, path: '/graphql' });
}
a();
This is not a bug. As per the documentation, the Apollo server needs to be instantiated in an async function. This is the recommended setup for Apollo Express:
import { ApolloServer } from 'apollo-server-express';
import { ApolloServerPluginDrainHttpServer } from 'apollo-server-core';
import express from 'express';
import http from 'http';
async function startApolloServer(typeDefs, resolvers) {
const app = express();
const httpServer = http.createServer(app);
const server = new ApolloServer({
typeDefs,
resolvers,
plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
});
await server.start();
server.applyMiddleware({ app });
await new Promise(resolve => httpServer.listen({ port: 4000 }, resolve));
console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`);
}
There are already some great answers here. But we should know why and where we should call server.start(). From apollo docs -
Always call await server.start() before calling
server.applyMiddleware and starting your HTTP server. This allows
you to react to Apollo Server startup failures by crashing your
process instead of starting to serve traffic.
One other option is to downgrade your apollo to any 2.x.x. It solved my problem
This is my working server:
import express from 'express';
import { ApolloServer } from 'apollo-server-express';
import typeDefs from './schema';
const app = express();
const server = new ApolloServer({
typeDefs,
mocks: true
});
server.start().then(() => {
server.applyMiddleware({
app,
cors: true,
});
});
const PORT = 4000;
app.listen(PORT, () => {
console.log(
`GraphQL endpoint and playground accessible at http://localhost:${PORT}${server.graphqlPath}`,
);
});
The key thing here is to wrap the "applyMiddleware" function call inside the "server.start" async function.
In v3, if you use apollo-server-express the start function is required https://www.apollographql.com/docs/apollo-server/api/apollo-server/#start.
You can do something like this.
const app = express()
app.use(express.urlencoded({ extended: true }))
app.use(express.json())
....
export const startup = async () => {
await server.start()
server.applyMiddleware({ app, path: `/api/${configs.region}/graphql` })
return app
}
// call startup in another file to get app
It is not ok to start the apollo server in advance. What happens with the case when I have to explicitly use http/https. Please see the following case:
const server = new ApolloServer({
typeDefs: [KeycloakTypeDefs, typeDefs], // 1. Add the Keycloak Type Defs
schemaDirectives: KeycloakSchemaDirectives, // 2. Add the
formatError: new ApolloErrorConverter(),
resolvers: resolvers,
context: ({ req }) => {
return makeContextWithDependencies(req);
}
});
server.applyMiddleware({ app });
http.createServer(app).listen(config.server.port, os.hostname());
const options = {
key: fs.readFileSync(config.server.ssl.keyFile, "utf8"),
cert: fs.readFileSync(config.server.ssl.certFile, "utf8"),
passphrase: config.server.ssl.passphrase
};
https
.createServer(options, app)
.listen(config.server.securePort, os.hostname());
console.log(
"Server waiting for requests on ports: " +
config.server.port +
"," +
config.server.securePort
);
We must wait for the server to get ready before adding middleware to it.
const app = express();
const apolloServer = new ApolloServer({
schema: await buildSchema({
resolvers: [HelloResolver],
validate: false,
}),
});
await apolloServer.start(); // First start the server then apply middleware on it
apolloServer.applyMiddleware({ app });
you can do like that, it works for me.
const server = new ApolloServer({ schema });
const startApollo = async () => {
try {
await server.start();
server.applyMiddleware({ app, path: "/api"})
} catch (error) {
console.log(error);
}
}
I'm build vue app, and for mine app need api request to server from client, also necessary proxy any request.
It's mine vue.config.js
const producer = require('./src/kafka/producer');
const bodyParser = require('body-parser')
module.exports = {
devServer: {
setup: function (app, server) {
app.use(bodyParser.json())
app.post('/send-message', function (req, res) {
producer.send(req.body)
.then(() => {
res.json({result: true, error: null});
})
.catch((e) => {
res.status(500).json({result: false, error: e});
})
});
},
proxy: {
'/v2/order/by-number': {
target: 'http://address-here'
}
}
}
};
As you can see so i'm use body-parser app.use(bodyParser.json())
After I added it, proxying stopped working for me. Request to /send-message freezes after show me error
Proxy error: Could not proxy request path-here from localhost:8080
to http://address-here
Internet searches have not led to a solution.
For a long time, i find a solution:
Add second param jsonParser to app.post()
See full example
const producer = require('./src/kafka/producer');
const bodyParser = require('body-parser')
const jsonParser = bodyParser.json({limit: '1mb'});
module.exports = {
devServer: {
setup: function (app, server) {
app.post('/send-message', jsonParser, function (req, res) {
producer.send(req.body)
.then(() => {
res.json({result: true, error: null});
})
.catch((e) => {
res.status(500).json({result: false, error: e});
})
});
},
proxy: {
'path': {
target: 'http://address-here'
}
}
}
};
I'm trying to make an axios HTTP request call to an express route to retrieve a response from passport spotify. I am struggling on sending the response from express to my vue.js component. I am using Nuxt.js.
spotify.vue
export default {
data: function() {
return {
userInfo: null
};
},
mounted() {
this.$axios.get("/auth/spotify")
.then((response) => {
userInfo = response;
});
}
};
server/index.js
const express = require('express');
const passport = require('passport');
const SpotifyStrategy = require('passport-spotify').Strategy;
const keys = require('../config/keys');
const app = express();
async function start () {
passport.use(
new SpotifyStrategy(
{
clientID: keys.spotifyClientID,
clientSecret: keys.spotifyClientSecret,
callbackURL: '/auth/spotify/callback'
},
function(accessToken, refreshToken, expires_in, profile, done) {
console.log(profile);
}
)
);
app.get('/auth/spotify', passport.authenticate('spotify'), function(req,res) {
res.json(data);
});
app.get('/auth/spotify/callback', passport.authenticate('spotify'));
}
When accessing localhost:3000/auth/spotify the data I am looking for is logged. I am wondering why res.json() or res.send() is not passing the data to the axios promise in my component.
Any help would be appreciated, Thanks in advance!!!
Before the upgrade we were having
import express from 'express';
import { graphqlExpress, graphiqlExpress } from 'apollo-server-express';
const app = express();
app.use(
'/graphql',
bodyParser.json(),
graphqlExpress(req => ({
schema,
tracing: true,
context: { req },
})),
);
app.use(
'/graphiql',
graphiqlExpress({
endpointURL: '/graphql',
}),
);
In our resolvers we could get the req and set req.session.token as follows,
const customResover = {
Query: {
custom: async (root, args, context) => {
console.log(' resolver called with args', args);
const { req } = context;
... fetch token info and set
req.session.token = ${token};
...
but with the upgrade to version 2.0.0 the code is changed to following and I am not sure how to fix the CustomResolver, to set the session token, any idea how the above could be accomplished ?
import express from 'express';
import { ApolloServer, gql } from 'apollo-server-express';
import { typeDefs, resolvers } from './schema/';
const app = express();
const apollo = new ApolloServer({
typeDefs
resolvers,
engine: false
});
apollo.applyMiddleware({
app,
});
https://www.apollographql.com/docs/apollo-server/migration-two-dot.html#request-headers
const apollo = new ApolloServer({
typeDefs
resolvers,
context: ({ req }) => ({ req })
engine: false
});
Solves it but got an issue with Cookie with token not getting to the browser.