How to pass sessionStorage via headers using async await with graphql mutations - async-await

I need to pass the sessionStorage dynamically through apollo client via graphql Mutations
but we use async/await to use graphql mutations, can anyone help me?

you can take sessionStorage and assign it to a variable then use Mutations to call the API with the variables passed in
Ex:
const [sendEmail] = useMutation(SEND_EMAIL);
const sendMail = await sendEmail({ variables: { to, subject, body } });
don't forget to import :
import { useMutation } from "#apollo/client";

Related

Getting NextAuth.js user session in Apollo Server context

My web app is using:
NextJS
NextAuth.js
Apollo Server
I have a NextAuth set up in my app, and I am able to log in just fine.
The problem is coming from trying to get access to the user's session in the Apollo context. I want to pass my user's session into every resolver. Here's my current code:
import { ApolloServer, AuthenticationError } from "apollo-server-micro";
import schema from "./schema";
import mongoose from "mongoose";
import dataloaders from "./dataloaders";
import { getSession } from "next-auth/client";
let db;
const apolloServer = new ApolloServer({
schema,
context: async ({ req }) => {
/*
...
database connection setup
...
*/
// get user's session
const userSession = await getSession({ req });
console.log("USER SESSION", userSession); // <-- userSession is ALWAYS null
if (!userSession) {
throw new AuthenticationError("User is not logged in.");
}
return { db, dataloaders, userSession };
},
});
export const config = {
api: {
bodyParser: false,
},
};
export default apolloServer.createHandler({ path: "/api/graphql" });
The problem is, the session (userSession) is always null, even if I am logged in (and can get a session just fine from a proper NextJS API route). My guess is that because the NextAuth function used to get the session, getSession({ req }) is being passed req--which is provided from Apollo Server Micro, and not from NextJS (which NextAuth is expecting). I've done a lot of searching and can't find anyone who's had this same problem. Any help is much appreciated!
I had exactly this issue and I found it was because of the Apollo GraphQL playground.
The playground does not send credentials without "request.credentials": "include".
My NextAuth / GraphQL API looks like this:
import { ApolloServer } from "apollo-server-micro";
import { getSession } from "next-auth/client";
import { typeDefs, resolvers } "./defined-elsewhere"
const apolloServer = new ApolloServer({
typeDefs,
resolvers,
context: async ({ req }) => {
const session = await getSession({ req });
return { session };
},
playground: {
settings: {
"editor.theme": "light",
"request.credentials": "include",
},
},
});
Hope this works for you!
I just ran into something similar. I'm not 100% sure because it's hard to know the exact details since your example code above doesn't show how you're interacting with apollo from the client before the session is coming through as null. I believe however that you're probably making an API call from inside the getStaticProps which causes static code generation and gets run at build time - ie when no such user context / session could possibly exist.
See https://github.com/nextauthjs/next-auth/issues/383
The getStaticProps method in Next.js is only for build time page generation (e.g. for generating static pages from a headless CMS) and cannot be used for user specific data such as sessions or CSRF Tokens.
Also fwiw I'm not sure why you got downvoted - seems like a legit question to ask imo even if the answer is mostly a standard rtm :). Has happened to me here before too - you win some you lose some :) Cheers

Apollo GraphQL: Call a Mutation from the Server?

I need to call a mutation from a cron job running on the server. I found this SO post, but the accepted answer said there was no way to do it.
Then I found this on GitHub, from 2017:
graphql-server is a network wrapper for graphql core function. if you
don't want to use it over network, you can just run it standalone:
import scheme from './scheme';
const query = `{
me {
name
}
}`;
const result = graphql(scheme, query);
console.log(result);
function documentation can be found here
That looks pretty good! Is that the best practices approach in 2020?
Yes, if you have access to the GraphQLSchema object used by your GraphQL server, then the simplest approach is to just use the graphql function exported by the graphql module. Note that you should await the returned Promise to access the result:
async function run () {
const { data, errors } = await graphql(
schema,
query,
rootValue,
context,
variables
)
}
However, you can also make requests to the server itself over the network -- if the server is on the same host, you'd just use localhost or 127.0.0.1. In that case, you can use axios, request or any other HTTP client library in a Node.js script. You can also just use curl to make the request directly in a bash script or curl command.
I just found out about this approach as well. It's possible to create an Apollo client directly on the server.
export const getApolloServerClient = () =>
new ApolloClient({
ssrMode: true,
cache: new InMemoryCache(),
link: new SchemaLink({ schema }),
});

Nuxt Apollo with dynamic headers for a session based authentication

