It seems like you have applied rules to Subscription types but Shield cannot find them in your schema - apollo-server

i have ApolloServer ( "graphql-shield": "^7.5.0 ,apollo-server-core 2.25.0 )
how resolve this issue?
const server = new ApolloServer({
schema: applyMiddleware(schema, permissions),
context: createContext,
uploads: false,
tracing: isDev(),
debug: isDev(),
})
const http = HTTP.createServer(app);
server.installSubscriptionHandlers(http)

Related

GraphQL Shield Type Validation Performed After Resolver Executed, Not Before

I'm using Apollo GraphQL Server with GraphQL shield. When I implement rule on GraphQL type, the Shield authorization performed after the resolver executed. Is that how GraphQL Shield works or is it caused by misconfiguration?
Here's the server configuration
import { ApolloServer } from 'apollo-server-express';
import { ApolloServerPluginDrainHttpServer } from 'apollo-server-core';
import http from 'http';
import { applyMiddleware } from 'graphql-middleware';
import schema from './schema';
import shield from './shield';
(async () => {
const httpServer = http.createServer(app);
const server = new ApolloServer({
schema: applyMiddleware(schema, shield),
csrfPrevention: true,
cache: 'bounded',
plugins: [ApolloServerPluginDrainHttpServer({ httpServer })]
});
await server.start();
server.applyMiddleware({ app });
await new Promise<void>((resolve) =>
httpServer.listen({ port: 80 }, resolve)
);
console.log(`Server ready at http://localhost:80${server.graphqlPath}`);
})(schema);
Thankyou

How to pass different Apollo client to useMutation graphql

I am new to graphql and react. Currently one apollo client is used by default for all useQuery and useMutation which was intialized via ApolloProvider.
Now I have to pass different apollo clients (having different uri) to different queries and mutations. I am able to pass different clients in useQuery() but not able to do the same in useMutation().
// Client initialized via ApolloProvider
const client = new ApolloClient({
cache: new InMemoryCache(),
link: httpLink1,
});
// Custom client with different http link
const customClient = new ApolloClient({
cache: new InMemoryCache(),
link: httpLink2,
});
// This is working where I can see it is using httpLink2
const { loading, error, data } = useQuery(GET_ITEMS, {
client: customClient
});
const [myMutation] = useMutation(LOAD_ITEMS)
const loadItem (): void => {
// not working. By default, the apollo client instance that's passed down via context is use.
const variables = { item: 1, client: customClient }
myMutation({ variables })
// rest of the code
}
As per below useMutation() documentation I can see that we can pass different clients.
https://www.apollographql.com/docs/react/data/mutations/#client. But somehow it is not working for me.
Could someone please help me here.
Thanks in advance.
You can use the same apollo client but use the httpLink conditionally.
https://www.apollographql.com/docs/react/api/link/introduction#providing-to-apollo-client
Creating the link:
import { ApolloLink, HttpLink } from '#apollo/client';
const directionalLink = ApolloLink.split(
operation => operation.getContext().clientName === "second",
new HttpLink({ uri: "http://localhost:4000/v1/graphql" }),
new HttpLink({ uri: "http://localhost:4000/v2/graphql" })
),
Initializing apollo client:
const client = new ApolloClient({
cache: new InMemoryCache(),
link: directionalLink
});
In the component:
const {data, error, loading} = useQuery(GET_STUFF, {
context: { version: "second" }
});

How can i set my ApolloServer to open a graphql playground instead of the apollographql sandbox by default?

My question is how can i set this graphql playground extension as my default playground instead of using the default sandbox when i visited http://hocalhost/port/graphql. Is there any option that i can set during the creation of the ApolloServer instance that can configure that?.
...
const apolloServer = new ApolloServer({
schema: await buildSchema({
validate: false,
resolvers: [HelloResolver, UserResolver],
}),
context: ({ req, res }) => ({ em: orm.em, req, res }),
});
await apolloServer.start();
apolloServer.applyMiddleware({ app });
....
Use the GraphQL Playground plugin and provide it to your Apollo Server constructor. For more info checkout Apollo Docs.
import {
ApolloServerPluginLandingPageGraphQLPlayground
} from "apollo-server-core";
const apolloServer = new ApolloServer({
...
plugins: [
ApolloServerPluginLandingPageGraphQLPlayground(),
],
});

How do you make Schema Stitching in Apollo Server faster?

Initially, I tried to use a Serverless Lambda function to handle schema stitching for my APIs, but I started to move toward an Elastic Beanstalk server to keep from needing to fetch the initial schema on each request.
Even so, the request to my main API server is taking probably ten times as long to get the result from one of the child API servers as my child servers do. I'm not sure what is making the request so long, but it seems like there is something blocking the request from resolving quickly.
This is my code for the parent API:
import * as express from 'express';
import { introspectSchema, makeRemoteExecutableSchema, mergeSchemas } from 'graphql-tools';
import { ApolloServer } from 'apollo-server-express';
import { HttpLink } from 'apollo-link-http';
import fetch from 'node-fetch';
async function run () {
const createRemoteSchema = async (uri: string) => {
const link = new HttpLink({ uri, fetch });
const schema = await introspectSchema(link);
return makeRemoteExecutableSchema({
schema,
link
});
};
const remoteSchema = await createRemoteSchema(process.env.REMOTE_URL);
const schema = mergeSchemas({
schemas: [remoteSchema]
});
const app = express();
const server = new ApolloServer({
schema,
tracing: true,
cacheControl: true,
engine: false
});
server.applyMiddleware({ app });
app.listen({ port: 3006 });
};
run();
Any idea why it is so slow?
UPDATE:
For anyone trying to stitch together schemas on a local environment, I got a significant speed boost by fetching 127.0.0.1 directly instead of going through localhost.
http://localhost:3002/graphql > http://127.0.0.1:3002/graphql
This turned out not to be an Apollo issue at all for me.
I'd recommend using Apollo engine to observe what is really going on with each request as you can see on the next screenshot:
you can add it to your Apollo Server configuration
engine: {
apiKey: "service:xxxxxx-xxxx:XXXXXXXXXXX"
},
Also, I've experienced better performance when defining the defaultMaxAge on the cache controle:
cacheControl: {
defaultMaxAge: 300, // 5 min
calculateHttpHeaders: true,
stripFormattedExtensions: false
},
the other thing that can help is to add longer max cache age on stitched objects if it does make sense, you can do this by adding cache hints in the schema stitching resolver:
mergeSchemas({
schemas: [avatarSchema, mediaSchema, linkSchemaDefs],
resolvers: [
{
AvatarFlatFields: {
faceImage: {
fragment: 'fragment AvatarFlatFieldsFragment on AvatarFlatFields { faceImageId }',
resolve(parent, args, context, info) {
info.cacheControl.setCacheHint({maxAge: 3600});
return info.mergeInfo.delegateToSchema({
schema: mediaSchema,
operation: 'query',
fieldName: 'getMedia',
args: {
mediaId: parseInt(parent.faceImageId),
},
context,
info,
});
}
},
}
},
Finally, Using dataLoaders can make process requests much faster when enabling batch processing and dataloaders caching read more at their github and the code will be something like this:
public avatarLoader = (context): DataLoader<any, any> => {
return new DataLoader(ids => this.getUsersAvatars(dataLoadersContext(context), ids)
.then(results => new Validation().validateDataLoaderArrayResults(ids, results))
, {batch: true, cache: true});
};

check for internet connectivity using WebSocketLink from apollo-link-ws

I'm trying to check for internet connectivity using apollo websockets, the purpose of this is to show a "you're disconnected" message when there is no connection to prevent the user from typing and assuming the changes are saved (the changes are supposedly saved on type), here's part of the setup of apollo-link-ws
const wsLink = new WebSocketLink({
uri: `ws://${hostname}${port ? `:${port}` : ''}/subscriptions`,
options: {
reconnect: true,
connectionParams: () => ({
authorization: localStorage.getItem('accelerator-token')
})
}
});
and
const hasSubscriptionOperation = ({ query: { definitions } }) =>
definitions.some(
({ kind, operation }) =>
kind === 'OperationDefinition' && operation === 'subscription'
);
and here's the client config:
const client = new ApolloClient({
link: ApolloLink.split(
hasSubscriptionOperation,
wsLink,
ApolloLink.from([
cleanTypenameLink,
authMiddleware,
errorLink,
stateLink,
createUploadLink()
])
),
cache
});
After some searching i found that i can use SubscriptionClient from subscriptions-transport-ws
export const myClient = new SubscriptionClient(`ws://${hostname}${port ?
`:${port}` : ''}/subscriptions`, {
reconnect: true,
connectionParams: () => ({
authorization: localStorage.getItem('accelerator-token')
})
});
myClient.onConnected(()=>{console.log("connected f client f onConnected")})
myClient.onReconnected(()=>{console.log("connected f client f
reconnected")})
myClient.onReconnecting(()=>{console.log("connected f client f
reconnecting")})
myClient.onDisconnected(()=>{console.log("connected f client f
onDisconnected")})
myClient.onError(()=>{console.log("connected f client f onError")})
export const wsLink = new WebSocketLink(myClient);
These methods can be used to detect the network status
If you are working with React I found this nice community package react-apollo-network-status

Resources