Wrapping a RESTapi with GraphQL using Apollo React - javascript

I need to do a project (currency exchange app) using Apollo client and React. I need to wrap an existing REST api (fixer.io) with graphql. So far no luck finding a solution online. Tried several tutorials but they don't seem to work. Anyone have experience with this?
Thanks.

I assume you use Apollo client 2.0 and want everything to be client side.
First you need an apollo bridge link. It's used "When you don't have GraphQL server (yet) and want to use GraphQL on the client". Its source code is quite short, so you can inline it:
/*
Copyright (c) 2017 David Cizek
https://github.com/dacz/apollo-bridge-link
*/
import { GraphQLSchema, graphql, print } from 'graphql';
import { addMockFunctionsToSchema, makeExecutableSchema } from 'graphql-tools';
import { ApolloLink } from 'apollo-link';
import Observable from 'zen-observable';
export const createBridgeLink = ({ schema, resolvers, mock, context = {} }) => {
let executableSchema;
if (typeof schema === 'string') {
executableSchema = makeExecutableSchema({ typeDefs: schema, resolvers });
} else if (schema.kind === 'Document') {
executableSchema = makeExecutableSchema({
typeDefs: print(schema),
resolvers,
});
} else if (schema instanceof GraphQLSchema) {
executableSchema = schema;
} else {
throw new Error('schema should be plain text, parsed schema or executable schema.');
}
if (mock)
{addMockFunctionsToSchema({
schema: executableSchema,
preserveResolvers: true,
});}
return new ApolloLink(
operation =>
new Observable(observer => {
const { headers, credentials } = operation.getContext();
const ctx = {
...context,
headers,
credentials,
};
graphql(executableSchema, print(operation.query), undefined, ctx, operation.variables, operation.operationName)
.then(data => {
observer.next(data);
observer.complete();
})
.catch(err => {
/* istanbul ignore next */
observer.error(err);
});
}),
);
};
export class BridgeLink extends ApolloLink {
requester;
constructor(opts) {
super();
this.requester = createBridgeLink(opts).request;
}
request(op) {
return this.requester(op);
}
}
Next you create schema and resolvers:
// schema.js
export default `
type Rate {
date: Date!
rate: Float!
}
type Query {
latestRate(from: String!, to: String!): Rate
}
schema {
query: Query
}
`;
// resolvers.js
const resolvers = {
Query: {
latestRate(obj, args, context, info) {
return fetch(`https://api.fixer.io/latest?base=${args.from}`).then(res => res.json())
.then(res => { date: res.date, rate: res.rates[args.to] })
}
}
}
export default resolvers;
Finally, you create an apollo client factory:
// clientFactory.js
import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { BridgeLink } from './apollo-bridge-link';
import schema from './schema';
import resolvers from './resolvers';
export default () => {
const mock = false;
const context = {};
const client = new ApolloClient({
link: new BridgeLink({ schema, resolvers, mock, context }),
cache: new InMemoryCache(),
});
return client;
};
Here's how you use it:
import gql from 'graphql-tag';
import clientFactory from './clientFactory'
const client = clientFactory();
client.query(gql`query {
latestRate(from: "USD", to: "EUR") { date, rate }
}`).then(console.log)
If you want to use it in React:
import { ApolloProvider } from 'react-apollo';
const client = clientFactory();
const App = ({ data: { latestRate, refetch } }) => {
return <div>
<span>Today:</span><span>{latestRate.date}</span>
<span>1 USD equals:</span><span>{latestRate.rate} EUR</span>
<button onClick={() => refetch()}>
Refresh
</button>
</div>
}
const AppWithQuery = graphql(gql`
query {
latestRate(from: "USD", to: "EUR") { date, rate }
}
`)(App);
ReactDOM.render(
<ApolloProvider client={client}>
<AppWithQuery/>
</ApolloProvider>,
document.getElementById('root'),
);

