How to get the headers of a reponse in a fetch request? - reactjs

I'm trying to get the headers of a response following a fetch request and to assign some values to my redux state. I can only get access to the promise of the headers though. I would appreciate some help on figuring out why.
export function sign_in(email, password){
return (dispatch) => {
dispatch({ type: 'LOGGING_USER_IN' });
return fetch("http://localhost:3000/api/v1/auth/sign_in" ,{
method: "POST",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Content-Type": "application/json; charset=utf-8"
},
body: JSON.stringify({
email: email,
password: password
})
})
.then(response => {
dispatch({type:'LOGGING_USER_IN_SUCCESS', payload: response.headers})
})
.catch(error =>{
dispatch({type:'LOGGING_USER_IN_FAILURE', payload: error, error:true})
})
}
};
My reducer:
export default function authReducer(state = {
isLoaded: false,
}, action) {
switch (action.type) {
case 'LOGGING_USER_IN':
return {
...state,
}
case 'LOGGING_USER_IN_SUCCESS':
// console.log(action.payload.get("access-token"))
return {
// ...state,
isLoaded: true,
user: action.payload}
case 'LOGGING_USER_IN_FAILURE':
return{
...state,
isLoaded: true,
errorMessage: action.payload.message}
default:
return state;
}
}

response.headers is a Headers{} object that represents the HTTP response headers.
You need to lookup the headers that you want to dispatch by calling get(name), or you can get all the headers by using forEach like this:
.then(response => {
const payload = {};
response.headers.forEach((value, name) => payload[name] = value);
dispatch({type:'LOGGING_USER_IN_SUCCESS', payload })
})
demo
A side note:
Only the following headers are exposed:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
So if you want to access any other headers, you will need to set the Access-Control-Expose-Headers header appropriately.
source

Related

React doesn't set cookies but Postman does?

I have a spring boot backend that allows a user to login.
When I use postman to send a json payload to login in a user it returns the correct response with a cookie for a JSESSION.
Postman details with response and cookie
When I send the payload in react (axios) I don't see the cookie for the JSESSION anywhere but the response is still okay ?
const API_URL = "http://localhost:8080/api/auth/";
login(uniqueId: string, password: string) {
return axios.post(API_URL + "login", JSON.stringify({
"uniqueId": uniqueId,
"password": password
}),
{
headers: {
'Content-Type': 'application/json',
'withCredentials': 'true'
}
})
.then(response => {
console.log(response);
return response;
}).catch(error => {
return error.response
});
}
Chrome tab with response and no cookie
'withCredentials': 'true' shoud be outside of headers (Request Config documentstion)
In your case it would be:
const API_URL = "http://localhost:8080/api/auth/";
login(uniqueId: string, password: string) {
return axios.post(API_URL + "login", JSON.stringify({
"uniqueId": uniqueId,
"password": password
}),
{
withCredentials: true,
headers: {
'Content-Type': 'application/json'
}
})
.then(response => {
console.log(response);
return response;
}).catch(error => {
return error.response
});
}
another solution is create instance axios with parametr withCredentials: true (creating axios instance).
const BASE_URL = "http://localhost:8080/api/";
const api = axios.create({
baseURL: BASE_URL,
withCredentials: true,
headers: {'Content-Type': 'application/json'}
});
and then you can do:
return api.post("/auth/login", JSON.stringify({
"uniqueId": uniqueId,
"password": password
})) .then(response => {
console.log(response);
return response;
}).catch(error => {
return error.response
});
I have the same issue as mentioned, And I am also using withCredentials: true outside the header.
But still, Postman get Cookies And React App not.

How to present API response with redux and react

