How to pass mocked executable schema to Apollo Client? - graphql

The Mocking example for Apollo GraphQL has the following code (see below).
The interesting thing is the last line - they create and execute the graphql query. But you usually need to create ApolloClient object. I can't figure out how to do that.
The ApolloClient expect the NetworkingInterface as an argument not the executable schema.
So, is there a way to create ApolloClient from the executable schema, without NetworkingInterface?
import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools';
import { graphql } from 'graphql';
// Fill this in with the schema string
const schemaString = `...`;
// Make a GraphQL schema with no resolvers
const schema = makeExecutableSchema({ typeDefs: schemaString });
// Add mocks, modifies schema in place
addMockFunctionsToSchema({ schema });
const query = `
query tasksForUser {
user(id: 6) { id, name }
}
`;
graphql(schema, query).then((result) => console.log('Got result', result));

The following is lifted from a docs PR written by magbicaleman on GitHub, based on our blog post:
You can easily do this with the apollo-test-utils, like so:
import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools';
import { mockNetworkInterfaceWithSchema } from 'apollo-test-utils';
import { typeDefs } from './schema';
// Create GraphQL schema object
const schema = makeExecutableSchema({ typeDefs });
// Add mocks
addMockFunctionsToSchema({ schema });
// Create network interface
const mockNetworkInterface = mockNetworkInterfaceWithSchema({ schema });
// Initialize client
const client = new ApolloClient({
networkInterface: mockNetworkInterface,
});
Now you can use the client instance as normal!

In Apollo client v2, networkInterface has been replaced with link for the network layer (see the client docs here).
apollo-test-utils hasn't been updated for Apollo client v2, and based on conversations from github, it seems the current recommendation is to use apollo-link-schema:
import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { SchemaLink } from 'apollo-link-schema';
import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools';
import { typeDefs } from './schema';
const schema = makeExecutableSchema({ typeDefs });
addMockFunctionsToSchema({ schema });
const graphqlClient = new ApolloClient({
cache: new InMemoryCache(),
link: new SchemaLink({ schema })
});
Then you just need to inject the client into whatever you're testing!

Related

How to apply validation in graphQL schema using graphql-constraint-directive

import { ApolloServer, makeExecutableSchema } from 'apollo-server-express';
const { constraintDirective, constraintDirectiveTypeDefs } = require('graphql-constraint-directive');
schema: mergeSchemas({
schemas: [
makeExecutableSchema({
resolvers: resolver,
typeDefs: [constraintDirectiveTypeDefs, typeDefs],
schemaTransforms: [constraintDirective()]
}),
],
})
I am referring this pacakge:
https://www.npmjs.com/package/graphql-constraint-directive.
I am getting this error in loading types on my console after implementing it:
Error: Directive "constraint" may not be used on ARGUMENT_DEFINITION.
How to apply validation at schema level?
Your problem is that you are trying to use makeExecutableSchema from apollo-server-express.
As stated in the docs, makeExecutableSchema from graphql-tools should be used.
Solution:
const { ApolloServer } = require('apollo-server-express')
const { makeExecutableSchema } = require('graphql-tools')

Apollo-client State management cache is not updating automatically after save and delete operation

I am using apollo-client for graphql calls along with I added state management with in the package apollo-client. In graphql module, assigned InMemoryCache to cache variable and client variable is exported.Client variable is imported in component so data is available in client.cache.data after default get call executed but I want to update client cache after save and delete graphql operations success callbacks
Here is my graphql.module.ts:
import {NgModule} from '#angular/core';
import {ApolloModule, APOLLO_OPTIONS} from 'apollo-angular';
import { ApolloClient } from 'apollo-client';
import {InMemoryCache} from 'apollo-cache-inmemory';
import { HttpLink } from 'apollo-link-http';
const cache = new InMemoryCache();
const link = new HttpLink({
uri:'https://api.graph.cool/simple/v1/ciyz901en4j590185wkmexyex'
});
export var client = new ApolloClient({
cache,
link
});
#NgModule({
})
and my service call implementation
client
.query({
query: gql`
{
fORoomTypes()
{
nodes
{
roomTypeId
roomType
ratSingle
ratDouble
ratExtra
statu
}
}
}
`,
})
.then(result => {
callback(result);
});
after callback client.cache.data contain data, I want to call this data with cache queries and I want to update cache automatically
this is my save service implementation
const post = gql`
mutation
{
saveRtype(rt:
{
rty:
{
rt:"Club room"
rat:4000
cchub:4500
ext:800
statu:1
}
traCheck:1
}
)
}
`
client.mutate({
mutation: post
}).then((data) => {
callback(data)
});
I've only used apollo client with React but hopefully can shed light on how it works. For this to happen "automatically", you either need to call refetchQueries to refetch fORoomTypes after the mutation, or manually update the cache. I noticed your responses do not return an id property, so how would it know which one to update? If there is an identifier that isn't called "id", then register it following this documentation.
Here is the link to documentation in general for what you want
https://www.apollographql.com/docs/angular/features/cache-updates/

