How to inject $axios into Pinia store SSR - axios

I'm trying to inject my axios instance into the store so that I'm able to login into the app but unfortunately I'm being unable to. I have the followed boot file
import { boot } from 'quasar/wrappers';
import axios from 'axios';
import type {AxiosResponse} from 'axios';
import type { StatusCodes } from 'http-status-codes';
export type WrappedResponse = { response?: AxiosResponse };
export const isError = (e: WrappedResponse, statusCode: StatusCodes) =>
e.response && e.response.status === statusCode;
export default boot(({ app, store }) => {
const api = axios.create({ baseURL: import.meta.env.VITE_APP_API_BASE_URL });
app.provide('axios', api);
store.$axios = api;
});
Then on my store I have:
import { defineStore } from 'pinia';
export const useAppStore = defineStore('app', {
state: () => ({
}),
getters: {
},
actions: {
async login() {
console.log(this.$axios);
console.log('Logging in from store');
}
},
});
Whenever login is called it prints undefined. Any idea on what I'm doing wrong?

You simply have to create a Pinia plugin:
export default boot(({ app, store }) => {
const api = axios.create({ baseURL: import.meta.env.VITE_APP_API_BASE_URL });
app.provide('axios', api);
store.use(() => ({ api })); // 👈
});

Related

may i use this code for finduserDetail in react using redux-thunk dispatch to calling function