With the Graphcool Framework, you can define resolver functions, which allow you to easily wrap any REST API. You can define a function and connect it to a specific mutation or query in your GraphQL Schema.
I prepared a demo, wrapping the fixer API.
Try to run this query to get the exchange rates with USD as base, for example:
query {
fixer(
base: "USD"
) {
base
date
eur
usd
rub
}
}
You can build this demo yourself like this:
git clone git#github.com:graphcool/templates.git
cd templates/curated/misc/fixer-wrapper
npm install -g graphcool#next
graphcool init
graphcool deploy
graphcool playground
Please feel free to share any improvement you might have in mind, the example is open source. You can read more about resolvers here.

Related

Create T3 App Redirect inside a TRPC middleware if user is not signed

How can I trigger a redirect on the server side if a signed in user has not completed their profile page
const enforceUserIsAuthed = t.middleware(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
// redirect to profile page if user has not completed profile
return next({
ctx: {
// infers the `session` as non-nullable
session: { ...ctx.session, user: ctx.session.user },
},
});
});
This is not currently possible in the way you are describing to the best of my knowledge.
Here are some alternatives that might be helpful:
In getServerSideProps
this only works if you want to redirect before the initial page load. You could also create a wrapper around gSSP to make this more DRY if you're going to use it on a lot of pages.
import { type GetServerSidePropsContext } from "next";
import { getServerAuthSession } from "../server/auth";
export async function getServerSideProps(ctx: GetServerSidePropsContext) {
const session = await getServerAuthSession(ctx);
if (!session) {
return {
redirect: {
destination: "/",
permanent: false,
},
};
}
return {
props: {},
};
}
export default function AuthedPage() {
return <div>Authed</div>;
}
As part of a query or mutation clientside
this is useful for a query or mutation that is only fired after the page has loaded. Again this is a very simple example and could be DRYed, probably the easiest way would be to extract into a custom hook.
import { useRouter } from "next/router";
import { api } from "../utils/api";
export default function AuthedPage() {
const router = useRouter();
// `authedHello` is the example Create T3 App "hello" procedure
// but as a protectedProcedure, ie throws "UNAUTHORIZED" if no session.
// Replace this with a middleware that throws on whatever condition you need it to.
const authedHello = api.example.protectedHello.useQuery(
{ text: "world" },
{
retry: (_count, err) => {
// `onError` only runs once React Query stops retrying
if (err.data?.code === "UNAUTHORIZED") {
return false;
}
return true;
},
onError: (err) => {
if (err.data?.code === "UNAUTHORIZED") {
void router.push("/");
}
},
}
);
return (
<div>
<h1>Authed Page</h1>
<p>{authedHello.data?.greeting}</p>
</div>
);
}
Using Next.js middleware
This is easy to apply to a bunch of routes using the matcher, but it falls a bit outside of T3 conventions.
// pages/middleware.ts
import { NextResponse } from "next/server";
import { getServerSession } from "next-auth";
import { authOptions } from "../server/auth";
import type { NextApiRequest, NextApiResponse } from "next";
export async function middleware(req: NextApiRequest, res: NextApiResponse) {
const session = await getServerSession(req, res, authOptions);
if (!session?.user) {
return NextResponse.redirect(new URL("/", req.url));
}
}
export const config = {
matcher: ["/protectedPage", "/anotherProtectedPage"],
};
Using require in next-auth's useSession
this is useful if you want to guard a page but can't use getServerSideProps. It doesn't quite solve your specific problem, but might be useful to other people who find this. See: https://next-auth.js.org/getting-started/client#require-session

Using react hooks inside NextJS /pages/api [duplicate]