Apollo on local client doesn't trigger the local resolvers

Apollo doesn't trigger the resolvers in the case of Local state Client (frontent local state). Apollo 2.7
Does anyone have any idea why it happens?
Here is the setup:
Apollo client
import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { HttpLink } from 'apollo-link-http'
import fetch from 'isomorphic-unfetch'
import { resolvers, typeDefs } from './resolvers';
import { initCache } from './init-cache';
export default function createApolloClient(initialState, ctx) {
// The `ctx` (NextPageContext) will only be present on the server.
// use it to extract auth headers (ctx.req) or similar.
return new ApolloClient({
ssrMode: Boolean(ctx),
link: new HttpLink({
uri: 'https://api.graph.cool/simple/v1/cixmkt2ul01q00122mksg82pn', // Server URL (must be absolute)
credentials: 'include', // Additional fetch() options like `credentials` or `headers`
fetch,
}),
typeDefs,
resolvers,
connectToDevTools: true,
cache: initCache({
robot: {
__typename: 'Robot',
name: 'Robbie',
status: 'live',
},
member: {
__typename: 'Member',
name: 'RFesagfd',
}
}),
})
}
Types & resolvers (resolvers.js)
import gql from 'graphql-tag';
export const typeDefs = gql`
type Robot {
name: String!
status: String!
}
type Member {
name: String!
isLogged: Boolean!
}
`;
export const resolvers = {
Member: {
isLogged: (...args) => {
console.log('args', args); // THIS NEVER TRIGGERS SOMEHOW
return true;
}
}
};
Query
const GET_IS_MEMBER_LOGGED = gql`
query isMemberLogged {
member #client {
name
isLogged
}
}
`;
Thanks for any help!
You need to define result type of local queries:
const typeDefs = gql`
extend type Query {
robot: Robot
member: Member
}
... and resolver for your query - not type (as you decorated entire query as local)... but you have to return typed data:
export const resolvers = {
Query: {
member: (...args) => {
console.log('args', args);
return {
__typename: 'Member',
name: 'some name', // read from cache
isLogged: true // function result
};
}
}
};
You should also use __typename for cache writes.
update
assuming you have a Memeber in cache ... you can:
// read (initialized with permanent) data:
const memberData = cache.readQuery(....
// f.e. it should have `__typename` and 'name`
// ... and 'decorate' it with derived properites
memberData.age = currentYear - memberData.birthYear;
memberData.isLogged = someFuncReturningBool();
return memberData; // Member type shaped object
It's about shape/data organization - typed (return type shaped object with defined properties) or simple (return all properties separately) or mixed, f.e. (some global app state)
const GET_IS_MEMBER_LOGGED = gql`
query profileViewData {
member #client {
name
isLogged
}
isProfilePanelOpen #client
termsAccepted #client
}
`;
I found a possible solution. Maybe this info will be useful for someone.
If we want to omit the Query Resolver + Field resolvers and we want to have the only Field resolver we need to use #client(always: true).
The in deep explanation
In general, there is a problem with how the Apollo client works with Cache.
By default, it caches the response, and next time it'll fetch the cached result from the cache (eg. optimistic UI). This behavior is the same even in the case of the Client.
It means when we have the initial model in cache Apollo will fetch in from the cache and ignores the resolvers, even if we pass the #client directive.
To solve this problem and let Apollo know that we need to use Local resolvers EVEN if we have a cached object, we need to use #client(always: true) for the preferred field or the whole object. I made an example below.
P.S. Unfortunately I didn't find how to force Apollo to work with non-existing field so if we want to have some resolver for a specific field, we still need to define the initial field value it the initial Cached Model to let the Apollo know about this field. After that, Apollo will use resolver for it to generate some high-calculated output for this particular field, thanks to #client(always: true).
In general, it's ok, because we should know what kind of dynamic field we'll have in our model.
Apollo client
import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { HttpLink } from 'apollo-link-http'
import fetch from 'isomorphic-unfetch'
import { resolvers, typeDefs } from './resolvers';
import { initCache } from './init-cache';
export default function createApolloClient(initialState, ctx) {
// The `ctx` (NextPageContext) will only be present on the server.
// use it to extract auth headers (ctx.req) or similar.
return new ApolloClient({
ssrMode: Boolean(ctx),
link: new HttpLink({
uri: 'https://api.graph.cool/simple/v1/cixmkt2ul01q00122mksg82pn', // Server URL (must be absolute)
credentials: 'include', // Additional fetch() options like `credentials` or `headers`
fetch,
}),
typeDefs,
resolvers,
connectToDevTools: true,
cache: initCache({
author: {
__typename: 'Author',
posts: 0,
name: '' // NEED TO SET AN INITIAL VALUE
}
})
}
Types & resolvers (resolvers.js)
import gql from 'graphql-tag';
import { print } from 'graphql';
export const typeDefs = gql`
type Author {
posts: Int!
name: String
}
`;
export const resolvers = {
Author: {
name(author) {
console.log('Author name resolver', author). // WORKS
return 'NAME';
},
},
};
Query
const GET_AUTHOR = gql`
query getAuthor {
author {
posts
name #client(always: true)
}
}
`;

How to define Upload scalar without GraphQL Schema Language?

There is a sample code where Upload scalar defined with GraphQL Schema Language:
import { makeExecutableSchema } from 'graphql-tools'
import { GraphQLUpload } from 'apollo-upload-server'
const typeDefs = `
scalar Upload
`
const resolvers = {
Upload: GraphQLUpload
}
export const schema = makeExecutableSchema({ typeDefs, resolvers })
How can we do the same thing without GraphQL Schema language?
You can create a GraphQLSchemaType object.
const uploadType = new GraphQLScalarType({ name: "Upload" });
You'd then have to use that as the type of GraphQLField and GraphQLInputObjectField objects.
(In my experience the GraphQL schema language is more compact and readable than building up a language-native object model and in practice I'd stick with the form you have in the question.)

Querying REST API with Cursor Pagination from Server with Apollo-Server-Express

Using Apollo-Server-Express, I want to wrap a REST API with GraphQL. I'm starting with the free to use SWAPI (Star Wars API). I can't find anything about server side fetching with cursor paging using apollo-server-express. The only thing that I found that could be a possibility since it's for the Apollo Client is fetchMore. Any help would be greatly appreciated. Here's my code:
schema.js
// Imports: GraphQL
import { makeExecutableSchema } from 'graphql-tools';
// Imports: GraphQL TypeDefs & Resolvers
import TYPEDEFS from './types.js';
import RESOLVERS from './resolvers.js';
// GraphQL: Schema
const SCHEMA = makeExecutableSchema({
typeDefs: TYPEDEFS,
resolvers: RESOLVERS
});
export default SCHEMA;
types.js
const TYPEDEFS = `
type Query {
getFilm(id: ID): Film
getAllFilms: [Film]
}
type Film {
title: String!
episode_id: Int!
opening_crawl: String
director: String
producer: String
release_date: String
characters: [Person]
planets: [Planet]
starships: [Starship]
vehicles: [Vehicle]
species: [Species]
created: String
edited: String
url: String
}
}`
export default TYPEDEFS;
resolvers.js
import fetch from 'node-fetch';
const RESOLVERS = {
Query: {
// Search for a Film by ID
getFilm: async (parent, args) => {
const response = await
fetch(`https://swapi.co/api/films/${args.id}`);
return response.json();
},
getAllFilms: async (parent, args) => {
const response = await
fetch(`https://swapi.co/api/films/`);
return response.json();
}
}
};
export default RESOLVERS;
I believe apollo-server does not provide cursor pagination out of the box.
You can either implement it yourself. Or you can use(or get inspired) by the one that Relay uses.
And according to Apollo client if you use Relay style cursor pagination the client has support for it.

Resources