i was going through a GraphQL tutorial from udemy,
https://www.udemy.com/introduction-to-graphql-and-apollo-building-modern-apis
And i was going through the guide to operating graphql and graphiql -> apollo -express - server. And got this. This particular error has not been defined in the videos. It is a free tutorial and lecture 9 has this.
Wht to do. i find no solution. Please help.
TypeError: Cannot read property 'startsWith' of undefined
at Object.renderGraphiQL (/home/dell/Desktop/graphql-
tutorial/node_modules/apollo-server-module-
graphiql/src/renderGraphiQL.ts:48:17)
at Object. (/home/dell/Desktop/graphql-tutorial/node_modules/apollo-
server-module-graphiql/src/resolveGraphiQLString.ts:62:10)
at step (/home/dell/Desktop/graphql-tutorial/node_modules/apollo-
server-module-graphiql/dist/resolveGraphiQLString.js:32:23)
at Object.next (/home/dell/Desktop/graphql-
tutorial/node_modules/apollo-server-module-
graphiql/dist/resolveGraphiQLString.js:13:53)
at fulfilled (/home/dell/Desktop/graphql-tutorial/node_modules/apollo-
server-module-graphiql/dist/resolveGraphiQLString.js:4:58)
at
at process._tickDomainCallback (internal/process/next_tick.js:228:7)
renderGraphiQLString.js
This is the line it says has error -->
export function renderGraphiQL(data: GraphiQLData): string {
const endpointURL = data.endpointURL;
const endpointWs =
endpointURL.startsWith('ws://') || endpointURL.startsWith('wss://');
const subscriptionsEndpoint = data.subscriptionsEndpoint;
const usingHttp = !endpointWs;
const usingWs = endpointWs || !!subscriptionsEndpoint;
const endpointURLWs =
usingWs && (endpointWs ? endpointURL : subscriptionsEndpoint);
resolveGraphiQLString.js
export async function resolveGraphiQLString(
query: any = {},
options: GraphiQLData | Function,
...args
): Promise<string> {
const graphiqlParams = createGraphiQLParams(query);
const graphiqlOptions = await resolveGraphiQLOptions(options,
...args);
const graphiqlData = createGraphiQLData(graphiqlParams,
graphiqlOptions);
return renderGraphiQL(graphiqlData);
}
server.js
import express from 'express';
import {graphqlExpress,graphiqlExpress} from 'apollo-server-express';
import bodyParser from 'body-parser';
import schema from './schema.js'
const server = express();
server.use('/graphql', bodyParser.json(), graphqlExpress(schema));
server.use('/graphiql', graphiqlExpress({ endpointURL: '/graphql'
}));
server.listen(4000,() =>{
console.log('listening on port 4000');
});
I was doing the same tutorial and got stuck with the same error. I just now got it working. For me, I had spelled endpointURL as endpointUrl because it seems stupid to me to capitalize acronyms within camel-case, but of course this being a specific key, it has to be spelled right.
For you, the only difference I see in the code is that I think you should pass {schema} to graphqlExpress, but you're passing just schema. So here's how I have it:
server.use("/graphql", bodyParser.json(), graphqlExpress({ schema }))
Your code is not correct. In order to define the graphiql endpoint you need to do this in the following way:
const server = express();
server.use('/graphql', bodyParser.json(), graphqlExpress(schema));
server.use('/graphiql', graphiqlExpress({ endpointURL: '/graphql' }));
Keep in mind you should pass to the graphiqlExpress method the endpointURL of your real graphql endpoint.
Cheers!
Related
Good Morning! I am currently working on a discord bot but I am facing an issue with the event handlers.
There seems to be a problem with the "get" command but I can't seem to find out what it
is, I have given the code below to my message.js
module.exports = (Discord, client, msg) => {
const prefix = 'e!';
if (!msg.content.startsWith(prefix) || msg.author.bot) return;
const args = msg.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
const cmd = client.commands.get(command)
if (!cmd){
msg.channel.send("That is not an available command!")
};
if(command) command.execute(client, msg, args, Discord);
};
The code below is my index.js
const Discord = require("discord.js")
const client = new Discord.Client({intents : ["GUILDS", "GUILD_MESSAGES"]});
const button = require('discord-buttons')(client)
const { MessageButton } = require("discord-buttons")
client.commands = new Discord.Collection();
client.events = new Discord.Collection();
['command_handler', 'event_handler'].forEach(handler =>{
require(`./handlers/${handler}`)(client, Discord);
})
client.login(process.env.token)
Any help would be greatly appreciated!
I fixed it! It seems that the order in which Discord and client were (in here).
module.exports = (Discord, client, msg)
was wrong! Instead, I swapped Discord around with client and it seems to work!
module.exports = (client, Discord, msg)
If anyone can tell me why this happens (as I would love to learn more)
You can comment or answer!
There was also an error with the execute command which I also fixed
if(cmd) {
cmd.execute(client, msg, args, Discord);
}
Thanks everyone for their contribution! Really needed your help!
I'm running a Graphql server from Apollo, and the objective is fetch some data. However, I need this data locally - on the same server. Is that possible, or is the only way to query the Apollo server using http?
I know that I could possible accomplish this without using GraphQl, and just access the data layer, but the thing is that I would like to benefit from:
Authorization
Dataloaders
Already built-in optimization in our Graphql Api
I already have a working solution where I just use node-fetch to query localhost, but it seems like quite a bit of overhead.
Yes it is possible!
Apollo makes the schema building and execution for you, but you can also do it yourself.
Here is a mini example based on the apollo-server-express package. I create the schema and then give it to the apollo-server. Look below the server startup, I also create a query-string, then parse it and execute it without apollo and without an http request.
const express = require('express');
const { ApolloServer, gql, makeExecutableSchema } = require('apollo-server-express');
const { parse } = require('graphql/language')
const { execute } = require('graphql')
// Construct a schema, using GraphQL schema language
const typeDefs = gql`
type Query {
hello: String
}
`;
// Provide resolver functions for your schema fields
const resolvers = {
Query: {
hello: () => 'Hello world!',
},
};
const schema = makeExecutableSchema({
typeDefs,
resolvers,
})
async function startApolloServer() {
const server = new ApolloServer({ schema });
await server.start();
const app = express();
server.applyMiddleware({ app });
await new Promise(resolve => app.listen({ port: 4000 }, resolve));
console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`);
return { server, app };
}
startApolloServer()
const query = `
query {
hello
}
`
const document = parse(query)
const res = execute({
schema,
document,
})
console.log('res no request:', res)
if you run it, install apollo-server-express and graphql with npm and you are good to go
To execute you can pass all your request logic as well:
execute({
schema,
document,
rootValue: {},
contextValue: {
userInfo,
dbClient,
},
variableValues: body.variables,
}),
It is highly useful also if you want to test you server. If you need to do subscriptions you can use the subscribe method imported from graphql as well.
I have below code written in nodejs10.
const ApolloClient = require('apollo-boost');
const client = new ApolloClient({
uri: 'http://localhost:8000/graphql'
});
The error I got when running this program is:
const client = ApolloClient({
^
TypeError: ApolloClient is not a function
Below is the dependencies:
"apollo-boost": "^0.3.1",
"apollo-cache-inmemory": "^1.6.0",
"apollo-client": "^2.6.0",
"apollo-link-http": "^1.5.14",
"apollo-server": "^2.5.0",
"apollo-server-express": "^2.5.1",
I followed the user guide to setup a apollo client to take to me server. But it failed at very beginning stage. I wonder what wrong with my code. Is there anything I missed?
In order to initialize Apollo Client, you must specify link & cache properties on the config object. You can override this by using the default import.
const apollo = require('apollo-boost');
const ApolloClient = apollo.default;
const client = new ApolloClient({
uri: 'http://localhost:8000/graphql'
});
require('apollo-boost') does not return ApolloClient, it returns an object that contains ApolloClient.
From a github issue on ApolloGraphQL/apollo-client:
// es6 import
import { default as ApolloClient } from 'apollo-boost';
// es5 or Node.js
const Boost = require('apollo-boost');
const ApolloClient = Boost.DefaultClient;
When using apollo-server 2.2.1 or later, how can one log, for each request, the query and the variables?
This seems like a simple requirement and common use case, but the documentation is very vague, and the query object passed to formatResponse no longer has the queryString and variables properties.
Amit's answer works (today), but IMHO it is a bit hacky and it may not work as expected in the future, or it may not work correctly in some scenarios.
For instance, the first thing that I thought when I saw it was: "that may not work if the query is invalid", it turns out that today it does work when the query is invalid. Because with the current implementation the context is evaluated before the the query is validated. However, that's an implementation detail that can change in the future. For instance, what if one day the apollo team decides that it would be a performance win to evaluate the context only after the query has been parsed and validated? That's actually what I was expecting :-)
What I'm trying to say is that if you just want to log something quick in order to debug something in your dev environment, then Amit's solution is definitely the way to go.
However, if what you want is to register logs for a production environment, then using the context function is probably not the best idea. In that case, I would install the graphql-extensions and I would use them for logging, something like:
const { print } = require('graphql');
class BasicLogging {
requestDidStart({queryString, parsedQuery, variables}) {
const query = queryString || print(parsedQuery);
console.log(query);
console.log(variables);
}
willSendResponse({graphqlResponse}) {
console.log(JSON.stringify(graphqlResponse, null, 2));
}
}
const server = new ApolloServer({
typeDefs,
resolvers,
extensions: [() => new BasicLogging()]
});
Edit:
As Dan pointed out, there is no need to install the graphql-extensions package because it has been integrated inside the apollo-server-core package.
With the new plugins API, you can use a very similar approach to Josep's answer, except that you structure the code a bit differently.
const BASIC_LOGGING = {
requestDidStart(requestContext) {
console.log("request started");
console.log(requestContext.request.query);
console.log(requestContext.request.variables);
return {
didEncounterErrors(requestContext) {
console.log("an error happened in response to query " + requestContext.request.query);
console.log(requestContext.errors);
}
};
},
willSendResponse(requestContext) {
console.log("response sent", requestContext.response);
}
};
const server = new ApolloServer(
{
schema,
plugins: [BASIC_LOGGING]
}
)
server.listen(3003, '0.0.0.0').then(({ url }) => {
console.log(`GraphQL API ready at ${url}`);
});
If I had to log the query and variables, I would probably use apollo-server-express, instead of apollo-server, so that I could add a separate express middleware before the graphql one that logged that for me:
const express = require('express')
const { ApolloServer } = require('apollo-server-express')
const { typeDefs, resolvers } = require('./graphql')
const server = new ApolloServer({ typeDefs, resolvers })
const app = express()
app.use(bodyParser.json())
app.use('/graphql', (req, res, next) => {
console.log(req.body.query)
console.log(req.body.variables)
return next()
})
server.applyMiddleware({ app })
app.listen({ port: 4000}, () => {
console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`)
})
Dan's solution mostly resolves the problem but if you want to log it without using express,
you can capture it in context shown in below sample.
const server = new ApolloServer({
schema,
context: params => () => {
console.log(params.req.body.query);
console.log(params.req.body.variables);
}
});
I found myself needing something like this but in a more compact form - just the query or mutation name and the ID of the user making the request. This is for logging queries in production to trace what the user was doing.
I call logGraphQlQueries(req) at the end of my context.js code:
export const logGraphQlQueries = ( req ) => {
// the operation name is the first token in the first line
const operationName = req.body.query.split(' ')[0];
// the query name is first token in the 2nd line
const queryName = req.body.query
.split('\n')[1]
.trim()
.split(' ')[0]
.split('(')[0];
// in my case the user object is attached to the request (after decoding the jwt)
const userString = req.user?.id
? `for user ${req.user.id}`
: '(unauthenticated)';
console.log(`${operationName} ${queryName} ${userString}`);
};
This outputs lines such as:
query foo for user e0ab63d9-2513-4140-aad9-d9f2f43f7744
Apollo Server exposes a request lifecycle event called didResolveOperation at which point the requestContext has populated properties called operation and operationName
plugins: [
{
requestDidStart(requestContext) {
return {
didResolveOperation({ operation, operationName }) {
const operationType = operation.operation;
console.log(`${operationType} recieved: ${operationName}`)
}
};
}
}
]
// query recieved: ExampleQuery
// mutation recieved: ExampleMutation
I have an express back-end with GraphQL that works when I go to /graphiqland manually perform some searches. My React front-end is trying to perform a search on the back-end. The following code should perform the query asynchronously:
const data = await this.props.client.query({
query: MY_QUERY,
variables: { initials: e.target.value }
});
console.log(data);
Where MY_QUERY is defined before and represents a query that I know works and has been tested on /graphiql. To do this in my React component I export it as export default withApollo(MyComponent) so that it has the client variable in the props.
In the index.js file I defined through Apollo the connection to /graphiql in order to perform the queries:
//link defined to deal with errors, this was found online
const link = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors)
graphQLErrors.map(({ message, locations, path }) =>
console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`,
),
);
if (networkError) console.log(`[Network error]: ${networkError}`);
});
//the httpLink to my GraphQL instance, BASE_URL is defined elsewhere
const httpLink = new HttpLink({
uri: BASE_URL,
headers: {
},
});
//here I define the client linking the GraphQL instance, the cache, and error handling
const client = new ApolloClient({
link: httpLink,
cache,
link
});
When executing the above mentioned query without the linkvariable that handles the error, I receive a 400 Bad Request from the server (ApolloError.js:37 Uncaught (in promise) Error: Network error: Response not successful: Received status code 400). Since this doesn't tell me more, here on StackOverflow and on the Apollo Web page I've found the above error declaration that outputs [Network error]: TypeError: forward is not a function. What does this error mean and how do I solve it?
Thanks!
Your client configuration has a duplicate property -- you first set the link property to your HttpLink and then set it again to your ErrorLink. This means the HttpLink is ignored completely, and you're only passing in the ErrorLink to the configuration. You're seeing that error because the ErrorLink created by onError is not meant to be used by itself. Instead, it should be chained with the HttpLink and that's what you should assign to the link property.
This page in the docs details how to correctly compose links. You can use concat but I prefer ApolloLink.from since it allows you to clearly show the order of your links:
const errorLink = onError(...)
const httpLink = new HttpLink(...)
const link = ApolloLink.from([
errorLink,
httpLink,
])
const client = new ApolloClient({
link,
cache,
})