Fetch API store custom header value for later use - javascript

I have the following:
let eTag: any
const request = (method: string) => (basePath: string) => async (path: string, data?: object) => {
const accessToken = await getAccessToken()
const opt: any = {
method,
headers: {
Authorization: `Bearer ${accessToken}`,
...(data && { eTag })
},
...(data && { body: data }),
}
return fetch(`${basePath}${path}`, opt).then(
res => {
eTag = res.headers.get('ETag')
return res.json()
}
)
}
I have managed to get the value form the customer header eTag but it doesn't seem to store it correctly.
I am getting the error of Unexpected end of JSON input in regards to res.json()

res.json() returns a promise. So you need the following:
let eTag: any
const request = (method: string) => (basePath: string) => async (path: string, data?: object) => {
const accessToken = await getAccessToken()
const opt: any = {
method,
headers: {
Authorization: `Bearer ${accessToken}`,
...(data && { eTag })
},
...(data && { body: data }),
}
return fetch(`${basePath}${path}`, opt).then(
async res => { //add async keyword
eTag = res.headers.get('ETag')
return await res.json() //add await here to return resolved json
}
)
}

Related

How to mock 'cross-fetch' GET POST & PUT methods

I have my code as
import fetch from 'cross-fetch'
const headers = {
Authorization: `Bearer abcdEFGH1234`,
Accept: 'application/json',
'Content-Type': 'application/json',
}
const getData = await fetch('https://api_base_url/rest/api/latest/queue/ProjectKey-PlanKey', {
method: 'GET',
headers: headers,
})
// convert the API Call response to Json
const getDataJson = await getData.json()
const putData = await fetch('https://api_base_url/rest/api/latest/queue/ProjectKey-PlanKey/comments', {
method: 'PUT',
headers: headers,
body: {message: "comment"},
})
// convert the API Call response to Json
const putDataJson = await putData.json()
cross-fetch does not seem to have methods directly like fetch.get or fetch.PUT, so the methods have to be passed via options.
The problem I am facing is how to mock these methods during testing with Jest.
I tried as below but it does not work
const mockFetchGet = jest.fn((arg1, arg2) => {
return new Promise((resolve) => {
resolve(true)
})
})
const mockFetchPost = jest.fn((arg1, arg2, arg3) => {
return new Promise((resolve) => {
resolve(true)
})
})
const mockFetchPut = jest.fn((arg1, arg2, arg3) => {
return new Promise((resolve) => {
resolve(true)
})
})
jest.mock('cross-fetch', () => {
return {
fetch: jest.fn().mockImplementation(() => {
return {
get: mockFetchGet,
post: mockFetchPost,
put: mockFetchPut,
}
}),
}
})
I get the error like below. Can anyone help? ANY GUIDANCE IN THIS IS HIGHLY APPRECIATED
TypeError: (0 , cross_fetch_1.default) is not a function
75 | )
76 |
> 77 | const mergePullRequest = await fetch(
| ^
78 | `https://api_base_url/rest/api/latest/queue/ProjectKey-PlanKey/merge`,
79 | {
80 | method: 'POST',

TypeError: res.json is not a function (not able to get fetch data)

I m trying to GET response using fetch API not stuck in a error as I mentioned below. Here's my code
const DefaultLayout = () => {
let history = useHistory()
const callHomePage = async () => {
try {
const res = fetch('http://localhost:4000/api/authenticate', {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-type': 'application/json',
},
credentials: 'include',
})
console.log(res)
const data = await res.json()
console.log(data)
if (!res.status === 200) {
const error = new Error(res.error)
throw error
}
} catch (err) {
console.log(err)
history.push('login')
}
}
Error: TypeError: res.json is not a function
Promise {} shows pending
const DefaultLayout = () => {
let history = useHistory()
const callHomePage = async () => {
try {
const res = await fetch('http://localhost:4000/api/authenticate', {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-type': 'application/json',
},
credentials: 'include',
})
console.log(res)
const data = await res.json()
console.log(data)
if (!res.status === 200) {
const error = new Error(res.error)
throw error
}
} catch (err) {
console.log(err)
history.push('login')
}
}
You need to await the fetch statement and then call the .json method of the response.
const res = await fetch(...)
data = await res.json();
Read more: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

How to map this given api response in react js javascript

I am getting an error when i was calling an post request in use effect hook and i got the response as promise pending, but the object is there, please see the response and please provide a perfect code to map this response.
code
function Comment({ id }) {
const [data, setdata] = useState([]);
console.log(id);
useEffect(() => {
const query = `
query{
forumAnswerId(id:${id}){
forumAnswerBody
forumAnswerTime
forumAnswerCode1
forumAnswerCode2
forumAnswerCode3
forumAnswerAuthor
forumAnswerBoolean
forumAnswerCode1Title
forumAnswerCode2Title
forumAnswerCode3Title
}
forumComment(forumAnswerComment:${id}){
forumAnswerCommentPost
forumAnswerCommentBody
forumAnswerCommentAuthor
forumAnswerCommentTime
}
}
`;
const opts = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query }),
};
const res = fetch('http://127.0.0.1:8000', opts).then((res) => res.json());
setdata(res);
}, []);
return <div></div>;
}
export default Comment;
here you are:
fetch('http://127.0.0.1:8000', opts)
.then((res) => res.json())
.then(r=> setdata(r))
promise result cannot be accessed outside. You need to set data inside the then function
Using Promise
fetch('http://127.0.0.1:8000', opts).then((res) => setdata(res.json()));
Using Async await
const res=await fetch('http://127.0.0.1:8000', opts)
setdata(res.json())
useEffect(() => {
const fetchData = async () => {
const query = `
query{
forumAnswerId(id:${id}){
forumAnswerBody
forumAnswerTime
forumAnswerCode1
forumAnswerCode2
forumAnswerCode3
forumAnswerAuthor
forumAnswerBoolean
forumAnswerCode1Title
forumAnswerCode2Title
forumAnswerCode3Title
}
forumComment(forumAnswerComment:${id}){
forumAnswerCommentPost
forumAnswerCommentBody
forumAnswerCommentAuthor
forumAnswerCommentTime
}
};`
const opts = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query }),
};
const res = await fetch('http://127.0.0.1:8000', opts).then((res) => res.json());
setdata(res);
}
fetchData();
}, []);

