habx / apollo-multi-endpoint-link Goto Github PK
View Code? Open in Web Editor NEW⛓ Apollo link which add an api directive to fetch data from multi endpoints
License: MIT License
⛓ Apollo link which add an api directive to fetch data from multi endpoints
License: MIT License
Hi and thank you for the wonderful library and idea!
We are working on similar solution and would be great to chat and see if we can reuse code or somehow help each other.
We've create GraphQL Mesh - a library that let's you query multiple APIs, they could be multiple GraphQL APIs but also other types of APIs (REST/OpenAPI/gRPC etc that are automatically converted into GraphQL).
GraphQL Mesh can run anywhere, including the client.
So we also worked on a project called Graph Client - it is a client side library that uses GraphQL Mesh under the hood and can expose all this logic as an Apollo Link.
I love the API and the simplicity of your solution, I wonder if somehow our libraries could benefit yours and the other way around
createHttpLink: () => new HttpLink({ ... })
hi there i confused about this line... in special with ( ... ) mmmm.. i start with graphql and react but i don understand what must be inside there.. can help me.. thk
For the last week I've trying to make this library work within Nuxt 3. I can't seem to access the multple endpoints
nuxt.config.ts
...
apollo: {
autoImports: true,
authType: "XXXXXX",
authHeader: "Authorization",
tokenStorage: "cookie",
proxyCookies: true,
clients: {
default: {
httpEndpoint: "localhost", //placeholder will be replaced at runtime by apollo plugin
tokenName: "headerAuth",
httpLinkOptions: {
credentials: "same-origin",
},
},
},
})
apollo.ts
import { provideApolloClient } from "@vue/apollo-composable"
import { MultiAPILink } from "@habx/apollo-multi-endpoint-link"
export default defineNuxtPlugin((nuxtApp) => {
const config = useRuntimeConfig()
let client = new ApolloClient({
cache: new InMemoryCache(),
link: ApolloLink.from([
new MultiAPILink({
endpoints: {
exchange: config.public.api,
trade: config.public.apiTwo,
},
createHttpLink: () => createHttpLink(),
httpSuffix: "",
getContext: (endpoint) => {
if (endpoint === "exchange") {
return {
headers: {
Authorization: `Bearer ${config.public.token}`,
},
}
}
return {
headers: {
Authorization: `Bearer ${config.public.token}`,
},
}
},
}),
]),
})
provideApolloClient(client)
})
Query
const query = gql`
query services {
services {
... on Service {
name
identifier {
externalID
}
serviceType {
name
identifier {
externalID
}
}
}
}
}
`
const { data, error } = await useAsyncQuery(query)
if (data.value) (this.data = data), (this.loading = false)
if (error.value) (this.error = error.value), console.log("error: " + error?.value)
if (data.value) {
console.log("Exchange: Services")
console.log(data.value)
}
}
It keeps calling the wrong endpoint. I've also tried useQuery
. Any suggestions?
Hello,
Thank you for publishing this link. I've faced a similar use case and implemented a similar one-off solution that works in a similar way. One thing that I have not found a solution for is the case when there are multiple endpoints and we need to feed Apollo Client with some schema, i.e. with IntrospectionFragmentMatcher
. I keep coming to the conclusion that Apollo just wants there to be one schema and that solutions like yours won't stand the test of time in more complex use cases. I'm just curious if you have encountered this problem?
The main link in the readme is broken.
https://www.habx.com/tech/micro-graphql-schema
External linking is bad practice especially for essential information.
We are trying to pass an apollo link object instead of string to the two endpoints but we are getting error that the apollo link is not assignable to type string.
return new ApolloClient({
ssrMode: typeof window === 'undefined',
link: ApolloLink.from([
new MultiAPILink({
endpoints: {
laravel: {
link: ApolloLink.from([
authLink,
errorLink,
httpLink
])
},
wordpress: {
link: ApolloLink.from([
authLinkwp,
errorLinkwp,
httpLinkwp
])
}
}
})
]),
cache: new InMemoryCache(),
});
}
How can this be fixed and how can we add different cache for each
I would like to use this neat library, but my multiple endpoints uris are not know upfront, some of them are, but the others are generated dynamically on user interaction with the application. Is there a way to inject more endpoint uris as they become available?
Here is my problem. I implemented this package into my code. It querys using GraphQL, then it just keep loading...
Does anyone know how to fix?
Hello, maybe can you help me with this, I can use this query (hasura endpoint) on GraphiQL and it response well but when I use it on my code this return: field 'basic_users' not found in type: 'query_root'
, but when I use nest endpoint it's work correctly.
Thank you
"@apollo/client": "^3.7.14",
"@habx/apollo-multi-endpoint-link": "^2.9.0",
"graphql": "^16.6.0"
import {gql} from '@apollo/client';
export const GET_BASIC_USER = gql`
query GetBasicUser @api(name: hasura) {
basic_users {
name
}
}
`;
const getGraphqlClient = (
token = '',
roles: BasicUserRoles,
env: boolean,
) => {
let currentToken = '';
return new ApolloClient({
connectToDevTools: true,
cache: new InMemoryCache({
addTypename: true,
typePolicies: {
query_root: {queryType: true},
},
}),
link: ApolloLink.from([
new MultiAPILink({
getContext: async endpoint => {
currentToken = `Bearer ${token || (await getPersist())}`;
if (endpoint === 'hasura') {
return {
headers: {
Authorization: currentToken,
'x-hasura-allowed-roles': roles,
},
};
}
return {};
},
endpoints: {
hasura: HASURA_GRAPHQL_ENDPOINT,
nest: NESTJS_GRAPHQL_ENDPOINT,
},
createHttpLink: () => createHttpLink(),
httpSuffix: '',
}),
]),
});
};
Hi there,
I'm running into an issue with the apollo-multi-endpoint-link
, and at this point I have no idea what to do anymore.
I'm using the same configuration as the example, providing 3 different endpoints, and using 3 Graphql queries that use this name as an identifier. Like this:
Queries:
const GET_ACTIVE_ITEMS_GOERLI = gql`
query GetActiveItems @api(name: goerli) {
activeItems(
...
`
const GET_ACTIVE_ITEMS_MUMBAI = gql`
query GetActiveItems @api(name: mumbai) {
...
`
const GET_ACTIVE_ITEMS_ARBITRUM_GOERLI = gql`
query GetActiveItems @api(name: arbitrumGoerli) {
...
`
Fetching:
const { data: goerliData, loading: goerliDataLoading } = useQuery(
GET_ACTIVE_ITEMS_GOERLI,
);
const { data: mumbaiData, loading: mumbaiDataLoading } = useQuery(
GET_ACTIVE_ITEMS_MUMBAI,
);
const { data: arbitrumGoerliData, loading: arbitrumGoerliDataLoading } =
useQuery(GET_ACTIVE_ITEMS_ARBITRUM_GOERLI);
Configuration:
const apolloClient = new ApolloClient({
cache: new InMemoryCache(),
link: ApolloLink.from([
errorLink,
new MultiAPILink({
endpoints: {
goerli: process.env.NEXT_PUBLIC_SUBGRAPH_URL_GOERLI,
mumbai: process.env.NEXT_PUBLIC_SUBGRAPH_URL_MUMBAI,
arbitrumGoerli: process.env.NEXT_PUBLIC_SUBGRAPH_URL_ARBITRUM_GOERLI,
},
createHttpLink: () => createHttpLink(),
httpSuffix: '',
}),
]),
});
These queries are all fetched, then a useEffect
hook sets a new variable activeItems
, choosing from the 3 results based on the network.
Unfortunatly, the activeItems
result seems completely random, as passing one network name will make the variable change between the queries results with no regularity. All 3 data variables goerliData
mumbaiData
and arbitrumGoerliData
get initialized with the same array on each refresh, as if the 3 query results could not coexist.
Since the network and conditions are working correctly, I believe the @api(name)
selector is not working. It looks like it's setting activeItems
to one of the 3 queries without respecting the endpoint selection.
I have no idea what I'm doing wrong here. Here is a codesandbox with just the needed parameters.
You can start it as usual yarn && yarn dev
, go to index.js
and then just change the Actually, you just need to refresh the page a few times, the results will change sometimes, maybe because it gets set up to the latest query result ? Although each data should get its own query ?network
variable (line 63) to any of the 3 networks: goerli
/ mumbai
/ arbitrumGoerli
. Then you just refresh the page. And you can repeat. They should respectively return an array of 9 / 2 / 4 objects, but they don't.
https://codesandbox.io/s/multi-endpoints-issue-dzxdw7?file=/pages/index.js
Thanks already to anyone who will take the time to help me :)
Hi, I am using WebStorm with the GraphQL extension. Intellisense gives me an error when I add API Directive, How can solve this problem, I tried to search how to add a directive to the nest.js with the arguments but I don't find a solution
Is there a way to define a default endpoint? So if { context: { apiName: 'name' } }
is not passed it defaults to that endpoint?
TLDR:
The persisted query link requires using the HttpLink
. (see link to their doc bellow).
Is it possible to set up MultiAPILink using HttpLink
? (instead of createHttpLink
)
Longer explanation:
Hello, in apollo-client.ts I had implemented PersistendQueryLink
, based on https://www.apollographql.com/docs/react/api/link/persisted-queries/
I have const links = []
and then push there errorLink
, authorizationLink
, (retry link
), following by:
if (process.env.NODE_ENV === 'production') {
const persistedQueryLink = createPersistedQueryLink({ sha256 })
links.push(persistedQueryLink)
}
const retryLink = new RetryLink()
links.push(retryLink)
const httpLink = new MultiAPILink({
createHttpLink: () => createHttpLink(),
endpoints,
httpSuffix: '',
wsSuffix: '',
})
links.push(httpLink)
export const client = new ApolloClient({
cache,
link: ApolloLink.from(links),
})
I get error from BE:
"PersistedQueryNotFoundError: PersistedQueryNotFound"
at processGraphQLRequest (/Users/david/Documents/github/datacatalog-be/node_modules/apollo-server-core/src/requestPipeline.ts:181:40)"
at processTicksAndRejections (node:internal/process/task_queues:96:5)"
at processHTTPRequest (/Users/david/Documents/github/datacatalog-be/node_modules/apollo-server-core/src/runHttpQuery.ts:434:24)"
message
:
"PersistedQueryNotFound"
Before using this library, I connected to 1 endpoint like so:
const httpLink = new HttpLink({
uri: process.env.NEXT_PUBLIC_API_URL,
})
Thus it is clear my error comes from connecting to multiple endpoints using this library.
I think answer to my problem is in sentence: The persisted query link requires using the HttpLink. (see link to their doc above).
Thus my question is, is it possible to set up MultiAPILink using HttpLink? (instead of createHttpLink). If yes, how?
How can I use two different apis in a single query, is there anyway to make api directives subquery specific?
query($id: String!) {
widgets( id: $id ) @api(name: widgetEndpoint) {
width
weight
}
gadgets( id: $id ) @api(name: gadgetEndpoint) {
length
color
}
}
;
Hello, it seems your library allows for using subscriptions-transport-ws
to establish graphql subscription, which is not maintained anymore and is not recommended to be used.
Is there a way to make your library work with graphql-ws
?
To be clear, I just want to use subscription
next to already using query
and mutation
using this library. Is there an example how apollo-multi-endpoint-link can be used with graphql subscription?
Thank you for any help.
Hi, I got multiple Graphql servers, and everyone has their own subscriptions
I'm wondering if your middleware support that or willing to support it in the near future?
It would really help to have a complete simple test case. That could be used as an example and to test the library,
May I know is this being maintained? I have implemented the solution, it seems like it's always in a loading state when data is fetched from GraphQL API.
Hello, I successfully use your library to query 2 endpoints. Now, how do I auto-generate types from 2 graphql schemas, when using 2 endpoints?
Scripts I used up until now (with standard 1 endpoint) uses Apollo codegen (source):
"schema": "npx apollo service:download --endpoint=http://localhost:8080/graphql graphql-schema.json",
"types": "npm run schema && apollo client:codegen --localSchemaFile=graphql-schema.json --variant=development --target=typescript --addTypename --queries=./src/**/*.graphql --useReadOnlyTypes --globalTypesFile=src/globalTypes.ts . && npm run prettier"
Possible solution is also generating 2 introspection schemas and then merging them together, I just didn't find how.
I'm also open to move to Graphql Code Generator.
Is there any example, guidance, or link please?
Thank you
There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.
Error type: Cannot find preset's package (github>habx/devops-repo-shared-configs//renovate/ts-lib-client-public)
Great idea to put together this library! I know the library is pretty young, and thus the documentation is lacking. I was wondering how we can pass in additional parameters/variables to the query?
Hi, thanks for this library! Is there any limitation in regards to using it (support for subscriptions, cache or something else)?
Also it's not clear how headers should be set, don't you support a way of setting headers per endpoints? If we need to set headers in the createHttpLink
function, does that mean that all headers are going to be sent to all endpoints? I have 2 different 3rd party services that uses Authorization
as headers, therefore I can't send the same headers for all endpoints.
Thanks!
I have several GraphQL endpoints I'm trying to fetch from that share many of the same field names, but have different schemas and values within those fields. For example, what if I have these 2 queries I want to run:
query {
products {
id # UUID string
seller # string
price # Int, number of cents
}
}
query {
products {
id # number
affiliate # string
price # string of the format "$1.23"
}
}
Can I use this library to query from both of these endpoints without any caching issues?
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
.circleci/config.yml
node 1.4.0
package.json
@apollo/client ^3.7.3
@habx/config-ci-front ^3.9.0
@habx/eslint-config-client ^6.10.0
@types/jest ^29.2.5
apollo-link-rest *
bili ^5.0.5
cz-conventional-changelog ^3.3.0
eslint ^8.30.0
graphql ^15.8.0
jest ^29.3.1
jest-fetch-mock ^3.0.3
lint-staged ^13.1.0
rimraf ^3.0.2
rollup-plugin-typescript2 ^0.34.1
ts-jest ^29.0.3
typescript ^4.9.4
@apollo/client ^3.7.3
Looks like tscov is missing from dev dependencies
Adding this and running
npm run type:coverage
shows error
Error: ENOENT: no such file or directory, stat '/home/mwoodpatrick/projects/git/www/apollo-multi-endpoint-link/@habx/config-ci-front/typescript/library.json'
When using this with fragments and prefixTypenames: true
, I end up getting an empty object without any of the fields from the fragments. The network result will include all the id and name values, but the object returned from the Apollo client will not. Is there anything special that we need to add to make those work?
Example:
query myQuery @api(name: myApi) {
clusterRangeQuery {
graphId
clusters {
...Cluster
}
edges {
source
target
}
}
}
fragment Cluster on Cluster {
id
label
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.