"Invalid URL: words" - apollo-server - graphql

I would like to create small project using GraphqQL, ApolloServer, but I encountered a problem, that I can't solve. I wrote it based on several documentation.
const { ApolloServer, gql } = require('apollo-server');
const { RESTDataSource } = require('apollo-datasource-rest');
const typeDefs = gql`
type Word {
id: ID!
word: String!
translation: String!
}
type Query {
words: [Word]
word(id: ID): Word
}
`;
class WordsAPI extends RESTDataSource {
constructor() {
super();
this.baseURL = 'localhost:5001/'
}
async getWord(id) {
return this.get(`word/${id}`)
}
async getAllWords() {
return this.get('words')
}
async getSpecifiedWords(SpecWord) {
return this.get(`words/${SpecWord}`)
}
}
const resolvers = {
Query: {
words: (_, __, { dataSources }) =>
dataSources.wordsAPI.getAllWords(),
word: async (_source, { id }, { dataSources }) => {
return dataSources.wordsAPI.getWord(id);
}
}
}
const server = new ApolloServer({
typeDefs,
resolvers,
dataSources: () => {
return {
wordsAPI: new WordsAPI()
};
},
context: () => {
return {
};
},
});
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
After
query {
words {
translation
}
}
In playground I am getting Invalid URL: words.
At localhost:5001/words is database and in Postman it works.
What did I bad?

Related

Apollo nodejs server; How to get mutation/query schema path in the request context when writing a plugin?

I'm writing an Apollo server plugin for node.js, and my goal is to improve my teams debugging experience. My plugin currently looks something like this:
export function eddyApolloPlugin(): ApolloServerPlugin {
return {
requestDidStart(requestContext) {
// Set requestId on the header
const requestId = (requestContext?.context as EddyContext)?.requestId;
if (requestId) {
requestContext.response?.http?.headers.set('requestId', requestId);
}
return {
willSendResponse(context) { // <== Where do I find the "path" in the schema here?
// Inspired by this: https://blog.sentry.io/2020/07/22/handling-graphql-errors-using-sentry
// and the official documentation here: https://docs.sentry.io/platforms/node/
// handle all errors
for (const error of requestContext?.errors || []) {
handleError(error, context);
}
},
};
},
};
}
I would like to know if I can access the path in the schema here? It's pretty easy to find the name of mutaiton/query with operation.operationName, but where can I get the name of the query/mutation as defined in the schema?
Solution
export function eddyApolloPlugin(): ApolloServerPlugin {
return {
requestDidStart(requestContext) {
// Set requestId on the header
const requestId = (requestContext?.context as EddyContext)?.requestId;
if (requestId) {
requestContext.response?.http?.headers.set('requestId', requestId);
}
return {
didResolveOperation(context) {
const operationDefinition = context.document
.definitions[0] as OperationDefinitionNode;
const fieldNode = operationDefinition?.selectionSet
.selections[0] as FieldNode;
const queryName = fieldNode?.name?.value;
// queryName is what I was looking for!
},
};
},
};
}
Your requirement is not very clear. If you want to get the name of the query/mutation to distinguish which query or mutation the client sends.
You could get the name from context.response.data in willSendResponse event handler.
E.g.
server.ts:
import { ApolloServer, gql } from 'apollo-server';
import { ApolloServerPlugin } from 'apollo-server-plugin-base';
import { parse, OperationDefinitionNode, FieldNode } from 'graphql';
function eddyApolloPlugin(): ApolloServerPlugin {
return {
requestDidStart(requestContext) {
return {
didResolveOperation(context) {
console.log('didResolveOperation');
const obj = parse(context.request.query!);
const operationDefinition = obj.definitions[0] as OperationDefinitionNode;
const selection = operationDefinition.selectionSet.selections[0] as FieldNode;
console.log('operationName: ', context.request.operationName);
console.log(`${context.operation!.operation} name:`, selection.name.value);
},
willSendResponse(context) {
console.log('willSendResponse');
console.log('operationName: ', context.request.operationName);
console.log(`${context.operation!.operation} name:`, Object.keys(context.response.data!)[0]);
},
};
},
};
}
const typeDefs = gql`
type Query {
hello: String
}
type Mutation {
update: String
}
`;
const resolvers = {
Query: {
hello() {
return 'Hello, World!';
},
},
Mutation: {
update() {
return 'success';
},
},
};
const server = new ApolloServer({ typeDefs, resolvers, plugins: [eddyApolloPlugin()] });
const port = 3000;
server.listen(port).then(({ url }) => console.log(`Server is ready at ${url}`));
GraphQL Query:
query test {
hello
}
the logs of the server:
didResolveOperation
operationName: test
query name: hello
willSendResponse
operationName: test
query name: hello
GraphQL Mutation:
mutation test {
update
}
the logs of the server:
didResolveOperation
operationName: test
mutation name: update
willSendResponse
operationName: test
mutation name: update

GraphQL Subscriptions return an empty (null) response [duplicate]