Apollo is not storing the header from the query dynamically.
pages/index.vue
methods: {
fetchCars() {
const token = Cookies.get('XSRF-TOKEN')
console.log(token) // 🟢 Token is shown in console
this.$apollo.query({
query: gql`
query {
cars {
uuid
name
}
}
`,
headers: {
'X-XSRF-TOKEN': token, // â­• Fetch without header
},
})
},
},
Is there a way to set the header value new for every Apollo request?
I have a separate Frontend and Backend. For the Frontend I am using Nuxt.js with Apollo. I want to have a session based communication with my server. For this reason I need to send the CSRF-Token with every Request.
Now the problem: On the first load of the page there is no Cookie set on the browser. I do a GET-Request on every initialization of my Nuxt application.
plugins/csrf.js
fetch('http://127.0.0.1:8000/api/csrf-cookie', {
credentials: 'include',
})
Now I have a valid Cookie set on my side and want to communicate with the GraphQL Server but my header is not set dynamically in the query. Does anyone know how I can solve this?
My Laravel Backend is throwing now a 419 Token Mismatch Exception because I did not send a CSRF-Token with my request.
Link to the repository: https://github.com/SuddenlyRust/session-based-auth
[SOLVED] Working solution: https://github.com/SuddenlyRust/session-based-auth/commit/de8fb9c18b00e58655f154f8d0c95a677d9b685b Thanks to the help of kofh in the Nuxt Apollo discord channel 🎉
In order to accomplish this, we need to access the code that gets run every time a fetch happens. This code lives inside your Apollo client's HttpLink. While the #nuxtjs/apollo module gives us many options, we can't quite configure this at such a high level.
Step 1: Creating a client plugin
As noted in the setup section of the Apollo module's docs, we can supply a path to a plugin that will define a clientConfig:
// nuxt.config.js
{
apollo: {
clientConfigs: {
default: '~/plugins/apollo-client.js'
}
}
}
This plugin should export a function which receives the nuxt context. It should return the configuration to be passed to the vue-cli-plugin-apollo's createApolloClient utility. You don't need to worry about that file, but it is how #nuxtjs/apollo creates the client internally.
Step 2: Creating the custom httpLink
In createApolloClient's options, we see we can disable defaultHttpLink and instead supply our own link. link needs to be the output of Apollo's official createHttpLink utility, docs for which can be found here. The option we're most interested in is the fetch option which as the docs state, is
a fetch compatible API for making a request
This boils down to meaning a function that takes uri and options parameters and returns a Promise that represents the network interaction.
Step 3: Creating the custom fetch method
As stated above, we need a function that takes uri and options and returns a promise. This function will be a simple passthrough to the standard fetch method (you may need to add isomorphic-fetch to your dependencies and import it here depending on your setup).
We'll extract your cookie the same as you did in your question, and then set it as a header. The fetch function should look like this:
(uri, options) => {
const token = Cookies.get('XSRF-TOKEN')
options.headers['X-XSRF-TOKEN'] = token
return fetch(uri, options)
}
Putting it all together
Ultimately, your ~/plugins/apollo-client.js file should look something like this:
import { createHttpLink } from 'apollo-link-http'
import fetch from 'isomorphic-fetch'
export default function(context) {
return {
defaultHttpLink: false,
link: createHttpLink({
uri: '/graphql',
credentials: 'include',
fetch: (uri, options) => {
const token = Cookies.get('XSRF-TOKEN')
options.headers['X-XSRF-TOKEN'] = token
return fetch(uri, options)
}
})
}
}

Passing query parameters to React Apollo POST requests

Is there a way to configure React Apollo to pass default query string parameters to each query / mutation ?
For now, all my requests have this format :
POST https://domain:8000/graphql;
I would like to have something like :
POST https://domain:8000/graphql?query=queryName
This would help for quick debugging purposes in the Chrome DevTools panel.
You can implement a custom fetch that apollo's http-link will then use.
When instantiating apollo client, do the following:
const customFetch = (uri, options) => {
const { operationName } = JSON.parse(options.body);
return fetch(`${uri}/graph/graphql?opname=${operationName}`, options);
};
const link = createHttpLink({ fetch: customFetch });

How to call an apollo client query from a redux action

If I'm using redux and the apollo client in my app, what's the best way to trigger a query from an action outside of a component.
For example, if I have a standard app, with redux and apollo client configured, how should I trigger a "refresh" list. I can trigger a function on the component itself which has the gql, but how would I do it from an action which would be more in line with flux.
import React, { Component, PropTypes } from 'react';
import { graphql } from 'react-apollo';
import gql from 'graphql-tag';
import { connect } from 'react-redux';
import { refreshProfile } from './actions';
class Profile extends Component { ... }
Profile.propTypes = {
data: PropTypes.shape({
loading: PropTypes.bool.isRequired,
user: PropTypes.object,
}).isRequired,
};
const UserQuery = gql`
query getUser {
user {
id
name
}
}
`;
const ProfileWithData = graphql(UserQuery)(Profile);
const ProfileWithDataAndState = connect(
(state) => ({ user: state.user })),
)(ProfileWithData);
And, say I want to trigger an action to refresh that user data? Since the logic is in the component itself, I'm not sure how I would trigger that gql query from the action itself.
I would need to use the ApolloClient in my actions.js. e.g.
import ApolloClient, { createNetworkInterface } from 'apollo-client';
const networkInterface = createNetworkInterface({
uri: config.graphCoolUri,
});
const client = new ApolloClient({
networkInterface,
dataIdFromObject: r => r.id,
});
const { data } = await client.query({
query: UserQuery
});
I see your needs, as I was just in your place couple of days ago.
The sad news is: if you want to use actions with graphQL, then you shouldn't be using apollo, just use graphQL directly. This is a very good article to walk you through - getting started with Redux and GraphQL. Why? Because Apollo uses a function called qraphql(query) which calls its own action.
How both Redux and Apollo work in a very simplistic way.
Redux: (User dispatches an action) ActionCreator --> Action --> Middleware --> reducer --> store --> bind data to user props. And we control each state manually.
Apollo: (User passes the query/mutation to graphql(query)) all hidden (action --> store) then binds data to user props.
You can say that Apollo replaces Redux if you are using graphql, because it has a better integration with react and graphQL.
In the meantime, as Apollo is still developing, you might need redux for redux-form and so on. If you are used to some redux libraries, which you might consider to continue using redux besides Apollo, you can still bind their stores and add costumed middleware that probably apply to both, but you probably won't be fetching data using Redux actions through Apollo.
I know it feels like you are loosing redux, but you are getting all advantages with more async requests and caching taking care of with Apollo.
and if you need a place to start react-redux-apollo.

Resources