This code for finduserdetail by hitting function with help of dispatch method and passing (match.params.id) not working, even function not called as I know on dispatch method it should be called how may I call this so that our stat could be update in root.js file then I can show detail on my ui by using useselector
in productDetail.js
import { Fragment } from "react";
import Carousel from "react-material-ui-carousel";
import {useParams} from "react-router-dom";
import './ProductDetails.css';
import {useDispatch} from "react-redux";
import { useEffect } from "react";
import { getProductDetail } from "../../actions/productAction";
const ProductDetails = () =>{
console.log("hello this is detail")
const dispatch= useDispatch();
let params = useParams()
const id= params.id;
// const {product,error} = useSelector(
// (state) =>state.product)
useEffect(()=>{
dispatch(getProductDetail(id))
}, [dispatch, id])
return(
<Fragment>
<div className="ProductDetails">
<div>
<Carousel>
{/* {product.images &&
product.images.map((item,i)=>{
<img
className="CarouselImage"
key={item.url}
src={item.url}
alt={`${i} Slide`}
/>
})} */}
</Carousel>
</div>
</div>
</Fragment>
);
};
export default ProductDetails
and using for calling api for findproductDetail using getProductDetail in productAction.js
export const getProductDetail =(id) => async (dispatch) => {
try {
dispatch({ type: PRODUCT_DETAILES_REQUEST });
const { data } = await axios.get(`/api/v1/product/${id}`);
dispatch({
type: PRODUCT_DETAILES_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: PRODUCT_DETAILES_FAIL,
payload: error.response.data.message,
});
}
};
and one other file productReducer.js
export const productDetailsReducer = (state = { product: {} }, action) => {
switch (action.type) {
case PRODUCT_DETAILES_REQUEST:
return {
loading: true,
...state,
};
case PRODUCT_DETAILES_SUCCESS:
return {
loading: false,
product: action.payload.product,
};
case PRODUCT_DETAILES_FAIL:
return {
loading: false,
error: action.payload,
};
and another file store.js
import { legacy_createStore as createStore, combineReducers, applyMiddleware } from 'redux';
import thunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
import { productDetailsReducer, productReducer } from './reducers/productReducer';
const reducer = combineReducers({
products: productReducer,
product: productDetailsReducer,
});
let initialState ={};
const middleware = [thunk];
const store = createStore(reducer, initialState,
composeWithDevTools(applyMiddleware(...middleware))
);
export default store;
These stuff not working. I am quite beginner in React programming
import { Fragment } from "react";
import Carousel from "react-material-ui-carousel";
import {useParams} from "react-router-dom";
import './ProductDetails.css';
import {useDispatch} from "react-redux";
import { useEffect } from "react";
import { getProductDetail } from "../../actions/productAction";
const ProductDetails = () =>{
console.log("hello this is detail")
const dispatch= useDispatch();
let params = useParams()
const id= params.id;
// const {product,error} = useSelector(
// (state) =>state.product)
useEffect(()=>{
dispatch(getProductDetail(id))
}, [dispatch, id])
return(
<Fragment>
<div className="ProductDetails">
<div>
<Carousel>
{/* {product.images &&
product.images.map((item,i)=>{
<img
className="CarouselImage"
key={item.url}
src={item.url}
alt={`${i} Slide`}
/>
})} */}
</Carousel>
</div>
</div>
</Fragment>
);
};
export default ProductDetails
and using for calling api for findproductDetail using getProductDetail in productAction.js
export const getProductDetail =(id) => async (dispatch) => {
try {
dispatch({ type: PRODUCT_DETAILES_REQUEST });
const { data } = await axios.get(`/api/v1/product/${id}`);
dispatch({
type: PRODUCT_DETAILES_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: PRODUCT_DETAILES_FAIL,
payload: error.response.data.message,
});
}
};
and one other file productReducer.js
export const productDetailsReducer = (state = { product: {} }, action) => {
switch (action.type) {
case PRODUCT_DETAILES_REQUEST:
return {
loading: true,
...state,
};
case PRODUCT_DETAILES_SUCCESS:
return {
loading: false,
product: action.payload.product,
};
case PRODUCT_DETAILES_FAIL:
return {
loading: false,
error: action.payload,
};
and another file store.js
import { legacy_createStore as createStore, combineReducers, applyMiddleware } from 'redux';
import thunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
import { productDetailsReducer, productReducer } from './reducers/productReducer';
const reducer = combineReducers({
products: productReducer,
product: productDetailsReducer,
});
let initialState ={};
const middleware = [thunk];
const store = createStore(reducer, initialState,
composeWithDevTools(applyMiddleware(...middleware))
);
export default store;
The most important stuff my redux state is not updating because of id matching condition once if
state will get update I am checking using redux tool

Apollo Server Express v4 GraphQL this.findOneById is not a function

I have the following ApolloServer (v4)
import { MongoDataSource } from 'apollo-datasource-mongodb'
export default class LoaderAsset extends MongoDataSource {
async getAsset(assetId) {
return this.findOneById(assetId) // ERROR IS HERE
}
}
async function startApolloServer(app) {
const httpServer = http.createServer(app);
const server = new ApolloServer({
typeDefs,
resolvers,
plugins: [ApolloServerPluginDrainHttpServer({ httpServer })]
});
await server.start();
app.use(
'/graphql',
cors(),
bodyParser.json(),
expressMiddleware(server, {
context: async ({ req }) => {
return {
dataSources: {
loaderAsset: new LoaderAsset(modelAsset),
}
}
},
}),
);
const port = config.get('Port') || 8081;
await new Promise(resolve => httpServer.listen({ port }, resolve));
}
when I run graphql and send one assetId, everything is working till I get following error:
this.findOneById is not a function
By the way (this) has collection and model objects but not any methods.
is it because apollo-datasource-mongodb is not compatible with the new version of apollo server v4?
dataSources in v3 were as follows:
dataSources: () => ({
users: new Users(client.db().collection('users'))
// OR
// users: new Users(UserModel)
})
but in the new version dataSources is inside the context
Maybe the issue is because of this change.
Credit to: https://github.com/systemkrash on https://github.com/GraphQLGuide/apollo-datasource-mongodb/issues/114
what i did is i override my datasource class so I can call the initialize method inside in the MongoDatasource class. Now it works for me.
import { MongoDataSource } from 'apollo-datasource-mongodb';
class ReceptionDataSource extends MongoDataSource {
constructor({ collection, cache }) {
super(collection);
super.initialize({ context: this.context, cache });
}
async getReception(receptionId) {
return await this.findOneById(receptionId);
}
}
export default ReceptionDataSource;
then in my context
async function startApolloServer(app) {
const httpServer = http.createServer(app);
const server = new ApolloServer({
typeDefs,
resolvers,
plugins: [ApolloServerPluginDrainHttpServer({ httpServer })]
});
await server.start();
app.use(
'/graphql',
cors(),
bodyParser.json(),
expressMiddleware(server, {
context: async ({ req }) => {
const { cache } = server
return {
dataSources: {
loaderAsset: new ReceptionDataSource({collection: ReceptionModel, cache}),
}
}
},
}),
);
const port = config.get('Port') || 8081;
await new Promise(resolve => httpServer.listen({ port }, resolve));
}

Turn In API giving no response

I'm trying to integrate google classroom API where student can submit their work on a particular
assignment and then update the state to hand in/turn in. I'm using turn in API endpoint but the API
doesn't update the state nor return any response.
import { Injectable } from '#nestjs/common';
import { ConfigService } from '#nestjs/config';
import { google, classroom_v1, Auth } from 'googleapis';
#Injectable()
export class GoogleApiService {
oauth2Client: Auth.OAuth2Client;
classroom: classroom_v1.Classroom;
constructor(private configService: ConfigService) {
const clientId = this.configService.get('GOOGLE_CLIENT_ID');
const clientSecret = this.configService.get('GOOGLE_SECRET_KEY');
const redirectUrl = this.configService.get('GOOGLE_REDIRECT_URL');
this.oauth2Client = new google.auth.OAuth2(
clientId,
clientSecret,
redirectUrl,
);
google.options({
http2: true,
});
this.classroom = google.classroom({
version: 'v1',
auth: this.oauth2Client,
});
}
setRefreshToken(token: string) {
this.oauth2Client.setCredentials({
refresh_token: token,
});
}
async turnIn(courseId: string, courseWorkId: string, submissionId: string) {
try {
const turnInParam: classroom_v1.Params$Resource$Courses$Coursework$Studentsubmissions$Turnin =
{
courseId,
courseWorkId,
id: submissionId,
};
const res =
await this.classroom.courses.courseWork.studentSubmissions.turnIn(
turnInParam,
);
return res;
} catch (error) {
console.log(error);
return false;
}
}
}
after this nothing executes.
const res =
await this.classroom.courses.courseWork.studentSubmissions.turnIn(
turnInParam,
);

How to get data from next auth signIn Google provider in custom signIn page?

I need to get the data from the custom signIn page in order to write a user to the sanity database. But these signIn data is only obtained in [...nextauth].js file.
Code:
[...nextauth].js
import NextAuth from 'next-auth'
import GoogleProvider from 'next-auth/providers/google'
export default NextAuth({
// Configure one or more authentication providers
providers: [
GoogleProvider({
clientId: "xxxxxx",
clientSecret: "xxxxx",
}),
// ...add more providers here
],
secret: "something",
pages: {
signIn: '/auth/signin',
},
callbacks: {
async session({ session, token, user }) {
session.user.username = session.user.name
.split(' ')
.join('')
.toLocaleLowerCase()
session.user.uid = token.sub
return session
},
},
})
And these session data can be used inside components using useSession from next-auth.
But while trying to get the data to my custom signIn page, session is undefined.
import { getProviders, signIn as signIntoProvider } from "next-auth/react";
import { sanityClient } from "../../sanity";
import { useSession } from 'next-auth/react';
function signIn({users}) {
const { data: session } = useSession()
const onSubmit = (data) => {
fetch("/api/createUser", {
method: "POST",
body: JSON.stringify(data),
})
.then((resp) => {
console.log(resp);
})
.catch((err) => {
console.log(err);
});
};
const checkIfUserThere = async () => {
let newUser = session.user.email;
for (const data of users) {
if (data.email === newUser) {
return true;
}
}
return false;
};
useEffect(() => {
(async () => {
const userExists = await checkIfUserThere();
if(userExists === false ){
onSubmit(session.user); //write to sanity database
}
})();
}, []);
return (
<>
<button
className="rounded-lg bg-blue-500 p-3 text-white"
onClick={() =>
signIntoProvider("google", { callbackUrl: "/" })
}
>
Sign in with Google
</button>
</>
);
}
The above code is for a custom signIn page.
What is expected :
Once the user clicks the sign-in with the Google button, the session data must be added to the sanity database. But in my case, session here is undefined.
A simple way to do this is to write the logic inside the [...nextAuth].js file.
To solve the task of popularizing a document in Sanity from a Google authentication, you must first establish a connection to your Sanity project. Note that this import comes from the 'npm i #sanity/client' package or 'yarn add #sanity/client' and is not a reference to the configuration located in the sanity.js file. To do this, you can import the #sanity/client library and set up a configuration to connect to your project:
import sanityClient from "#sanity/client";
const config = {
dataset: "DATASET_NAME",
projectId: "PROJECT_ID",
useCdn: 'CDN'
token: "YOUR_TOKEN_SANITY",
};
export const client = sanityClient(config);
After setting up authentication with Google, you must set up a callback to run every time a user authenticates. This callback should look in Sanity to see if the user already exists, and if not, create a new user document in Sanity with the authenticated user's information:
const populateSanityUser = async (user) => {
const sanityUser = await client.fetch(
`*[_type == "users" && email == "${user.email}"]{ //check if the email exists
email
}`
);
if (sanityUser.length > 0) { //if exists
return sanityUser;
} else { //if not, create a new user with Google user session data
try {
await client.create({
_type: "user",
name: user.name,
email: user.email,
urlImage: user.image,
... // another field in your document
});
return user;
} catch (error) {
return error;
}
}
};
export default NextAuth({
...authOptions,
callbacks: {
async signIn(user) {
const isAllowedToSignIn = true; //optional
if (isAllowedToSignIn) {
const sanityUser = await populateSanityUser(user.user);
return sanityUser;
} else {
return false;
}
},
},
});
Important: Make sure that when you pass the user coming from NextAuth callback function you use user.user, as it comes nested with more data.
More information about callbacks in NextAuth here: https://next-auth.js.org/configuration/callbacks

What is cancelToken by axios and how I fix it?

I made a React app and I making requests to the backend using Axios. I created a middleware in my backend for authorization and on the frontend side I'm trying to pass to every call that is made to the backend the auth token if exists in the localStorage. Before I added the logic for that everything worked perfectly, now every time I try to log in or register I get this in the console
TypeError: Cannot read properties of undefined (reading 'cancelToken')
at throwIfCancellationRequested (dispatchRequest.js:12:1)
at dispatchRequest (dispatchRequest.js:24:1)
at async auth.js:6:1
My index.js which handles every call to the backend looks like this:
import axios from 'axios';
const API = axios.create({
baseURL: 'http://localhost:3500'
})
API.interceptors.request.use((req) => {
if (localStorage.getItem('profile')) {
req.headers.Authorization = `Bearer ${JSON.parse(localStorage.getItem('profile')).token}`
}
})
export const fetchHunts = () => API.get('/hunts');
export const createHunt = (newHunt) => API.post('/hunts', newHunt);
export const updateHunt = (id, updatedHunt) => API.patch(`/hunts/${id}`, updatedHunt);
export const deleteHunt = (id) => API.delete(`/hunts/${id}`);
export const signInAdmin = (formData) => API.post('/admins/signinadmin', formData);
export const signUpAdmin = (formData) => API.post('/admins/signupadmin', formData);
Right now I am not logged in so there is no profile in the localStorage. I tried to add this, I found this here on stack overflow but didn't work
const CancelToken = Axios.CancelToken;
instance.interceptors.request.use(req => {
/* some logic */
const CancelToken = Axios.CancelToken;
return {
...req,
cancelToken: new CancelToken((cancel) => cancel('Cancel repeated request'))
};
});
but when I used this it only returned " Cancel repeated request " and did nothing. Do you know how can I fix that? Thank you in advance!
Based on the Axios Documentation - Interceptors, the interceptor function should return the req.
API.interceptors.request.use((req) => {
if(localStorage.getItem('profile')) {
req.headers.Authorization = `Bearer ${JSON.parse(localStorage.getItem('profile')).token}`;
}
return req;
})
My 2cents:
looks like it's easier NOT to make the request in the first place, if user is not authorized =)
Just add a global middleware on frontend to redirect user to auth page.
Here is an example in Vue, but you get the logic.
import { Middleware } from '#nuxt/types';
import { RoutesName } from '~/shared/repository/routes/routes-name';
const auth: Middleware = async (context) => {
const { route, store } = context;
const isAuthorized = store.getters['user/isAuthorized'];
const isAuthPage = route.name === RoutesName.auth;
if (!isAuthorized && !isAuthPage) {
return context.redirect(`/${RoutesName.auth}`);
}
if (isAuthorized && isAuthPage) {
return context.redirect('/');
}
};
export default auth;