I need a graphql client lib to run on node.js for some testing and some data mashup - not in a production capacity. I'm using apollo everywhere else (react-apollo, apollo's graphql-server-express). My needs are pretty simple.
Is apollo-client a viable choice? I can find no examples or docs on using it on node - if you're aware of any, please share.
Or maybe I should/can use the reference graphql client on node?
Apollo Client should work just fine on Node. You only have to install cross-fetch.
Here is a complete TypeScript implementation of Apollo Client working on Node.js.
import { ApolloClient, gql, HttpLink, InMemoryCache } from "#apollo/client";
import { InsertJob } from "./graphql-types";
import fetch from "cross-fetch";
const client = new ApolloClient({
link: new HttpLink({ uri: process.env.PRODUCTION_GRAPHQL_URL, fetch }),
cache: new InMemoryCache(),
});
client.mutate<InsertJob.AddCompany, InsertJob.Variables>({
mutation: gql`mutation insertJob($companyName: String!) {
addCompany(input: { displayName: $companyName } ) {
id
}
}`,
variables: {
companyName: "aaa"
}
})
.then(result => console.log(result));
Newer Apollo version provide a simpler approach to perform this, as described in Apollo docs, check the section "Standalone". Basically one can simply use ApolloLink in order to perform a query or mutation.
Below is copy of the example code from the docs as of writing this, with node-fetch usage as config to createHttpLink. Check the docs for more details on how to use these tools.
import { execute, makePromise } from 'apollo-link';
import { createHttpLink } from 'apollo-link-http';
import gql from 'graphql-tag';
import fetch from 'node-fetch';
const uri = 'http://localhost:4000/graphql';
const link = createHttpLink({ uri, fetch });
const operation = {
query: gql`query { hello }`,
variables: {} //optional
operationName: {} //optional
context: {} //optional
extensions: {} //optional
};
// execute returns an Observable so it can be subscribed to
execute(link, operation).subscribe({
next: data => console.log(`received data: ${JSON.stringify(data, null, 2)}`),
error: error => console.log(`received error ${error}`),
complete: () => console.log(`complete`),
})
// For single execution operations, a Promise can be used
makePromise(execute(link, operation))
.then(data => console.log(`received data ${JSON.stringify(data, null, 2)}`))
.catch(error => console.log(`received error ${error}`))
If someone is looking for a JavaScript version:
require('dotenv').config();
const gql = require('graphql-tag');
const ApolloClient = require('apollo-boost').ApolloClient;
const fetch = require('cross-fetch/polyfill').fetch;
const createHttpLink = require('apollo-link-http').createHttpLink;
const InMemoryCache = require('apollo-cache-inmemory').InMemoryCache;
const client = new ApolloClient({
link: createHttpLink({
uri: process.env.API,
fetch: fetch
}),
cache: new InMemoryCache()
});
client.mutate({
mutation: gql`
mutation popJob {
popJob {
id
type
param
status
progress
creation_date
expiration_date
}
}
`,
}).then(job => {
console.log(job);
})
You can make apollo-client work, but it's not the best option for this use case.
Try graphql-request instead.
Minimal GraphQL client supporting Node and browsers for scripts or simple apps
Features per npmjs:
Most simple & lightweight GraphQL client
Promise-based API (works with async / await)
Typescript support
Isomorphic (works with Node / browsers)
example:
import { request, gql } from 'graphql-request'
const query = gql`
{
Movie(title: "Inception") {
releaseDate
actors {
name
}
}
}
`
request('https://api.graph.cool/simple/v1/movies', query).then((data) => console.log(data))
I have no affiliation with this package.
Here is simple node js implementation.
'graphiql' client is good enough for development activities.
1. run npm install
2. start server with "node server.js"
3. hit "http://localhost:8080/graphiql" for graphiql client
server.js
var graphql = require ('graphql').graphql
var express = require('express')
var graphQLHTTP = require('express-graphql')
var Schema = require('./schema')
// This is just an internal test
var query = 'query{starwar{name, gender,gender}}'
graphql(Schema, query).then( function(result) {
console.log(JSON.stringify(result,null," "));
});
var app = express()
.use('/', graphQLHTTP({ schema: Schema, pretty: true, graphiql: true }))
.listen(8080, function (err) {
console.log('GraphQL Server is now running on localhost:8080');
});
schema.js
//schema.js
var graphql = require ('graphql');
var http = require('http');
var StarWar = [
{
"name": "default",
"gender": "default",
"mass": "default"
}
];
var TodoType = new graphql.GraphQLObjectType({
name: 'starwar',
fields: function () {
return {
name: {
type: graphql.GraphQLString
},
gender: {
type: graphql.GraphQLString
},
mass: {
type: graphql.GraphQLString
}
}
}
});
var QueryType = new graphql.GraphQLObjectType({
name: 'Query',
fields: function () {
return {
starwar: {
type: new graphql.GraphQLList(TodoType),
resolve: function () {
return new Promise(function (resolve, reject) {
var request = http.get({
hostname: 'swapi.co',
path: '/api/people/1/',
method: 'GET'
}, function(res){
res.setEncoding('utf8');
res.on('data', function(response){
StarWar = [JSON.parse(response)];
resolve(StarWar)
console.log('On response success:' , StarWar);
});
});
request.on('error', function(response){
console.log('On error' , response.message);
});
request.end();
});
}
}
}
}
});
module.exports = new graphql.GraphQLSchema({
query: QueryType
});
In response to #YakirNa 's comment:
I can't speak to the other needs I described, but I have done a fair amount of testing. I ended up doing all of my testing in-process.
Most testing ends up being resolver testing, which I do via a jig that invokes the graphql library's graphql function with a test query and then validates the response.
I also have an (almost) end-to-end test layer that works at the http-handling level of express. It creates a fake HTTP request and verifies the response in-process. This is all within the server process; nothing goes over the wire. I use this lightly, mostly for testing JWT authentication and other request-level behavior that's independent of the graphql request body.
I was running into your same question, because I wanted to create a middleware service to prepare data from graphQL to a final frontend application,
to have :
optimised data representation (and standard output data interface)
faster response time
assuming that graphQL server is provided by an external provider , so no ownership to data model, directly with GQL
So I didn't want to implement GraphQL Apolloclient directly in a frontend framework like React / Angular, Vuejs... but manage the queries via Nodejs at backend of a REST API.
So this is the class wrapper for Apolloclient I was able to assemble (using typescript):
import ApolloClient from "apollo-client";
import { ApolloLink } from 'apollo-link'
import { HttpLink } from 'apollo-link-http'
import { onError } from 'apollo-link-error'
import fetch from 'node-fetch'
import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'
import introspectionQueryResultData from '../../fragmentTypes.json';
import { AppConfig } from 'app-config';
const config: AppConfig = require('../../../appConfig.js');
export class GraphQLQueryClient {
protected apolloClient: any;
constructor(headers: { [name: string]: string }) {
const api: any = {
spaceId: config.app.spaceId,
environmentId: config.app.environmentId,
uri: config.app.uri,
cdnApiPreviewToken: config.cdnApiPreviewToken,
};
// console.log(JSON.stringify(api));
const ACCESS_TOKEN = api.cdnApiPreviewToken;
const uri = api.uri;
console.log(`Apollo client setup to query uri: ${uri}`);
const fragmentMatcher = new IntrospectionFragmentMatcher({
introspectionQueryResultData
});
this.apolloClient = new ApolloClient({
link: ApolloLink.from([
onError(({ graphQLErrors, networkError }:any) => {
if (graphQLErrors) {
graphQLErrors.map((el:any) =>
console.warn(
el.message || el
)
)
graphQLErrors.map(({ message, locations, path }:any) =>
console.warn(
`[GraphQL error - Env ${api.environmentId}]: Message: ${message}, Location: ${JSON.stringify(locations)}, Path: ${path}`
)
)
}
if (networkError) console.log(`[Network error]: ${networkError}`)
}),
new HttpLink({
uri,
credentials: 'same-origin',
headers: {
Authorization: `Bearer ${ACCESS_TOKEN}`
},
fetch
})
]),
cache: new InMemoryCache({ fragmentMatcher }),
// fetchPolicy as network-only avoids using the cache.
defaultOptions: {
watchQuery: {
fetchPolicy: 'network-only',
errorPolicy: 'ignore',
},
query: {
fetchPolicy: 'network-only',
errorPolicy: 'all',
},
}
});
}
}
After this constructor I run queries like :
let response = await this.apolloClient.query({ query: gql`${query}` });
As you might have noticed:
I needed to inject fetch on Httplink
I had to setup Authorization headers to access external provider graphQL endpoint
I used IntrospectionFragmentMatcher in order to use Fragments in my queries, along with building schema type ("fragmentTypes.json" with an init script)
Posting this to just add my experience and maybe more info for the question.
Also looking forward for comments and points of improvement for this wrapper.

