I'm relatively new in this environment. I use "Ant design pro 4" with React and Typescript for a new project.
I call successful my IdentityServer 4 for a token for a login. I see my response in my Browser.
But how get the token in my code?
import { Reducer } from 'redux';
import { Effect } from 'dva';
export interface StateType {
status?: 'ok' | 'error';
jsonRes: string;
type?: string;
currentAuthority?: 'user' | 'guest' | 'admin';
}
export interface LoginModelType {
namespace: string;
state: StateType;
effects: {
login: Effect;
};
reducers: {
changeLoginStatus: Reducer<StateType>;
};
}
const Model: LoginModelType = {
namespace: 'login',
state: {
// status: undefined,
jsonRes: '',
},
effects: {
* login({ payload }, { call, put }) {
const response = yield call(accountLogin, payload);
yield put({
type: 'changeLoginStatus',
payload: response,
});
},
},
reducers: {
changeLoginStatus(state, { payload }) {
return {
...state,
jsonRes: payload.json, //not work
};
},
},
};
export default Model;
EDIT:
Maybe that's helpful.
export async function accountLogin(params: LoginParamsType) {
const sendData = `grant_type=password&username=${params.userName}&password=${params.password}& ........`;
const retValue = request('https://localhost:44308/connect/token', {
method: 'POST',
data: sendData,
mode: 'no-cors',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'string',
});
return retValue;
}
use payload.json().It will read the response stream to completion and parses the response as json.
I'm sure you had it figured it out by now, but here it goes anyways
reducers: {
changeLoginStatus(state, { payload }) {
return {
...state,
jsonRes: payload.access_token, //<--this should do it
};
},
when you call const response = yield call(accountLogin, payload); it gets you the output you see in debug window.
Hope that helps.
Related
I'm currently using axios and NextJS.
I currently have this code in my component:
export async function getServerSideProps(context) {
const data = await getVideo(context.query.id);
console.log('data: ', data);
// console.log('context: ', context);
console.log('context params: ', context.params);
console.log('context query: ', context.query);
if (!data) {
return { notFound: true };
}
return {
props: {
videoId: context.params.id,
videoSlug: context.params.slug,
videoContent: data
}
};
}
This getserverSideProps call the function of getVideo which looks exactly like this:
export const getVideo = (id) => async (dispatch) => {
dispatch({ type: CLEAR_VIDEO });
try {
console.log('Action file: ', id);
const res = await api.get(`/videos/${id}`);
return dispatch({
type: GET_VIDEO,
payload: res.data
});
} catch (err) {
dispatch({
type: VIDEO_ERROR,
payload: { msg: err.response?.statusText, status: err.response?.status }
});
}
};
Said function goes through my api function to make requests to backend:
import axios from 'axios';
import { LOGOUT } from '../actions/types';
import { API_URL } from '../config';
const api = axios.create({
baseURL: `${API_URL}/api/v1`,
headers: {
'Content-Type': `application/json`
}
});
/**
intercept any error responses from the api
and check if the token is no longer valid.
ie. Token has expired
logout the user if the token has expired
**/
api.interceptors.response.use(
(res) => {
res;
console.log('Res: ', res.data);
},
(err) => {
if (err?.response?.status === 401) {
typeof window !== 'undefined' &&
window.__NEXT_REDUX_WRAPPER_STORE__.dispatch({ type: LOGOUT });
}
return Promise.reject(err);
}
);
export default api;
It works great when doing POST, PUT,PATCH requests.
As you can see, I'm doing a console.log('data: ',data) but it returns [AsyncFunction (anonymous)] whenever I read the terminal; on the other hand, the front-end returns this error:
Server Error Error: Error serializing .videoContent returned from
getServerSideProps in "/videos/[id]/[slug]". Reason: function
cannot be serialized as JSON. Please only return JSON serializable
data types.
Does anyone knows how to solve this?
NOTE: I'm using react-redux, redux and next-redux-wrapper.
That is because your getVideo function returns another function. The right way to call it would be:
const data = await getVideo(context.query.id)()//<- pass in the dispatch here
But you should not use redux in the backend like that. I think you can completely remove it.
export const getVideo async (id) => {
try {
console.log('Action file: ', id);
const res = await api.get(`/videos/${id}`);
return res.data
});
} catch (err) {
return { msg: err.response?.statusText, status: err.response?.status }
}
};
// call
const data = await getVideo(context.query.id)
I have been able to pull data from an API that I built using MongoDB and Express, but am having trouble rendering the nested data to my React component.
For example, if I type in <p>{restaurant.cuisine}</p> I am able to retrieve Burgers, American, but if I try and access {restaurant.status.delivery}, I get an error that says:
Cannot read property 'delivery' of undefined.
But if I {console.log(restaurant.status} I can see the object? I tried turning the object into an array using Object.values, but that didn't work either.
The same thing happens if I try to access the nested objects in {restaurant.images} and {restaurant.geometry}.
Here's a copy of my React hook:
import { useReducer, useEffect } from 'react';
import axios from 'axios';
const ACTIONS = {
MAKE_REQUEST: 'make-request',
GET_DATA: 'get-data',
ERROR: 'error',
};
function reducer(state, action) {
switch (action.type) {
case ACTIONS.MAKE_REQUEST:
return { loading: true, restaurant: [] };
case ACTIONS.GET_DATA:
return {
...state,
loading: false,
restaurant: action.payload.restaurant,
};
case ACTIONS.ERROR:
return {
...state,
loading: false,
error: action.payload.error,
restaurant: [],
};
default:
return state;
}
}
export default function useFetchSingleRestaurant({ id }) {
const [state, dispatch] = useReducer(reducer, {
restaurant: [],
loading: true,
});
useEffect(() => {
dispatch({ type: ACTIONS.MAKE_REQUEST });
axios
.get('http://localhost:4444/restaurants/' + id)
.then((res) => {
dispatch({
type: ACTIONS.GET_DATA,
payload: { restaurant: res.data.restaurant },
});
})
.catch((e) => {
dispatch({
type: ACTIONS.ERROR,
payload: { error: e },
});
});
}, [id]);
return state;
}
I'm accessing it in my SingleRestaurant component:
function SingleRestaurant({ match }) {
const { restaurant } = useFetchSingleRestaurant({ id: match.params.id });
return (
<p>{restaurant.status.delivery}</p>
)
}
And then here's my backend setup as well:
showRestaurant = async (req, res) => {
const restaurant = await Restaurant.findById(req.params.id)
.populate({ path: 'reviews', populate: { path: 'author' } })
.populate('author');
if (!restaurant) {
req.flash('error', 'Restaurant not found.');
return res.redirect('/restaurants');
}
res.send({ restaurant });
};
Until your server request returns restaurant it will be set as the default [] that you have set.
An empty array does not have a property of status, so hence the error.
if you change your default to null:
const [state, dispatch] = useReducer(reducer, {
restaurant: null,
loading: true,
});
And then check for a value:
function SingleRestaurant({ match }) {
const { restaurant } = useFetchSingleRestaurant({ id: match.params.id });
if (!restaurant) return 'Loading'
return (
<p>{restaurant.status.delivery}</p>
)
}
You could also pass back the loading state from your hook and then do a check on that.
I am currently developing a proof-of-concept REST api app with Deno and I have a problem with my post method (getAll et get working). The body of my request does not contain data sent with Insomnia.
My method :
addQuote: async ({ request, response }: { request: any; response: any }) => {
const body = await request.body();
if (!request.hasBody) {
response.status = 400;
response.body = { message: "No data provided" };
return;
}
let newQuote: Quote = {
id: v4.generate(),
philosophy: body.value.philosophy,
author: body.value.author,
quote: body.value.quote,
};
quotes.push(newQuote);
response.body = newQuote;
},
Request :
Response :
I put Content-Type - application/json in the header.
If I return only body.value, it's empty.
Thanks for help !
Since value type is promise we have to resolve before accessing value.
Try this:
addQuote: async ({ request, response }: { request: any; response: any }) => {
const body = await request.body(); //Returns { type: "json", value: Promise { <pending> } }
if (!request.hasBody) {
response.status = 400;
response.body = { message: "No data provided" };
return;
}
const values = await body.value;
let newQuote: Quote = {
id: v4.generate(),
philosophy: values.philosophy,
author: values.author,
quote: values.quote,
};
quotes.push(newQuote);
response.body = newQuote;
}
Problem while nodejs connecting with MYSQL which is connected by mongodb with JWT authentication
AM using nodejs mongodb jwt redux based authentication.Now am converting it to mysql db which is showing email or password incorrect.I have commented monodb code.I have mentioned ******** for mongdb configuration.I want to know why it is showing email or password incorrect for mysql itself.
loginAdmin.js
// Imports
import bcrypt from 'bcrypt'
// App Imports
import params from '../../../setup/config/params'
import validate from '../../../setup/helpers/validation'
import { logCreate } from '../../log/mutation'
//import User, { collection as user } from '../model' //Mongodb********
import authResponse from './authResponse'
import Sequelize from 'sequelize'
const sequelize = new Sequelize('dusminute', 'root', '', {
host: 'localhost',
//dialect: /* one of 'mysql' | 'mariadb' | 'postgres' | 'mssql' */
dialect: 'mysql'
});
sequelize
.authenticate()
.then(() => {
console.log('SETUP - Database Connected....');
})
.catch(err => {
console.error('Unable to connect to the database:', err);
});
const User = sequelize.define('user', {
// attributes
email: {
type: Sequelize.STRING,
allowNull: false
}
}, {
// options
});
// Login
export default async function loginAdmin({ params: { email, password }, translate }) {
var qry1,data1;
// Validation rules
const rules = [
{
data: { value: email },
check: 'email',
message: translate.t('user.messages.fields.email')
},
{
data: { value: password, length: params.user.rules.passwordMinLength },
check: 'lengthMin',
message: translate.t('user.messages.fields.passwordMinLength', { length: params.user.rules.passwordMinLength })
}
]
// Validate
try {
validate(rules)
} catch(error) {
throw new Error(error.message)
}
// Check if user exists with same email
try {
// Get user
//MongoDB *****************************
// const user = await User.findOne({ email })
// console.log(user)
// if(user) {
// const passwordsMatch = bcrypt.compare(password, user.password)
// if (passwordsMatch) {
// return {
// data: authResponse(user),
// message: translate.t('user.login.messages.success')
// }
// }
// }
User
.findOrCreate({where: {email: email,role:'admin'},attributes: ['role','isVerified','isPublished','isDeleted','id','email','password','name','mobile','image','createdAt','updatedAt']})
.then(([users, created]) => {
const user=users.get({plain: true})
console.log(user);
if(user) {
const passwordsMatch = bcrypt.compare(password, user.password)
if (passwordsMatch) {
data1= authResponse(user)
console.log(data1)
return {
data: authResponse(user),
message: translate.t('user.login.messages.success')
}
}
}
/*
findOrCreate returns an array containing the object that was found or created and a boolean that
will be true if a new object was created and false if not, like so:
[ {
username: 'sdepold',
job: 'Technical Lead JavaScript',
id: 1,
createdAt: Fri Mar 22 2013 21: 28: 34 GMT + 0100(CET),
updatedAt: Fri Mar 22 2013 21: 28: 34 GMT + 0100(CET)
},
true ]
In the example above, the array spread on line 3 divides the array into its 2 parts and passes them
as arguments to the callback function defined beginning at line 39, which treats them as "user" and
"created" in this case. (So "user" will be the object from index 0 of the returned array and
"created" will equal "true".)
*/
})
} catch (error) {
//await logCreate({ params: { payload: { method: 'userLogin', message: error.message } } })
throw new Error(translate.t('common.messages.error.server'))
}
throw new Error(translate.t('user.login.messages.error.wrongCredentials'))
}
authResponse.js
// Imports
import jwt from 'jsonwebtoken'
// App Imports
import { SECURITY_SECRET } from '../../../setup/config/env'
// Auth Response (token and user info)
export default function userAuthResponse(user) {
//user = user.toJSON() //mongodb***********************
//user=user[0];
delete user.password
//console.log(user.id)
return {
token: jwt.sign({ id: user._id }, SECURITY_SECRET),//mongodb********
//token: jwt.sign({ id: user.id }, SECURITY_SECRET),//mysql
user: user
}
}
query.js
export function login({ email, password }, isLoading = true) {
return async dispatch => {
dispatch({
type: LOGIN_REQUEST,
isLoading
})
dispatch({
type: MESSAGE_SHOW,
message: 'Please wait..'
})
try {
const { data } = await axios.post(API_URL, {
operation: 'userLoginAdmin',
params: { email, password }
})
let message = ''
if(data.success) {alert('success')
console.log(data.data.user)
dispatch(setUser(data.data.token, data.data.user))
setUserLocally(data.data.token, data.data.user)
message = `Login successful. Welcome back, ${ data.data.user.name }.`
} else {console.log(data)
message = data.message
}
dispatch({
type: MESSAGE_SHOW,
message
})
} catch(error) {
dispatch({
type: MESSAGE_SHOW,
message: 'Please try again.'
})
} finally {
dispatch({
type: LOGIN_RESPONSE
})
}
}
}`enter code here`
enter image description here
Plz see the output screen below image
Do you get a success message when hooking up to the database initially.. Does this line print?
console.log('SETUP - Database Connected....');
I'm trying to create an action for redux by using an import from a different file, but something isn't working. It's easier to show the code:
In Api.js:
exopt const API = {
GET_LIST: {path: '/list', method: 'GET'},
POST_LIST: {path: '/users/data', method: 'POST'}
};
In action.js:
import { API } from './Api';
export const fetchList = () => ({
type: 'API_ACTION',
payload: {
API.GET_LIST
}
)};
I would like fetchList to return the following action:
{
type: 'API_ACTION',
payload: {
path: '/exercises/list',
method: 'GET'
}
}
But instead I'm getting an error:
Syntax error: ... Unexpected token, expected , (7:9)
5 | type: 'API_ACTION',
6 | payload: {
> 7 | API.GET_LIST,
| ^
What am I doing wrong?
Appreciate the help!
You are trying to set a key on an object without specifying a value.
Your fetchList in action.js should look like this instead:
export const fetchList = () => ({
type: 'API_ACTION',
payload: {
path: API.GET_LIST.path,
method: API.GET_LIST.method,
},
)};
OR (even simpler)
export const fetchList = () => ({
type: 'API_ACTION',
payload: API.GET_LIST,
)};
There are many other ways to assign your payload (object spread, etc.), but the above should get you there.