I am replacing axios to rn-fetch-blob in my react-native project. In the request I ping my server with credentials and I expect a response.
The old request with axios is as follows and works perfectly:
export const postWorkspace =
(newWorkspace: Workspace): AppThunk =>
async (dispatch) => {
console.log('addWorkspace Start');
dispatch(setIsLoading(true));
let configOption = {
headers: {
'Access-Control-Allow-Origin': '*',
'X-AUTH-USER': newWorkspace.credentials.email,
'X-AUTH-TOKEN': newWorkspace.credentials.password,
},
};
await axios
.get(`${newWorkspace.url}/api/ping`, configOption)
.then(async (resp) => {
console.log('addWorkspace resp', resp);
try {
await storeWorkspaceToStorage(newWorkspace);
} catch (e) {
console.error(e);
}
})
.catch((err) => {
console.log('addWorkspace err', JSON.stringify(err));
return Promise.reject(err);
})
.finally(() => dispatch(setIsLoading(false)));
};
This is how I transformed the code with rn-fetch-blob:
export const postWorkspace=
(newWorkspace: Workspace): AppThunk =>
async (dispatch) => {
console.log('addWorkspace Start');
dispatch(setIsLoading(true));
let configOption = {
'Access-Control-Allow-Origin': '*',
'X-AUTH-USER': newWorkspace.credentials.email,
'X-AUTH-TOKEN': newWorkspace.credentials.password,
};
await RNFetchBlob
.fetch('GET', '${newWorkspace.url}/api/ping', configOption)
.then( async(resp) => {
console.log('addWorkspace resp', resp);
try {
await storeWorkspaceToStorage(newWorkspace);
} catch (e) {
console.error(e);
}
})
.catch((err) => {
//console.log(err.info().status);
console.log('addWorkspace err', JSON.stringify(err));
return Promise.reject(err);
})
.finally(() => dispatch(setIsLoading(false)));
};
The new request with rn-fetch-blob returns this error:
response error "line":126349,"column":34,"sourceURL":"http://localhost:8081/index.bundle?platform=android&dev=true&minify=false"
When I opend the file "http://localhost:8081/index.bundle?platform=android&dev=true&minify=false" around line 1262349 the code looks like this, I can't understand what went wrong:
var req = RNFetchBlob[nativeMethodName];
req(options, taskId, method, url, headers || {}, body, function (err, rawType, data) {
subscription.remove();
subscriptionUpload.remove();
stateEvent.remove();
partEvent.remove();
delete promise['progress'];
delete promise['uploadProgress'];
delete promise['stateChange'];
delete promise['part'];
delete promise['cancel'];
promise.cancel = function () {};
//line 126349
if (err) reject(new Error(err, respInfo));else {
if (options.path || options.fileCache || options.addAndroidDownloads || options.key || options.auto && respInfo.respType === 'blob') {
if (options.session) session(options.session).add(data);
}
respInfo.rnfbEncode = rawType;
resolve(new FetchBlobResponse(taskId, respInfo, data));
}
});
});
I am doing this since rn-fetch-blob is basically one of the few libraries that allows react-native to ping a server with no SSL certification.
Thank you
Related
Context :
I make an API with API-Platform, and I consume this API with Vue 3 and HTTP client Axios
I have two entities in my API :
Author : name(string)
Text : content(string), author(relation to Author)
So a text item is relate to an Author...
Problem :
In Vue 3, I want to call my API for get Text entity.
But in the author column (<td> {{ item.author }} </td>) i have juste the URI reference (/api/authors/2) but I need the name of author...
Solution I tried :
<td> {{ getAuthor(item.author) }} </td>
(authorLink = /api/authors/2)
methods: {
getAuthor: async function (authorLink){
const res = await axios.get('http://127.0.0.1:8000' + authorLink)
console.log(res.data.name)
return res.data.name
}
Result of my solution :
With console.log() : 'JohnDoe' -> this work !
With return : '"[object Promise]"' -> this didnt work..
This way to get the return name with async/await pattern.
And axios needs a Accept-Encoding with correct format.
const getAuthor = async () => {
...
const res = await axios.get(...);
return Promise.resolve(res.data.name);
};
getAuthor()
.then(result => {
console.log(result);
})
Demo code
const axios = require("axios");
const getAuthor = async () => {
try {
const res = await axios.get('https://jsonplaceholder.typicode.com/users/1',
{
headers: {
'Accept-Encoding': 'application/json',
}
}
);
return Promise.resolve(res.data.name);
} catch (error) {
return Promise.reject(error);
}
};
getAuthor()
.then(result => {
console.log(result);
})
.catch(error => {
console.error(error);
});
Result this code
$ node get-data.js
Leanne Graham
This is express server version
const express = require("express")
const axios = require("axios")
const cors = require("cors")
const PORT = 3030
const app = express()
app.use(express.urlencoded({ extended: true }))
app.use(cors())
const getAuthor = async () => {
try {
const res = await axios.get('https://jsonplaceholder.typicode.com/users/1',
{
headers: {
'Accept-Encoding': 'application/json',
}
}
);
return Promise.resolve(res.data.name);
} catch (error) {
return Promise.reject(error);
}
};
app.get("/users/:id", async (req, res) => {
getAuthor()
.then(result => {
res.json(result)
})
.catch(error => {
console.error(error);
});
})
app.listen(PORT, (err) => {
if (err)
console.log("Error in server setup")
console.log("Server listening on Port", PORT);
})
install dependencies
npm install express axios cors
run it
$ node data-server.js
Server listening on Port 3030
Open this URL Chrome and open DevTool by F12
http://localhost:3030/users/1
im using rn-secure-storage to save authState when using oauth2, then i have class AppHelper to control all network function like below:
import RNSecureStorage, { ACCESSIBLE } from 'rn-secure-storage'
export const accessToken = async() => {
await RNSecureStorage.get("authState").then((value) => {
console.log("authState", value);
return JSON.parse(value).accessToken
}).catch((err) => {
console.log("can not get authState", err);
});
};
export const getData = (url, tag = 'getData') => {
return fetch(url, {
method : 'GET',
headers: {
'Content-Type': 'application/json;charset=utf-8',
'Authorization' : 'Bearer ' + accessToken
}
})
.then((response) => {
console.log(tag, 'Bearer ' + accessToken);
return response.text();
})
.then((json) => {
console.log(tag, json)
return json;
})
.catch((error) => {
handleError(err)
console.log(tag, error, url)
});
}
export const handleError = (error) => {
if (error.response.code == 401){
alert('Unauthorized')
}else{
console.log('network call failed', error)
}
}
im coding native before, so im not familiar with React native syntax. I just want to get access token to apply in network call, but my code show error:
_getMasterInfoApi Bearer function _callee() {
return _regenerator.default.async(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return _regenerator.default.awrap(_rnSecureStorage.default.get("authState").then(function (value) {
console.log("authState", value);
return JSON.parse(value).accessToken;
}).catch(function (err) {
handleError(err);
}));
case 2:
case "end":
return _context.stop();
}
}
}, null, null, null, Promise);
}
Can anyone help? thanks in advance
The app is not rendering the login page in case the dataprovider is failing.
I have made a customized login page, using firebase as authProvider.
I'm trying to make it work so that I log in and then use the user.id provided to use a correct API -key to fetch & update data from WooCommerce site.
Everything works fine if I have predefined the user id in the dataprovider, like this
const user = async () => {await authProvider.checkAuth()};
const vendor = user.lengt > 0 ? user.uid: 'reader';
let WooCommerce = new WooCommerceAPI(wcConfig[host][vendor]);
If I plainly use the user.uid it is undefined before I log in and the login age will not be shown at all. Now what I do wonder is that why would we try to use the dataprovider before auth and how to get pass that?
After log in the vendor (used for woocommerce api) is not updated either.
WooCommerce dataProvider is self made, it does return a 401, but I'm wondering if there's something missing in the error handling.
Here's the actual code:
export default {
getList: (resource, params) => {
const search = params.filter.q;
const { page, per_page } = params.pagination;
const query = {
page: JSON.stringify(page),
per_page: JSON.stringify(per_page),
search: JSON.stringify(search)
};
let url = `${resource}/?${stringify(query)}`
if (resource === 'system_status'){
url = resource;
}
return WooCommerce.get(url, params.data)
.then((response) => {
return {
data: response.data,
total: parseInt(response.headers['x-wp-total']),
pages: parseInt(response.headers['x-wp-totalpages'])
};
})
.catch((error) => {
// Invalid request, for 4xx and 5xx statuses
console.log("Response Status:", error.response.status);
console.log("Response Headers:", error.response.headers);
console.log("Response Data:", error.response.data);
return { data: error.response.data };
})
.finally(() => {
// Always executed.
});
},
getOne: (resource, params) => {
return WooCommerce.get(resource + '/' + params.id)
.then((response) => {
// Successful request
return {
data: response.data
};
})
.catch((error) => {
// Invalid request, for 4xx and 5xx statuses
console.log("Response Status:", error.response.status);
console.log("Response Headers:", error.response.headers);
console.log("Response Data:", error.response.data);
return { data: error.response.data };
})
.finally(() => {
// Always executed.
});
},
update: (resource, params) => {
return WooCommerce.put(resource + '/' + params.id, params.data)
.then((response) => {
// Successful request
return {
data: response.data
};
})
.catch((error) => {
// Invalid request, for 4xx and 5xx statuses
console.log("Response Status:", error.response.status);
console.log("Response Headers:", error.response.headers);
console.log("Response Data:", error.response.data);
return { data: error.response.data };
})
.finally(() => {
// Always executed.
});
},
create: (resource, params) => {
return WooCommerce.post(resource, params.data)
.then((response) => {
// Successful request
return {
data: response.data
};
})
.catch((error) => {
// Invalid request, for 4xx and 5xx statuses
console.log("Response Status:", error.response.status);
console.log("Response Headers:", error.response.headers);
console.log("Response Data:", error.response.data);
return { data: error.response.data };
})
.finally(() => {
// Always executed.
});
}
}
Apparently one has to handle the configuration error.
let WooCommerce = () => {
try {
return new WooCommerceAPI(config[host][vendor]);
} catch (error) {
console.error(error)
}
}
Could've been better, but at least it works now.
I am trying to make a get request to an sqlite3 table, using Express, based on input from a form. The fetch request works and so does the db.all, but I receive a response as an empty array from rows. I tried req.query and req.params already. Not sure where the error is.
//server.js
app.get('/names/state', (req, res, next) => {
const stateValue = req.query.state;
db.all(`SELECT name FROM states WHERE name=$stateVal`,
{
$stateVal: stateValue
},
(err, rows) => {
res.send({rows:rows});
})
});
//script.js
const fetchOneBtn = (e) => {
e.preventDefault();
const stateVal = stateInputValue.value;
fetch(`/names/state?state=${stateVal}`)
.then(response =>{
if(response.ok){
return response.json();
}
}).then(names => {
console.log(names);
})
};
You can change your code in your backend with this code below:
app.get('/names/state', (req, res, next) => {
const stateValue = req.query.state;
var query = "SELECT name FROM states WHERE name = " + stateValue;
db.all(query, (err, rows) => {
if(err) {
console.log(err);
res.status(500).send(err);
}else {
res.send({rows});
}
})
});
Now, for your frontend, you can change with the code below:
const fetchOneBtn = async (e) => {
e.preventDefault();
const stateVal = stateInputValue.value;
try {
const response = await fetch(`/names/state?state=${stateVal}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
});
console.log(await response.json());
return await response.json();
} catch(ex) {
console.log(ex);
}
};
I hope it can help you.
If the internet connection is lost during a fetch in my react-native app I get Network request failed and the app crashes.
updateClientData() {
var cachedData = null;
AsyncStorage.getItem('cachedData').then((cachedDataString) => {
cachedData = JSON.parse(cachedDataString);
})
.done(() => {
if (cachedData) {
const base64 = require('base-64');
return fetch('https://...data.json', {
method: 'get',
headers: {
'Authorization': 'Basic '+base64.encode("..."),
}
})
.then( (response) => {
// never called:
return response.json();
})
.catch( (error) => {
//Shouldn't this catch network errors? It never gets called.
console.log('caught network error');
})
.then( (responseJSON) => {
//do something with the JSON
})
}
});
},
I would love to be able to handle this gracefully rather than have it crash. Any ideas?
For some reason, moving the AsyncStorage call out of this function made it work fine. I didn't actually need it until I had the result of the fetch anyway, so I moved it.
This works now:
updateClientData() {
const base64 = require('base-64');
return fetch(clientListURL, {
method: 'get',
headers: {
'Authorization': 'Basic '+base64.encode("..."),
}
})
.then( (response) => {
return response.json();
})
.catch( (error) => {
console.log('error...')
})
.then( (responseJSON) => {
// now do something with the JSON and the data from Async Storage
}
},