info argument is empty in Apollo GraphQL resolver type signature

I'm working on this library https://github.com/ilyaskarim/wertik-js called Wertik JS to make GraphQL + Rest API more easily, In resolvers, when I console log info, it shows undefined. For each module, I have created dynamic resolvers to make things more easy for developers who will use this library.
let object = {
create: async (_:any, args:any, context:any,info: any) => {
console.log(info); // This will be undefined
let v = await validate(validations.create,args.input);
let {success} = v;
if (!success) {
throw new ApolloError("Validation error",statusCodes.BAD_REQUEST.number,{list: v.errors})
}
try {
let createModel = await model.create(args.input);
pubsub.publish(`${camelCase(moduleName)}Created`, { [`${camelCase(moduleName)}Created`]: createModel });
return createModel;
} catch (e) {
return internalServerError(e);
}
},
}
Line: https://github.com/ilyaskarim/wertik-js/blob/ec813f49a14ddd6a04680b261ae4ef2aadc2b1a5/src/framework/dynamic/resolvers.ts#L102
The info is described in Apollo Server Documentation https://www.apollographql.com/docs/apollo-server/essentials/data/#resolver-type-signature, Which says: This argument contains information about the execution state of the query, including the field name, the path to the field from the root, and more. For me, unfortunately, it is getting undefined.
To reproduce the issue:
Download https://github.com/ilyaskarim/wertik-js/tree/development
Yarn install
Go to examples/demo
Run node index.js
Now go to http://localhost:1209/
Enter this mutation for example:
mutation {
createRole(input: {name: "Asd"}) {
name
}
}
This line executes on this mutation https://github.com/ilyaskarim/wertik-js/blob/ec813f49a14ddd6a04680b261ae4ef2aadc2b1a5/src/framework/dynamic/resolvers.ts#L102
And returns undefined on the console.
This is how I setup the application:
const { ApolloServer } = require('apollo-server');
import mutations from "./loadAllMutations";
import queries from "./loadAllQueries";
import resolvers from "./loadAllResolvers";
import subscriptions from "./loadAllSubscriptions";
import schemas from "./loadAllSchemas";
import generalSchema from "./../helpers/generalSchema";
export default function (rootDirectory: string,app: any,configuration: object) {
let allMutations = mutations(rootDirectory);
let allQueries= queries(rootDirectory);
let allSchemas = schemas(rootDirectory);
let allResolvers = resolvers(rootDirectory);
let allSubscriptions = subscriptions(rootDirectory);
let {validateAccessToken} = require(`${rootDirectory}/framework/predefinedModules/user/auth`).default;
let mainSchema = `
${generalSchema}
${allSchemas}
type Subscription {
${allSubscriptions}
}
type Mutation {
${allMutations}
}
type Query {
${allQueries}
}
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
`;
const server = new ApolloServer({
typeDefs: mainSchema,
resolvers: allResolvers,
context: async (a: any) => {
await validateAccessToken(a.req);
}
});
server.listen(1209).then(({ url, subscriptionsUrl }) => {
console.log(`Server ready at ${url}`);
console.log(`Subscriptions ready at ${subscriptionsUrl}`);
});
}
What could be a possible reason?
You're truncating the parameters received by the resolvers inside this module. If you need to assign a function to some object property, it's much better to just do it like this:
mutations: {
[`create${moduleName}`]: mutations[`create${moduleName}`],
},
This is not only more succinct, but it also means you don't risk accidentally leaving off a parameter, which is what happened here.