I have the following GRAPHQL subscription:
Schema.graphql
type Subscription {
booking: SubscriptionData
}
type SubscriptionData {
booking: Booking!
action: String
}
And this is the resolver subsrciption file
Resolver/Subscription.js
const Subscription = {
booking: {
subscribe(parent, args, { pubsub }, info) {
return pubsub.asyncIterator("booking");
}
}
};
export default Subscription;
Then I have the following code on the Mutation in question
pubsub.publish("booking", { booking: { booking }, action: "test" });
I have the follow subscription file in front end (React)
const getAllBookings = gql`
query {
bookings {
time
durationMin
payed
selected
activity {
name
}
}
}
`;
const getAllBookingsInitial = {
query: gql`
query {
bookings {
time
durationMin
payed
selected
activity {
name
}
}
}
`
};
class AllBookings extends Component {
state = { allBookings: [] }
componentWillMount() {
console.log('componentWillMount inside AllBookings.js')
client.query(getAllBookingsInitial).then(res => this.setState({ allBookings: res.data.bookings })).catch(err => console.log("an error occurred: ", err));
}
componentDidMount() {
console.log(this.props.getAllBookingsQuery)
this.createBookingsSubscription = this.props.getAllBookingsQuery.subscribeToMore(
{
document: gql`
subscription {
booking {
booking {
time
durationMin
payed
selected
activity {
name
}
}
action
}
}
`,
updateQuery: async (prevState, { subscriptionData }) => {
console.log('subscriptionData', subscriptionData)
const newBooking = subscriptionData.data.booking.booking;
const newState = [...this.state.allBookings, newBooking]
this.setState((prevState) => ({ allBookings: [...prevState.allBookings, newBooking] }))
this.props.setAllBookings(newState);
}
},
err => console.error(err)
);
}
render() {
return null;
}
}
export default graphql(getAllBookings, { name: "getAllBookingsQuery" })(
AllBookings
);
And I get the following response:
data: {
booking: {booking: {...} action: null}}
I get that I am probably setting up the subscription wrong somehow but I don't see the issue.
Based on your schema, the desired data returned should look like this:
{
"booking": {
"booking": {
...
},
"action": "test"
}
}
The first booking is the field on Subscription, while the second booking is the field on SubscriptionData. The object you pass to publish should have this same shape (i.e. it should always include the root-level subscription field).
pubsub.publish('booking', {
booking: {
booking,
action: 'test',
},
})

GraphQL query ( Apollo client link state ) returns empty object {}

The Query
const GET_MEMBER = gql`
query getMembers {
getMembers #client {
firstname
lastname
__typename
}
}
`
export { GET_MEMBER }
The Resolver:
export default {
resolvers: {
Query: {
getMembers: async (_, variables, { cache }) => {
try {
const res = await apiClient.get('/contacts')
return { ...res.data, __typename: 'Member' }
} catch (e) {
throw e
}
},
},
apiClient is an instance of axios
React App:
<Query query={GET_MEMBER}>
{({ loading, error, data }) => {....
I am getting this warning
and the Query in my React App returns {}
Where should I start to debeg it?

Hello world example for Apollo Client 2 + React?

Im trying to return a string with React and GraphQL but I'm getting stuck at the first stage. Here is my attempt:
import { makeExecutableSchema } from 'graphql-tools';
const typeDefs = `
type Query {
author: Person
}
type Person {
name: String
}
`;
const resolvers = {
Query: {
author: { name: 'billy' },
},
};
const schema = makeExecutableSchema({
typeDefs,
resolvers,
});
createApolloServer({ schema });
And this is my understanding of that code:
In my schema I've defined a Query called author which should return a Person.
A Person has a name field which is a string.
My resolver has a Query called author which should return an object with a name field of value 'billy'
However in my Graphicool browser tools this query:
query {
author{
name
}
}
Returns this:
{
"data": {
"author": null
}
}
Resolvers are functions which GraphQL will call when resolving that particular field. That means your resolvers object should look more like this:
const resolvers = {
Query: {
author: () => ({ name: 'billy' }),
},
}
Or, alternatively,
const resolvers = {
Query: {
author() {
return { name: 'billy' }
},
},
}
You can check out the docs for more information.
import { createApolloServer } from 'meteor/apollo';
import { makeExecutableSchema } from 'graphql-tools';
import merge from 'lodash/merge'; // will be useful later when their are more schemas
import GroupsSchema from './Groups.graphql';
import GroupsResolvers from './resolvers';
const typeDefs = [GroupsSchema];
const resolvers = merge(GroupsResolvers);
const schema = makeExecutableSchema({
typeDefs,
resolvers,
});
createApolloServer({ schema });
In ./Groups.graphql:
type Query {
hi: String
groups: [Group]
group: Group
}
type Group {
name: String
}
In './resolvers':
export default {
Query: {
hi() {
return 'howdy';
},
groups() {
return [{ name: 'one', _id: '123' }, { name: 'two', _id: '456' }];
// return Groups.find().fetch();
},
group() {
return { name: 'found me' };
},
},
};
In a React component:
const mainQuery = gql`
{
groups {
name
}
}
`;
export default graphql(mainQuery)(ComponentName);

Variable value in graphql mutation isn't saving

I have simple mutation with variables as:
Mutation Query
mutation M($name: String) {
Adduser(name: $name) {
_id
name
}
}
Query variables
{
"name":"user1"
}
And in graphql API:
app.post('/graphql', (req, res) => {
const query = req.body.query;
const vars = req.body.variables;
//console.log(vars);/*showing { "name":"user1" }*/
graphql(Schema, query, null, vars).then(result => {
res.send(result);
});
});
but the output i am getting is:
{
"data": {
"Adduser": {
"_id": "593a2cd4cf057a07d073e971",
"name": null
}
}
}
Updated
userType:
const Adduser = {
type: userType,
args: {
name: {
type: graphql.GraphQLString
},
age: {
type: graphql.GraphQLInt
}
},
resolve: (obj, args) => {
return new Promise((resolve, reject) => {
var user=new User({
name:args.name
});
user.save(function(err,usr){
if(err){
console.log(err);
}
else{
resolve(usr);
}
});
})
}
};
mutation:
const Rootmutation = new graphql.GraphQLObjectType({
name: 'Rootmutation',
fields: {
Adduser: Adduser
}
});
const schema = new graphql.GraphQLSchema({
query: Rootquery,
mutation: Rootmutation
});
It means the variable value is not binding with mutation query.
Any suggestion here??

Resources