I need to get IP address and port number details from an external source. These details are required to make some other requests. Following is the code I am trying on:
import axios from 'axios'
let ServerURL
axios.get('http://some/path')
.then((response) => {
ServerURL = 'http://' + response.data.server_ip_address + ':' + response.data.server_ip_port
})
.catch((error) => {
console.log(error)
})
const apiClient = axios.create({
baseURL: ServerURL,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
})
export default {
getConfigInfo () {
return apiClient.get('/config')
}
}
My problem is that by the time the exported function getConfigInfo() is called, still, the ServerURL is undefined.
How can I handle this kind of problem? Any help is highly appreciated.
Yes you can:
import axios from 'axios'
let apiClient;
const getApiClient = async () => {
if (apiClient) {
return apiClient;
}
const {
data: {
server_ip_address: ipAdress,
server_ip_port: ipPort,
}
} = await axios.get('http://some/path');
const serverUrl = `http://${ipAddress}:${ipPort}`;
apiClient = axios.create({
baseURL: ServerURL,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
});
}
export default {
async getConfigInfo() {
const apiClient = await getApiClient();
return apiClient.get('/config')
}
}
Pattern used: singleton
Related
That is my axios code but is throwing me a error of Request failed with status code 400
import axios from "axios";
import { BASE_URL } from "../../enums/baseUrl";
import { UploadUrls } from "../../enums/imageupload/urls";
import { axiosInstance } from "../config";
export const upload = async (formData: FormData
): Promise<string> => {
const { data } = await axiosInstance.post(
`${BASE_URL.DEVELOPMENT}/${UploadUrls.UPLOAD}`, formData, {
headers: { 'Authorization': 'Bearer ************',
'Content-Type': 'multipart/form-data' },
transformRequest: formData => formData,
});
return data;
};
Right now to call a private endpoint I need to copy this code to each component. Which is messy, unsustainable, and error-prone. How would I wrap this behavior in a function call and put it where I want utilities to go? So I could import { ApiUtil } from .. and ApiUtil.post('/user', user)
import axios from 'axios';
import { useAuth0 } from '../../../react-auth0-spa';
const authContext = useAuth0();
const {
getTokenSilently
} = authContext;
const token = await getTokenSilently();
await axios({
method: 'post',
headers: {
Authorization: `Bearer ${token}`,
},
url: '/user',
data: user,
});
You can create a instance of axios and can be reused in each component
import axios from 'axios';
//token code sample
const instance = axios.create({
baseURL: API_URL,
headers: { Authorization: `Bearer ${token}` }
});
export default instance;
You could create a new file and export an instance of axios
// ApiUtil.js
import axios from 'axios';
import { useAuth0 } from '../../../react-auth0-spa';
const authContext = useAuth0();
const { getTokenSilently } = authContext;
const token = await getTokenSilently();
export default axios.create({
headers: {
Authorization: `Bearer ${token}`,
},
});
Then, you could use it like this:
import ApiUtil from './ApiUtil';
// …
await ApiUtil.post('/user', { user });
Here is my sample src/main.ts file
import axios from 'axios';
export async function main() {
const URL = 'test url';
const secretKey = 'Test key'
const response = await axios.get(URL, {
headers: { 'Content-Type': 'application/json', 'KEY': secretKey },
});
I want to write my test case in spec/test.ts file using mocha. Can someone show me how to create a mock and stub for axios dependency.
For mock/stub axios in typestript I recommend axios-mock-adapter, for expect functions chai
Here is an example of how to do this
request.ts
import axios from 'axios';
const apiConfig = {
returnRejectedPromiseOnError: true,
timeout: 30000,
headers: {
common: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
},
};
const request = axios.create(apiConfig);
export default request;
main.ts
import request from './request';
export const URL = 'https://httpbin.org/get';
export const secretKey = 'secret_key';
export async function main() {
const response = await request.get(URL, {
headers: {
KEY: secretKey,
},
});
// response logic
return response;
}
main.spec.ts
import MockAdapter from 'axios-mock-adapter';
import { expect } from 'chai';
import request from './request';
import { main, URL, secretKey } from './main';
describe('Request test', () => {
let stub: MockAdapter;
const receivedData = { data: 'data' };
before(() => {
stub = new MockAdapter(request);
stub.onGet(URL, {
headers: {
KEY: secretKey,
},
}).replyOnce(200, receivedData);
// replyOnce if you assume that your code sends a single request
});
it('test', async () => {
const response = await main();
expect(response.status).to.be.equal(200);
expect(response.data).to.be.deep.equal(receivedData);
});
after(() => {
stub.restore();
});
});
I've got an API where some of the parameters need to be given within the URL.
Example of how my api url looks like: https://www.server.com/api/actions/execute?auth_type=apikey&data={"Name": "name","Email" : "email"}
What my code looks like right now
register = async () => {
let data = {"Name":this.state.name, "Email":this.state.email}
data = JSON.stringify(data)
let URL = 'https://www.server.com/api/actions/execute?auth_type=apikey&data=';
fetch(URL, {
method: 'POST',
headers: new Headers({
'Content-Type': 'application/json'
}),
body: data
})
.then((response) => response.text())
.then((responseText) => {
alert(responseText);
})
.catch((error) => {
console.error(error);
});
}
The response I get on my device:
{"code":"succes","details":{"userMessage":["java.lang.Object#2e56000c"],"output_type":void","id:"20620000000018001"},"message":"function executed succesfully"}
This is alle working fine when I test it in postman but I can't get it to work within React-Native. I've tried stuff like 'Content-Type':'application/x-www-form-urlencoded' already.
First install the package axios from the url https://www.npmjs.com/package/react-native-axios
Then create two service for handling get and post request so that you can reuse them
GetService.js
import axios from 'axios';
let constant = {
baseurl:'https://www.sampleurl.com/'
};
let config = {
headers: {
'Content-Type': 'multipart/form-data',
'Accept': 'application/json'
}
};
export const GetService = (data,Path,jwtKey) => {
if(jwtKey != ''){
axios.defaults.headers.common['Authorization'] = 'Bearer '+jwtKey;
}
try{
return axios.get(
constant.baseUrl+'api/'+Path,
data,
config
);
}catch(error){
console.warn(error);
}
}
PostService.js
import axios from 'axios';
let constant = {
baseurl:'https://www.sampleurl.com/'
};
let config = {
headers: {
'Content-Type': 'multipart/form-data',
'Accept': 'application/json'
}
};
export const PostService = (data,Path,jwtKey) => {
if(jwtKey != ''){
axios.defaults.headers.common['Authorization'] = 'Bearer '+jwtKey;
}
try{
return axios.post(
constant.baseUrl+'api/'+Path,
data,
config
);
}catch(error){
console.warn(error);
}
}
Sample code for using get and post services is given below
import { PostService } from './PostService';
import { GetService } from './GetService';
let uploadData = new FormData();
uploadData.append('key1', this.state.value1);
uploadData.append('key2', this.state.value2);
//uploadData.append('uploads', { type: data.mime, uri: data.path, name: "samples" });
let jwtKey = ''; // Authentication key can be added here
PostService(uploadData, 'postUser.php', jwtKey).then((resp) => {
this.setState({ uploading: false });
// resp.data will contain json data from server
}).catch(err => {
// handle error here
});
GetService({}, 'getUser.php?uid='+uid, jwtKey).then((resp) => {
// resp.data will contain json data from server
}).catch(err => {
// handle error here
});
If you need to pass parameters via URL you should use GET, if you use POST then the parameters should be passed in the body
Right now, in my React-Native app I have the following:
fetch('http://localhost/SOMETHING', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer '+this.state.authtoken
}
})
Goal: Have my API know what UID is making the call. I know this should be in authtoken but different users can have the same authtoken.
My initial thought is to add a ?uid=${UID} to the end of every url. However, I have GET, POST, PATCHs, with their own set of queries
Another thought would be add a header value with the UID data.
Regardless of what I choose, it would be awesome to be able to add this value to every FETCH without having to do much else work.
Is this something that is possible? Open to suggestions on what you would do.
If You can then best would be to switch to Axios (https://github.com/axios/axios) - it's much easier to do that there.
But if You need to use fetch then https://github.com/werk85/fetch-intercept is your solution.
Example code
fetchIntercept.register({
request: (url, config) => {
config.headers = {
"X-Custom-Header": true,
...config.headers
};
return [url, config];
}
});
Not sure if you're willing to step away from fetch, but we use apisauce.
import { create } from 'apisauce';
const api = create({
baseURL: 'http://localhost',
headers: { 'Accept': 'application/json' },
});
api.addRequestTransform(request => {
if (accessToken) {
request.headers['Authorization'] = `bearer ${accessToken}`;
}
});
api.get('/SOMETHING');
edit
If you want to keep it close to fetch, you could make a helper function.
let authToken = null;
export const setAuthToken = token => {
authToken = token;
};
export const fetch = (url, options) => {
if (!options) {
options = {};
}
if (!options.headers) {
options.headers = {};
}
if (authToken) {
options.headers['Authorization'] = `Bearer ${authToken}`;
}
return fetch(url, options);
};
You will probably only use the setAuthToken function once.
import { setAuthToken } from '../api';
// e.g. after login
setAuthToken('token');
Then where you would normally use fetch:
import { fetch } from '../api';
fetch('http://localhost/SOMETHING');
I would not consider creating a onetime helper function and an extra import statement for each fetch a lot of "extra work".
You can build a wrapper function for fetching with uid
function fetchWithUid(baseUrl, uid, authtoken, options) {
const { method, headers, body, ...rest } = options;
const fetchOptions = {
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + authtoken,
...headers,
},
method,
...rest,
};
if (body) {
fetchOptions.body = JSON.stringify(body);
}
return fetch(`${baseUrl}?uid=${uid}`, fetchOptions);
}
Use the fetchWithUid function like this, the fetchOptions just mimic the original fetch function's option.
const fetchOptions = {
method: 'POST',
body: {
hello: 'world',
},
};
fetchWithUid('http://localhost/SOMETHING', 123, 'abcd', fetchOptions);