Destructuring error, response from fetch()

I want to implement a Go style error-handling-first data fetch in a React component by destructuring the [responseError, response] objects returned from the fetch(). I'm running into this error:
Uncaught (in promise) TypeError: arr[Symbol.iterator] is not a function
Which is being triggered by the destructuring syntax.
The fetch works fine when I set it up without destructuring i.e
const res = await fetch(APIurl) .
What I want to do:
let requestBody = {
query: `
query {
users {
email
}
}
`
}
const [resError, res] = await fetch(APIurl, {
method: 'POST',
body: JSON.stringify(requestBody),
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + context.token
}
})
if (resError || !res) {
console.log('Request failed', resError)
return
}
const [parseError, json] = await res.json()
if (parseError || !json) {
console.log('Request failed', parseError)
return
}
const userData = json.data.users
setUsers(userData)
}
What works currently:
let requestBody = {
query: `
query {
users {
email
}
}
`
}
const res = await fetch(APIurl, {
method: 'POST',
body: JSON.stringify(requestBody),
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + context.token
}
})
if (res.status !== 200 && res.status !== 201) {
throw new Error('Fetch failed')
}
const json = await res.json()
const userData = json.data.users
setUsers(userData)
}
I expect the output to be the same, but the destructuring is triggering the error mentioned above. I am trying to replicate the pattern mentioned in this article: https://www.dalejefferson.com/articles/2016-01-25-error-first-pattern-for-es7-async-await/
You need to write your own middleware that handles your Responses.
const validate = (req) => {
// do some magic
return [err, res];
};
const request = fetch('/api/url');
const [err, res] = validate(request);

apisauce (axios wrapper) - Can i handle the response error to write once and automatically called instead of manually add if else

I have too many API to called in my project and I'm using apisauce to communicating into API
I've an example code :
api.get("myUrl")
.then((response)=>{
console.log(response)
if(response.ok && response.status == 200){
//displaying data to screen
} else{
//display alert failed to call API
}
})
for now I want to handle if the authorization token is failed I want to redirect to login page, but I don't want to add the code authorization token is failed to all of my api request
Is there a way to create code else if(!response.ok && response.status == 401){redirectToLogin()} once instead of add this code into all of my API.get?
For our react-native app I create a class with own get, delete, put, update methods, which handles errors and then invoke apisauce.get e.t.c.
I use flow type annotations, but it'll be nicer using typescript for easily creating private methods.
type ApiRequest = (url: string, payload?: Object) => Promise<ApiResponse>;
export class Api {
apiSauce: {
get: ApiRequest,
post: ApiRequest,
put: ApiRequest,
delete: ApiRequest,
};
constructor(baseURL: string) {
this.apiSauce = apisauce.create({
baseURL,
headers: {
"Cache-Control": "no-cache",
},
timeout: 60 * 1000,
});
}
_get = async (url: string, payload?: Object) => {
const res = await this._handleResponse(this.apiSauce.get, { url, payload });
return res;
};
_put = async (url: string, payload?: Object) => {
const res = await this._handleResponse(this.apiSauce.put, { url, payload });
return res;
};
_post = async (url: string, payload?: Object) => {
const res = await this._handleResponse(this.apiSauce.post, { url, payload });
return res;
};
_delete = async (url: string, payload?: Object) => {
const res = await this._handleResponse(this.apiSauce.delete, { url, payload });
return res;
};
_handleResponse = async (apiRequest: ApiRequest, params: ApiRequestParams): Promise<ApiResponse> => {
const res = await apiRequest(params.url, params.payload);
return this._handleError(res);
};
_handleError = (res: ApiResponse) => {
if (!res.ok) {
if (res.status === 401 || res.status === 403) {
// **redirect to login page**
}
if (res.data && res.data.message) {
showNotification(res.data.message);
}
showNotification(res.problem);
}
return res;
};
getUser = async (userId: string): Promise<User> => {
const response = await this._get(`users/{userId}`);
return transformUserApiResponse(response.data);
};
}
const MyApi = new Api(BASE_URL);

Categories

Resources