I am trying to use ApolloClient with a local IP as uri, but when I set it, it automatically changes it from http to https and, of course, it doesn't work locally.
I've tried 2 way of configuring Gatsby to use ApolloClient.
The first way is in gatsby-browser like so:
import React from 'react';
import 'core-js/modules/es6.set';
import 'core-js/modules/es6.map';
import 'raf/polyfill';
import Apollo from 'providers/Apollo';
export const wrapRootElement = ({ element }) => <Apollo>{element}</Apollo>;
And, the ApolloClient config:
import React from 'react';
import { ApolloProvider, ApolloClient, InMemoryCache } from '#apollo/client';
export default ({ children }) => {
const client = new ApolloClient({
uri: 'http://192.162.1.112:4000/graphql',
cache: new InMemoryCache(),
request: async operation => {
...
},
fetchOptions: {
mode: 'no-cors',
},
});
return <ApolloProvider client={client}>{children}</ApolloProvider>;
};
The second way is using the plugin gatsby-plugin-apollo in gatsby-config like so
{
resolve: 'gatsby-plugin-apollo',
options: {
uri: 'http://192.168.1.112:4000/graphql'
}
}
Notice both uri have http.
Also, it is either one or the other, not both. (Although I've tried with both and it the same result).
This is what I get trying to do a gql query in the network tab:
It is enforcing https and I can't test locally. How do can I make request to http using Gatsby and ApolloClient?
By the way, I set ApolloClient just like this in another project that doesn't use Gatsby (obviously not using the gatsby plugin either) and it works as expected.
There are a few confusing things in the way you are using apollo client.
There is no point in explaining something that has already been done.
You might want to check out this talk and demo by Jason Lengstorf. Here he explained how one can get started with gatsby + apollo client.
Youtube
gatsby-with-apollo
Related
I have a React/Next.js app which is using GraphQL and Apollo to connect and interact with a headless API. I am using Strapi as my headless API/CMS which is working great, except for one issue. I am trying to upload a file from my React app to a content type in my Strapi CMS using a GraphQL mutation and it keeps failing on the upload part.
When I upload a file using Altair(my playground environment) to Strapi with the exact same mutation everything works fine, but once I try to run the same mutation from my React app I get this error:
Variable \"$file\" got invalid value {}; Upload value invalid.. Everything I see online brings up using apollo-upload-client and adding something like link: createUploadLink({ uri: "http://localhost:4300/graphql" }), to my Apollo client initiation. I have tried that but whenever I use it, it breaks my app and I get this GraphQL error Error: Cannot return null for non-nullable field UsersPermissionsMe.username..
It seems like the only answer I can find is using apollo-upload-client but when I use it, it seems to break my app. I don't know if I need to use it differently maybe because I am using Strapi, or Next, or #apollo/client. I am a little lost on this one.
This is how I initiate my Apollo client and when everything works except uploading a file.
import { ApolloClient, InMemoryCache, NormalizedCacheObject } from "#apollo/client";
import { parseCookies } from "nookies";
import { useMemo } from 'react'
import getConfig from "next/config";
const { publicRuntimeConfig } = getConfig();
let apolloClient: ApolloClient<NormalizedCacheObject>;
function createApolloClient(ctx) {
return new ApolloClient({
ssrMode: typeof window === "undefined",
uri: publicRuntimeConfig.PUBLIC_GRAPHQL_API_URL,
cache: new InMemoryCache(),
headers: {
Authorization: `Bearer ${ctx ? parseCookies(ctx).jwt : parseCookies().jwt}`,
},
});
}
My app runs perfect with this code except for the fact that I get "message":"Variable \"$file\" got invalid value {}; Upload value invalid.", whenever I try to upload a file. So when I try to use apollo-upload-client to fix that like this:
import { ApolloClient, InMemoryCache, NormalizedCacheObject } from "#apollo/client";
import { createUploadLink } from 'apollo-upload-client';
import { parseCookies } from "nookies";
import { useMemo } from 'react'
import getConfig from "next/config";
const { publicRuntimeConfig } = getConfig();
let apolloClient: ApolloClient<NormalizedCacheObject>;
function createApolloClient(ctx) {
return new ApolloClient({
ssrMode: typeof window === "undefined",
// uri: publicRuntimeConfig.PUBLIC_GRAPHQL_API_URL,
link: createUploadLink({ uri: publicRuntimeConfig.PUBLIC_GRAPHQL_API_URL }),
cache: new InMemoryCache(),
headers: {
Authorization: `Bearer ${ctx ? parseCookies(ctx).jwt : parseCookies().jwt}`,
},
});
}
I get this error: Error: Cannot return null for non-nullable field UsersPermissionsMe.username..
I am still new to GraphQL and Strapi so maybe I am missing something obvious. Everything works except uploads. I can upload from my playground, just not from my app, that is where I am at.
So after two days of this issue, I figured it out after 10 minutes of reading the apollo-upload-client documentation. So much shame. All I needed to do was move my header request from the ApolloClient options to the createUploadLink options. Final fix was
function createApolloClient(ctx) {
return new ApolloClient({
ssrMode: typeof window === "undefined",
link: createUploadLink({
uri: publicRuntimeConfig.PUBLIC_GRAPHQL_API_URL,
headers: {
Authorization: `Bearer ${ctx ? parseCookies(ctx).jwt : parseCookies().jwt}`,
},
}),
cache: new InMemoryCache(),
});
}
I'm trying to deploy my application to a production environment, but having some trouble wiring it all together.
I've got a create-react-app for my frontend, which is served up by a simple express/serve server. On the backend, I've got NGINX proxying successfully to my API server, which is using Apollo to serve my data. The API is running on port 4000.
The Apollo-Server is as-follows, and works fine:
import { resolve } from "path";
import dotenv from "dotenv";
const envi = process.env.NODE_ENV;
dotenv.config({ path: resolve(__dirname, `../.${envi}.env`) });
import "reflect-metadata";
import { connect } from "./mongodb/connect";
import { buildSchema } from "type-graphql";
import { ApolloServer } from "apollo-server";
import { SenateCommitteeResolver, HouseCommitteeResolver } from "./resolvers";
import { populateDatabase } from "./util";
(async () => {
// Connect to MongoDB
await connect();
console.log(`š Databases connected`);
const schema = await buildSchema({
resolvers: [HouseCommitteeResolver, SenateCommitteeResolver],
emitSchemaFile: resolve(__dirname, "schema.gql"),
});
// If development, set database docs
envi === "development" && (await populateDatabase());
// Launch the server!
const server = new ApolloServer({
schema,
playground: true,
});
// Server listens at URL
const { url } = await server.listen(4000);
console.log(`š Server ready, at ${url}`);
})();
I'm trying to connect my express server to the Apollo Server, but that's where I'm running into problems. The application is supposed to connect using Apollo's Client and HTTP Link, because I'm using Apollo Client on the frontend too:
import React, { useEffect } from "react";
import { AppRouter } from "./routers";
import ReactGA from "react-ga";
import { ApolloProvider } from "#apollo/client";
import client from "./graphql/client";
import "./styles/index.scss";
function App(): React.ReactElement {
return (
<ApolloProvider client={client}>
<AppRouter />
</ApolloProvider>
);
}
export default App;
And here's the client file:
import { ApolloClient, InMemoryCache, createHttpLink } from "#apollo/client";
const httpLink = createHttpLink({ uri: process.env.REACT_APP_API as string });
const cache = new InMemoryCache();
const client = new ApolloClient({
link: httpLink,
cache,
connectToDevTools: true,
});
export default client;
However, when the user navigates to the site and the site itself tries to make a request to my backend, I'm getting a CORS error:
Access to fetch at 'https://www.cloture.app/' from origin 'https://cloture.app' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
What's going wrong? How can I connect Apollo's client with my Apollo Server on the backend?
Adding it here, because the suggestion requires some code.
Try adding :
const server = new ApolloServer({
schema,
playground: true,
cors: {
origin: "*" // it will allow any client to access the server, but you can add specific url also
}
});
I'm building a project using React, Apollo and Next.js. I'm trying to update react-apollo to 3.1.3 and I'm now getting the following error when viewing the site.
Invariant Violation: Could not find "client" in the context or passed in as an option. Wrap the root component in an , or pass an ApolloClient instance in via options.
If I downgrade the react-apollo package to 2.5.8 it works without issue so I'm thinking something has changed between 2.5 and 3.x but can't find anything in the react-apollo or next-with-apollo documentation to indicate what that might be. Any assistance would be greatly appreciated.
withData.js
import withApollo from 'next-with-apollo';
import ApolloClient from 'apollo-boost';
import { endpoint } from '../config';
function createClient({ headers }) {
return new ApolloClient({
uri: endpoint,
request: operation => {
operation.setContext({
fetchOptions: {
credentials: 'include'
},
headers
});
},
// local data
clientState: {
resolvers: {
Mutation: {}
},
defaults: {}
}
});
}
export default withApollo(createClient);
_app.js
import App from 'next/app';
import { ApolloProvider } from 'react-apollo';
import Page from '../components/Page';
import { Overlay } from '../components/styles/Overlay';
import withData from '../lib/withData';
class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}
// this exposes the query to the user
pageProps.query = ctx.query;
return { pageProps };
}
render() {
const { Component, apollo, pageProps } = this.props;
return (
<ApolloProvider client={apollo}>
<Overlay id="page-overlay" />
<Page>
<Component {...pageProps} />
</Page>
</ApolloProvider>
);
}
}
export default withData(MyApp);
In my case, I found that I had react-apollo#3.0.1 installed as well as #apollo/react-hooks#3.0.0. Removing #apollo/react-hooks and just relying on react-apollo fixed the invariant issue for me. Make sure that you aren't using any mismatched versions in your lock file or package.json
This is what someone said in a GitHub issue thread, which, was the case for me too. Make sure you try it!
I've had a mixture of solutions, i think it does boil down to how you initially go about setting up all the related packages.
"Some packages don't work well with others when it comes to connecting the client to Reacts Context.Provider"
I've had two go two fixes that seem to work well (With new projects and updating old):
1: Uninstall #apollo/react-hooks
Then:
import { ApolloProvider } from "#apollo/client";
instead of:
import { ApolloProvider } from "react-apollo";
(This allowed me to keep the "#apollo/react-hooks" package without conflicts)
3: Double-check that the server that is serving HttpLink client URI is up and running for the client to connect (This give a different error then the one were talking about but is still good to know in this situation)
Conclusion: It can be a slight bit of trial and error, but try to use the matching/pairing packages
I uninstalled 'react-apollo', used '#apollo/client' instead, it solved the issue for me.
import gql from 'graphql-tag';
import {graphql} from '#apollo/react-hoc';
import { ApolloClient, InMemoryCache } from '#apollo/client';
import { ApolloProvider } from '#apollo/react-hooks';
These imports worked for me perfectly. I had a great time debugging and finding different import libraries but finally after 3 hours this was the solution for using graphql and appolo.
I found this to be the solution as well, though now I'm only using #apollo/client and apollo-link since they are the latest version.
import {ApolloProvider} from 'apollo/client' instead 'react-apollo'or '#apollo/react-hooks'
I have a React app which is using Apollo Client. I'm using apollo-link-state and apollo-cache-persist and need to reset my store to its default values when client.resetStore() is called in my app.
The docs say that when creating a client you should call client.onResetStore(stateLink.writeDefaults) and this will do the job but writeDefaults is exposed by Apollo Link State which i don't have direct access to as Iām using Apollo Boost.
Here is my Apollo Client code:
import ApolloClient from 'apollo-boost';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { persistCache } from 'apollo-cache-persist';
import { defaults, resolvers } from "./store";
const cache = new InMemoryCache();
persistCache({
storage: window.localStorage,
debug: process.env.NODE_ENV !== 'production',
cache
});
const client = new ApolloClient({
uri: process.env.NODE_ENV === 'production' ? 'https://five-yards-api.herokuapp.com/graphql' : 'http://localhost:7777/graphql',
credentials: 'include',
clientState: {
defaults,
resolvers
},
cache
});
// TODO: Doesn't work as expected
client.onResetStore(client.writeDefaults);
export default client;
I use Apollo Client 2.x, and Apollo Boost may be the same.
I had the same problem with Apollo Client 2.x, and below was the solution for me.
In the root file where you configure your Apollo (e.g. App.js):
cache.writeData({data : defaultData }); # I assume you already have this to initialise your default data.
# Then, you just add below underneath.
client.onResetStore(() => {
cache.writeData({data : defaultData });
});
const App = () => (...
AFAIK the only way to this is to migrate from Apollo Boost which configures a lot of things under the hood for you and set up Apollo Client manually. After migrating I was able to call onResetStore() as per the docs and everything is working :)
Apollo Boost migration:
https://www.apollographql.com/docs/react/advanced/boost-migration.html
Does axios-mock-adapter only work on requests made with axios?
I have written a component that POSTs to an API (using vanilla XHR, not axios). I'm testing it in Storybook and want to intercept those POST requests since the endpoint doesn't exist yet:
import React from "react"
import { storiesOf } from "#kadira/storybook"
import MyComponent from "./MyComponent"
import axios from "axios"
import MockAdapter from "axios-mock-adapter"
var mock = new MockAdapter(axios)
storiesOf("My Component", module).addWithInfo(
"Simulator",
() => {
mock.onPost().reply(500)
return <MyComponent />
},
{}
)
My component still is trying to hit the API endpoint and I am getting a 404 response - not the expected 500 response.
Does axios-mock-adapter only work on requests made with axios?
Does the mock call have to be inside MyComponent?
Thanks.
xhr-mock should work for local testing where you probably don't want to make requests across the internet.
Outside of testing, if you are waiting on the real endpoints to be built you could use Mock/it (https://mockit.io) in development. You can claim your own dedicated subdomain and swap it out later for the real one. Disclaimer: this is a side project I recently released and would love any feedback on it!
You can use xhr-mock instead of axios-mock-adapter.
Utility for mocking XMLHttpRequest.
Great for testing. Great for prototyping while your backend is still being built.
Works in NodeJS and in the browser. Is compatible with Axios, jQuery, Superagent >and probably every other library built on XMLHttpRequest
import mock from 'xhr-mock';
storiesOf("My Component", module).addWithInfo("Simulator",
() => {
mock.post('', {
status: 500,
body: '{}'
});
return <MyComponent />
},
{}
)
Additionaly you need to add jquery script in preview-head.html file in storybook
1) https://www.npmjs.com/package/xhr-mock
I've started using json-server to intercept API calls. You have to start it in one tab, and start storybook in another, but it is pretty cool.
You can use fetchMock npm module. All XHR call will be mocked with data you provide.
Storybook configuration:
import React from 'react';
import Messages from '../components/messagesList';
import fetchMock from "fetch-mock";
import MESSAGES from './data/messages';
fetchMock.get('/messages', MESSAGES);
export default {
title: 'Messages',
component: Messages
};
export const ToStorybook = () => <Messages />;
ToStorybook.story = {
name: 'Messages list',
};
The complete tutorial how to do it is on YouTube
You can use storybook-addon-mock to mock any fetch or XHR request using the addon panel.
This package supports
Modify response from the panel and test on the fly.
Modify the status code to verify the error response.
Add a delay time to experience the loading state.