I am new to front-end. I use react and redux-form after I subbmit form on backend don't know how to handle response and present it with react. My response is simply only one number.
return function (dispatch, getState) {
dispatch({
type: CHANGE_ID_SUBMIT_DATA,
});
let reqBody = {
firstname: changeId.firstName
username: cnahgeId.userName,
};
return fetch(`${__REST_HOST__}/test/api/change/id`, {
credentials: 'include',
method: 'post',
headers: {
'Accept': 'application/json;charset=UTF-8',
'Content-Type': 'application/json;charset=UTF-8',
},
body: JSON.stringify(reqBody),
}).then(
response => dispatch(receiveData(response)),
error => dispatch({
type: CHANGE_ID_RESPONSE_ERR_DATA,
error
})
);
};
}
function receiveData(resp) {
console.log(resp.text());
return resp.text().then(response => dispatch({
type: CHANGE_ID_RESPONSE_DATA,
newId: response,
receivedAt: moment(Date.now())
}));
}```

how to pass returned fetch data to a reducer using redux saga

I'm doing a fetch request that makes a new user in my database. All of it works and a new user is made/api-key returned.
The problem is that i am unable to pass the received response of my fetch request to my reduces.
I'm wondering if I should call another action as a response to my successful fetch request that triggers a reducer and takes the response of the request as payload.
Or if I am able to pass the response of the fetch request to the reducer instantly.
Here is my SAGA:
import { call, put, takeEvery, takeLatest, delay } from 'redux-saga/effects';
import {REGISTER} from '../redux/actions/loginAPIcall'
function* callAPIregister(){
const json = yield fetch('http://spotlight-api.local/api/register', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'apptest3',
email: 'apptest3#test.be',
password: '123456789'
}),
})
.then((response) => response.json())
.then(data => {
console.log(data)
})
yield put({type: 'REGISTER_SAGA', payload: json})
}
export function* watchAPIcall(){
yield takeEvery(REGISTER, callAPIregister)
}
and below is my reducer:
import {REGISTER, LOGIN} from '../actions/loginAPIcall'
const initialState = {
apiCalling: false,
occupation: null
}
function addAPIcall(state = initialState, action, payload){
console.log('inside the api reducer')
switch(action.type){
case "REGISTER_SAGA":
console.log('inside register_saga reducer', payload)
return {
apiCalling: true,
occupation: 'REGISTER'
}
case LOGIN:
return {
apiCalling: true,
occupation: 'LOGIN'
}
default:
return state;
}
}
export default addAPIcall
when loggin the reducer payload now it says undefined.
yield by itself will wait until Promise is resolved if Promise will be returned from the yielded statement. So correct callAPIregister will be
function* callAPIregister(){
// yield will wait for Promise to resolve
const response = yield fetch('http://spotlight-api.local/api/register', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'apptest3',
email: 'apptest3#test.be',
password: '123456789'
}),
})
// Again yield will wait for Promise to resolve
const data = yield response.json()
console.log(data)
yield put({type: 'REGISTER_SAGA', payload: data})
}
And also I recommend to consider using call in yield statements. It is for easier unit testing
In my opinion, this thing will work for you. Made 'FETCH_FAILED' type well if there's any error in fetching then you can catch that error. So, make one more variable in your reducers initial_state object.
sagas.js
import { call, put, takeLatest, takeEvery } from 'redux-saga/effects';
import {REGISTER} from '../redux/actions/loginAPIcall';
function getData(payload){
return fetch('http://spotlight-api.local/api/register', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
})
.then(response => response.json())
.then(json => json)
.catch(error => {
throw error;
});
}
function* callAPIregister(){
try{
const payload = {
name: 'apptest3',
email: 'apptest3#test.be',
password: '123456789'
}
const response = yield call(getData, payload);
//In this please check what is the name of your data variable
//Eg if its message then you can
console.log(response);
//use response: response.message
yield put({type: 'REGISTER_SAGA', response: response})
} catch (error){
yield put({ type: 'FETCH_FAILED', error });
}
}
export function* watchAPIcall(){
yield takeEvery(REGISTER, callAPIregister)
}
In your reducer you can create a variable in initial state object and then in your 'REGISTER_SAGA' capture the data that we got from our saga
reducer.js
const initialState = {
apiCalling: false,
occupation: null,
data: []
}
case "REGISTER_SAGA":
console.log('inside register_saga reducer', payload)
return {
apiCalling: true,
occupation: 'REGISTER',
data: action.response
}
import { takeEvery, put, call } from "redux-saga/effects";
import { AnyAction } from "redux";
const users = [
{
id: 1,
name: "Keshav Gera",
email: "Keshav.Gera#gmail.com"
},
{
id: 2,
name: "Happy Gera",
email: "Happy.Gera#gmail.com"
}
];
yield put(getUsersSuccess({ users }));

Update state values from a different file in react native

I am keeping all my functions in one file, and calling those functions in activities where needed in my react native project. Now in one of my functions which has a fetch api, I am fetching data from my online server and printing the response after a successful query.
Now I want to be able to update state value with the response from the fetch method in the then.
App.js
...
import {registerUsers} from './src/utils/api.js'
export class App extends Component{
state = {
isLoggedIn:false,
isLoading:false,
isAppready:false
}
_Register = (email,password,fullName) =>{
this.setState({isLoading:true})
//calling the register user function here
registerUsers(email,password,fullName)
}
...
The api file
import React from 'react'
import { Alert } from 'react-native';
export function registerUsers(email, password, fullName) {
fetch('http://00.00.00.00/reg/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
userEmail: email,
userPassword: password,
userFullName: fullName
})
}).then((response) => response.json())
.then((responseJson) => {
//setState({ isLoggedIn: true, isLoading: false })
// Showing response message coming from server after inserting records.
Alert.alert(responseJson);
}).catch((error) => {
// this.setState({ isLoggedIn: true, isLoading: false })
console.error(error);
});
}
I would now want to update the state values thus isLoggedIn: true and isLoading:false after the fetch method has been processed. The problem now is that I can't figure it out where to update the state values since I am calling the registerUsers function from a different file.
I would be grateful if someone could share an idea as to how to figure this out. Thanks
registerUsers should return the promise. That way, you can handle the response directly inside your component:
API:
export function registerUsers(email, password, fullName) {
return fetch('http://00.00.00.00/reg/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
userEmail: email,
userPassword: password,
userFullName: fullName
})
}).then( response => response.json());
}
Component:
import {registerUsers} from './src/utils/api.js'
export class App extends Component{
state = {
isLoggedIn:false,
isLoading:false,
isAppready:false
}
_Register = (email,password,fullName) =>{
this.setState({isLoading:true})
//calling the register user function here
registerUsers(email, password, fullName)
.then( responseJson => {
this.setState({
isLoggedIn: true,
isLoading: false,
data: responseJson
});
}).catch( error => {
this.setState({ isLoggedIn: false, isLoading: false });
});
}

Display server response in vuejs template

I am using vuejs and backend Django. When i send request to server then it send response i had use console to display any error in console log. The problem is that i want that response to display in vuejs template. so i don`t have any idea.. so what can i do??
login: function () {
// for storing token sent by server
axiosInstance({
method: 'post',
url: '/auth/jwt/create/',
data: {
'password': this.credentials.password,
'email': this.credentials.email
}
})
.then(response => {
this.non_field_errors.push(response.data.non_field_errors)
console.log(response)
console.log(response.data.token)
this.$cookie.set('accesstoken', response.data.token, 1)
this.$cookie.set('usertype', response.data.usertype, 1)
console.log(this.$cookie.get('usertype'))
this.$router.push('/')
})
.catch(e => {
this.errors.push(e)
console.error(e)
})
}
}
First, declare a property in data object.
data: function() {
errors: null
}
You can set the value of it like this.
login: function () {
let that = this
// for storing token sent by server
axiosInstance({
method: 'post',
url: '/auth/jwt/create/',
data: {
'password': this.credentials.password,
'email': this.credentials.email
}
})
.then(response => {
//if success
})
.catch(e => {
//if catch an error
// set e or any of its props
that.errors = e
})
}
To display:
<pre v-text="errors"></pre>
Updated
working fiddle: https://fiddle.jshell.net/Zugor/601tdxoe/

Resources