Nuxt-i18n: how to load messages asynchronously?

I am building a multilingual Nuxt web app.
Using this example from the official documentation (Codepen link), I no longer want to use local JSON files where my translations are saved to work as defined in the code below:
messages: {
'en': require('~/locales/en.json'), # I want to get this asynchronously from an HTTP URL
'fr': require('~/locales/fr.json') # I want to get this asynchronously from an HTTP URL
}
I wonder what available alternatives to set asynchronously en and fr values by reading the JSON data from a URL instead?
plugins/i18n.js:
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
export default ({ app, store }) => {
// Set i18n instance on app
// This way we can use it in middleware and pages asyncData/fetch
app.i18n = new VueI18n({
locale: store.state.locale,
fallbackLocale: 'en',
messages: {
'en': require('~/locales/en.json'), # How to get this asynchronously?
'fr': require('~/locales/fr.json') # # How to get this asynchronously?
}
})
app.i18n.path = (link) => {
if (app.i18n.locale === app.i18n.fallbackLocale) {
return `/${link}`
}
return `/${app.i18n.locale}/${link}`
}
}
What I tried:
messages: {
'en': axios.get(url).then((res) => {
return res.data
} ),
'fr': require('~/locales/fr.json')
}
Where url points to the /locals/en.json file which is hosted on my Github profile.
You can use axios with await directly in the constructor:
export default async ({ app, store }) => {
app.i18n = new VueI18n({ //construction a new VueI18n
locale: store.state.i18n.locale,
fallbackLocale: 'de',
messages: {
'de': await axios.get('http://localhost:3000/lang/de.json').then((res) => {
return res.data
}),
'en': await axios.get('http://localhost:3000/lang/en.json').then((res) => {
return res.data
})
}
})
}
I've a solution with localise.biz and cross-fetch
First add async to the pluginsplugins / i18n.js function and add await to the remote translation calls :
import Vue from 'vue';
import VueI18n from 'vue-i18n';
import getMessages from './localize';
Vue.use(VueI18n);
export default async ({ app, store }) => {
app.i18n = new VueI18n({
locale: store.state.locale,
fallbackLocale: 'en',
messages: {
'en': await getMessages('en'),
'fr': await getMessages('fr')
}
});
app.i18n.path = (link) => {
if (app.i18n.locale === app.i18n.fallbackLocale) return `/${link}`;
return `/${app.i18n.locale}/${link}`;
}
}
And create new function for get remote translation :
import fetch from 'cross-fetch';
const LOCALIZE_API_KEY = 'XXXXXXXXXXX';
const LOCALIZE_URL = 'https://localise.biz/api/export/locale';
const HEADERS = {
'Authorization': `Loco ${LOCALIZE_API_KEY}`
};
const getMessages = async (locale) => {
const res = await fetch(`${LOCALIZE_URL}/${locale}.json`, { headers: HEADERS });
if (res.status >= 400) throw new Error("Bad response from server");
return await res.json();
};
export default getMessages;
This is what i ended up with:
async asyncData(context){
// fetch translation for your source
var translation = await fetch('/translation')
// get locale of current page
var locale = context.app.i18n.locale
// set translation for Server Side Rendering
context.app.i18n.mergeLocaleMessage(locale, translation)
// save it for use on client side
return {translation: translation}
},
created(){
// prevent reverting back to not found after hard-loading page.
this.$i18n.mergeLocaleMessage(this.$i18n.locale, this.translation)
}

