Comments (17)
My implementation, based on @Zn4rK's work, for avoiding ' You are calling concat on a terminating link, which will have no effect` while still using Batching etc.
import { getMainDefinition } from 'apollo-utilities';
import { split } from 'apollo-link';
import { httpLink } from './httpLink.js';
import { wsLink } from './wsLink.js';
import { uploadLink } from './uploadLink.js';
const isFile = value => (
(typeof File !== 'undefined' && value instanceof File) ||
(typeof Blob !== 'undefined' && value instanceof Blob)
);
const isUpload = ({ variables }) =>
Object.values(variables).some(isFile);
const isSubscriptionOperation = ({ query }) => {
const { kind, operation } = getMainDefinition(query);
return kind === 'OperationDefinition' && operation === 'subscription';
};
const requestLink = split(isSubscriptionOperation, wsLink, httpLink);
export const terminalLink = split(isUpload, uploadLink, requestLink);
from apollo-upload-client.
That error makes sense, it looks like you are concatenating the links in the wrong order. apollo-upload-client
is a "terminating" link; that means no link can be concatenated after because it is the end of the road for sending the request off.
from apollo-upload-client.
The omitTypename
with JSON.parse
is too aggressive that it deleted the File
, so when forwarding to the uploadLink, it disappeared.
function omitTypename(key, value) {
return key === '__typename' ? undefined : value
}
const cleanTypenameFieldLink = new ApolloLink((operation, forward) => {
if (operation.variables) {
operation.variables = JSON.parse(JSON.stringify(operation.variables), omitTypename)
}
return forward(operation)
});
My fix is to use a less aggressive omit __typename function with a check for file uploading first.
const isFile = value => (
(typeof File !== 'undefined' && value instanceof File) ||
(typeof Blob !== 'undefined' && value instanceof Blob)
);
//borrow from https://gist.github.com/Billy-/d94b65998501736bfe6521eadc1ab538
function omitDeep(value, key) {
if (Array.isArray(value)) {
return value.map((i) => omitDeep(i, key))
} else if (typeof value === 'object' && value !== null && !isFile(value)) {
return Object.keys(value).reduce((newObject, k) => {
if (k == key) return newObject
return Object.assign({ [k]: omitDeep(value[k], key) }, newObject)
}, {})
}
return value
}
function createOmitTypenameLink() {
return new ApolloLink((operation, forward) => {
if (operation.variables) {
operation.variables = omitDeep(operation.variables, '__typename')
}
return forward(operation)
})
}
const uploadLink = createUploadLink({
uri: GRAPHQL_URL
})
const createApolloClient = (cache = {}) => {
return new ApolloClient({
connectToDevTools: process.browser,
ssrMode: typeof window !== 'undefined',
cache: new InMemoryCache().restore(cache),
link: ApolloLink.from([omitTypenameLink, uploadLink])
})
}
from apollo-upload-client.
@dbelchev I'm aware you can concat in that manner too. I tried that and it yielded the same result:
import cleanTypenameFieldLink from './utils/cleanTypenameFieldLink';
const uploadLink = createUploadLink({ uri });
// Apollo client
const client = new ApolloClient({
link: ApolloLink.from([cleanTypenameFieldLink, uploadLink]),
cache: new InMemoryCache(),
credentials: 'same-origin' //TODO: Make this more stringent on prod
});
Which is a un-promised preview file on the server:
upload:
{ preview: 'blob:http://localhost:3333/3a4284ce-0ffd-4eed-b80b-3a6262d7ee3a' }
or upload simply ends up null as shown below.
The only thing I can think is that I'm using the scalar Upload
type as a nested property on a larger input type at this point:
export const PhotoInput = `
scalar Upload
input PhotoInput {
id: String!
postName: String!
whatToDo: String!
unixTime: Int!
bounty: Float
upload: Upload!
meta: PhotoMetaInput!
}
`;
Here's what my object looks like before sending:
Note that this input works when un-composed, and doesn't include the "__typename" prop.
Here's the same object console.logged
in an extremely dumb link function showing that the photoInput upload property has changed:
export default new ApolloLink((operation, forward) => {
console.log('after', operation);
return forward(operation)
});
At this point, depending on what the "dumb" link does, upload either ends up: null
or just a preview blob, and I can't execute the promise on the server.
from apollo-upload-client.
This was an issue with my own link. Closing, and I apologize for any confusion.
from apollo-upload-client.
I have exactly the same issue, no idea how to figure out the cause of the problem.
Any ideas plesae how to start solving such an issue? It seems it could be valuable for others as well.
Maybe it would be also very useful if someone could provide an example how to correctly create a complex link both on the client and using ssr, and how to use it if the graphql schema is a bit more complex.
from apollo-upload-client.
I decided to avoid this package. I send base64 of whatever I want to upload to the server.
from apollo-upload-client.
I'm trying to figure this one out. Would love some help if anyone notices an obvious blunder below
import {ApolloClient} from 'apollo-client';
import {ApolloLink} from 'apollo-link';
import {InMemoryCache} from 'apollo-cache-inmemory';
import fetch from 'isomorphic-fetch'; // https://github.com/apollographql/apollo-link/issues/513#issuecomment-368234260
import apolloLogger from 'apollo-link-logger';
import {authLink, httpLink} from './links';
import errorLink from './links/errorLink';
import {createUploadLink} from 'apollo-upload-client';
// create apollo cache
const cache = new InMemoryCache({});
const uploadLink = createUploadLink({
uri: !process.env.REACT_APP_API_HOST,
headers: {
'keep-alive': 'true',
},
});
let links = [authLink, errorLink, httpLink, uploadLink];
if (process.env.NODE_ENV === 'development') {
links = [apolloLogger, authLink, errorLink, httpLink, uploadLink];
}
// create apollo-client instance
const client = new ApolloClient({
link: ApolloLink.from(links),
fetch,
cache,
connectToDevTools: process.env.NODE_ENV === 'development',
});
// export the client to be used by the app
export default client;
everything is working until I add uploadLink
UPDATE: All I had to do was remove my httpLink which I guess is doing the same thing as uploadLink
from apollo-upload-client.
As mentioned in 1) and 2) I've tried it both ways. With uploadLink last as well.
It appears to me what's happening is:
When I don't compose it and just use the straight up uploadLink
const uploadLink = createUploadLink({ uri });
const client = new ApolloClient({
link: uploadLink,
cache: new InMemoryCache(),
credentials: 'same-origin' //TODO: Make this more stringent on prod
});
I'm getting an upload "Promise" on the server side, which then lets me resolve the stream from it:
upload:
Promise {
{ stream: [Object],
filename: 'cool2.png',
mimetype: 'image/png',
encoding: '7bit' } }
But, when I compose the link with my custom link:
import cleanTypenameFieldLink from './utils/cleanTypenameFieldLink';
const uploadLink = createUploadLink({ uri });
const appLink = concat(cleanTypenameFieldLink, uploadLink);
// Apollo client
const client = new ApolloClient({
link: appLink,
cache: new InMemoryCache(),
credentials: 'same-origin' //TODO: Make this more stringent on prod
});
The response on my server I just get a "preview" file upload, and no promise to resolve:
upload:
{ preview: 'blob:http://localhost:3333/e514498c-3031-403c-96ea-349b2bd120d7' }
I'm not sure if I did something wrong? But before I wrote my code depending on a promise being sent to the server. So that's breaking.
from apollo-upload-client.
@flemwad, I assume that you have other problem here, but according to Apollo-link docs you can compose the links as follows:
let link = ApolloLink.from([errorLink, middlewareLink, apolloUploadLink]);
The above is working for me in my project without any problem with apolloUploadLink.
from apollo-upload-client.
@flemwad Please how did you resolve your issue? If you don't mind, can you look at this #64
Currently, I can't even do a post to my server.
from apollo-upload-client.
yes @flemwad I'm getting the same thing. please let us know how you fixed it.
from apollo-upload-client.
I have a requestLink
which routes requests depending on if they are subscriptions or queries, which is a terminating link. That means that I have to choose between using uploadLink and requestLink? Is it not possible to use this package with another terminating link?
from apollo-upload-client.
@bennypowers you can't have 2 terminating links, because, well, they are terminating. The last one will never happen! You can use the Apollo link .split()
method to create a fork on some sort of logic to choose which link to terminate with.
from apollo-upload-client.
I think it would be worthwhile to mention in the README that you can use .split()
in combination with upload-client, to keep batch working for your regular queries, I think that's what the major usecase people are looking for, not the batching of the uploads themselves.
from apollo-upload-client.
I have this issue currently and tried to solve it by using @bennypowers 's method. Since my mutations are sometimes objects, i've used lodash's isPlainObject method to determine the terminal link.
const requestLink = split(
({ query }) => {
const { kind, operation }: any = getMainDefinition(query)
console.log('requestLink', { query, kind, operation })
return kind === 'OperationDefinition' && operation === 'subscription'
},
wsLink,
httpLink
)
const uploadLink = createUploadLink({ uri: BACKEND_GQL })
const isFile = (value: any) => {
if (isPlainObject(value)) return Object.values(value).map(isFile).includes(true)
const isfile = typeof File !== 'undefined' && value instanceof File
const isblob = typeof Blob !== 'undefined' && value instanceof Blob
return isfile || isblob
}
const isUpload = ({ variables }) => Object.values(variables).some(isFile)
const terminalLink = split(isUpload, uploadLink, requestLink)
const link = ApolloLink.from([
authLink,
errorLink,
terminalLink
])
export const client = new ApolloClient({
link,
cache
})
The topic was closed and a little bid old. Therefore I'd like to ask if there is any update to this or any other solution, or more easy way? Because for each request I have make this decision, and 99% of the operations are not related to upload.
from apollo-upload-client.
@acomito, I got the same issue, but the solution was on README in installation
section.
Quote:
Apollo Client can only have 1 terminating Apollo Link that sends the GraphQL requests; if one such as HttpLink is already setup, remove it.
It seems to better read the docs first for all of us 😂
from apollo-upload-client.
Related Issues (20)
- Module not found - after updating to 18.0.1 HOT 2
- Problem with Typescript HOT 2
- Document required TypeScript libs HOT 1
- How do you use ReactNativeFile in the latest version HOT 3
- Error with Vite HOT 1
- Failed to resolve entry for package "apollo-upload-client". HOT 2
- Support for @defer directive?
- Version 18 doesn't work with React Native HOT 2
- Module not found HOT 2
- Broken compatibility with HotChocolate 13.2 -> HOT 1
- Why js instead of ts? HOT 3
- Version 18 incompatible with Next.js HOT 3
- Support with @habx/apollo-multi-endpoint-link HOT 2
- Query on Compatibility with @apollo/client 3.9.0 and apollo-upload-client HOT 1
- Pending requests issue HOT 2
- importing the library in react js project HOT 1
- "Reached maximum amount of queued data" in Safari HOT 2
- Must provide query string HOT 3
- Can this lib provider `typings` HOT 4
- ReactNativeFile HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from apollo-upload-client.