vue-apollo 3.0.0 Beta configuration

Pretty new at this so any help much appreciated.
I know how to do Authentication with Apollo client but when I add to my Vue-cli-3 generated project the new vue-apollo-plugin (https://www.npmjs.com/package/vue-apollo). I don't understand how and where to configure my authMiddleware.
Here is the auto generated file form the the cli:
import Vue from 'vue'
import VueApollo from 'vue-apollo'
import { createApolloClient, restartWebsockets } from 'vue-cli-plugin-apollo/graphql-client'
// Install the vue plugin
Vue.use(VueApollo)
// Name of the localStorage item
const AUTH_TOKEN = 'apollo-token'
// Config
const defaultOptions = {
httpEndpoint: process.env.VUE_APP_GRAPHQL_HTTP || 'http://localhost:4000', // Use `null` to disable subscriptions
wsEndpoint: process.env.VUE_APP_GRAPHQL_WS || 'ws://localhost:4000',
// LocalStorage token
tokenName: AUTH_TOKEN,
// Enable Automatic Query persisting with Apollo Engine
persisting: false,
// Use websockets for everything (no HTTP)
// You need to pass a `wsEndpoint` for this to work
websocketsOnly: false,
// Is being rendered on the server?
ssr: false,
// Additional ApolloClient options
// apollo: { ... }
// Client local data (see apollo-link-state)
// clientState: { resolvers: { ... }, defaults: { ... } }
}
// Call this in the Vue app file
export function createProvider (options = {}) {
// Create apollo client
const { apolloClient, wsClient } = createApolloClient({
...defaultOptions,
...options,
})
apolloClient.wsClient = wsClient
// Create vue apollo provider
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
defaultOptions: {
$query: {
// fetchPolicy: 'cache-and-network',
},
},
errorHandler (error) {
// eslint-disable-next-line no-console
console.log('%cError', 'background: red; color: white; padding: 2px 4px; border-radius: 3px; font-weight: bold;', error.message)
},
})
return apolloProvider
}
// Manually call this when user log in
export async function onLogin (apolloClient, token) {
localStorage.setItem(AUTH_TOKEN, token)
if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient)
try {
await apolloClient.resetStore()
} catch (e) {
// eslint-disable-next-line no-console
console.log('%cError on cache reset (login)', 'color: orange;', e.message)
}
}
// Manually call this when user log out
export async function onLogout (apolloClient) {
localStorage.removeItem(AUTH_TOKEN)
if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient)
try {
await apolloClient.resetStore()
} catch (e) {
// eslint-disable-next-line no-console
console.log('%cError on cache reset (logout)', 'color: orange;', e.message)
}
}
I have what I would previously use for authentication via the header here:
const authMiddleware = new ApolloLink((operation, forward) => {
// add the authorization to the headers
const token = localStorage.getItem(AUTH_TOKEN)
operation.setContext({
headers: {
authorization: token ? `Bearer ${token}` : null
}
})
return forward(operation)
})
It seems like when I dig a bit deeper into some of the imported objects from the vue-apollo package there is something like this already built in in the createApolloClient object it has this property:
authLink = setContext(function (_, _ref2) {
var headers = _ref2.headers;
return {
headers: _objectSpread({}, headers, {
authorization: getAuth(tokenName)
})
};
});
Does this mean I can simply destructure the property off the createApolloClient object? Any help or tips much appreciated.
Take a look at vue-cli-plugin-apollo
You can pass a link: authLink and\or getAuth:()=>{return "something"} in const defaultOptions = { ... } in /vue-apollo.js.
Or in main.js when you call createProvider
new Vue({
// router, store
apolloProvider: createProvider({
link: authLink,
getAuth: AUTH_TOKEN => localStorage.getItem(AUTH_TOKEN)
}),
// ...
})
using both if you adding header in authLink, getAuth is probably redundant.
if you plan to use more than one link, there is apollo-link package link: ApolloLink.from([ ... ])

Categories

Resources