I'm trying to figure out how to code my current API call so that I can access each field from the API call and render it, then be able to use it across multiple components. I'm using the QuickBase API call that only allows POST to pull field values. I've been out of the game for a couple of years and can't figure out how to accurately render these to be able to be used in other components by importing the api.js file. The project is a React within Electron to pull QuickBase data, and be able to create Line Charts (7 on one page) to show a job cost/hours and the jobs included departments cost/hours. All of my data is in quickbase, I just can't figure out how to get it over to react and able to actually use it!
Here is my API call:
let headers = {
'QB-Realm-Hostname': 'XXXXXXXXX.quickbase.com',
'User-Agent': 'FileService_Integration_V2.1',
'Authorization': 'QB-USER-TOKEN XXXXXX_XXXXX_XXXXXXXXXXXXXXX',
'Content-Type': 'application/json'
}
let body = {"from":"bpz99ram7","select":[3,6,80,81,82,83,86,84,88,89,90,91,92,93,94,95,96,97,98,99,101,103,104,105,106,107,109,111,113,115,120,123,224,225,226,227,228,229,230,231,477,479,480,481],"sortBy":[{"fieldId":6,"order":"ASC"}],"groupBy":[{"fieldId":40,"grouping":"equal-values"}],"options":{"skip":0,"top":0,"compareWithAppLocalTime":false}}
fetch('https://api.quickbase.com/v1/records/query',
{
method: 'POST',
headers: headers,
body: JSON.stringify(body)
})
.then(res => {
if (res.ok) {
return res.json().then(res => console.log(res));
}
return res.json().then(resBody => Promise.reject({status: res.status, ...resBody}));
})
.catch(err => console.log(err))
Any help would be greatly appreciated as I've been struggling on this for awhile! Right now I'm able to get all the correct data in the Console. But don't know how to go about rendering it on my application for actual use.
Thanks!
I think you should put your code inside a function and call that function from the component where you need the data, something like
import React, { Component } from 'react'
let headers = {
'QB-Realm-Hostname': 'XXXXXXXXX.quickbase.com',
'User-Agent': 'FileService_Integration_V2.1',
'Authorization': 'QB-USER-TOKEN XXXXXX_XXXXX_XXXXXXXXXXXXXXX',
'Content-Type': 'application/json'
};
class App extends Component {
state = {
data: null,
}
componentDidMount() {
this.fetchData();
}
fetchData = () => {
let body = {"from":"bpz99ram7","select":[3,6,80,81,82,83,86,84,88,89,90,91,92,93,94,95,96,97,98,99,101,103,104,105,106,107,109,111,113,115,120,123,224,225,226,227,228,229,230,231,477,479,480,481],"sortBy":[{"fieldId":6,"order":"ASC"}],"groupBy":[{"fieldId":40,"grouping":"equal-values"}],"options":{"skip":0,"top":0,"compareWithAppLocalTime":false}}
fetch('https://api.quickbase.com/v1/records/query', {
method: 'POST',
headers: headers,
body: JSON.stringify(body)
}).then(response => {
if (response.ok) {
return response.json().then(res => {
this.setState({
data: res,
})
});
}
return response.json().then(resBody => Promise.reject({status: response.status, ...resBody}));
}).catch(err => console.log(err))
}
render() {
const { data } = this.state;
if (data === null) return 'Loading...';
return (
<div>
{/* Do something with data */}
</div>
);
}
}
export default App;
Check the Docs, you can send the JSON in the props of the component to render it.
You can modify your code following this example.
sandbox
import { useEffect, useState } from "react";
async function apiCall() {
return await new Promise((resolve, reject) => {
// Api Call
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => response.json())
.then((json) => resolve(json));
});
}
const TestApp = () => {
let [data, setData] = useState({ Text: "Before api call." });
useEffect(() => {
(async () => {
let res = await apiCall();
res.Text = "After api call.";
setData(res);
})();
}, []);
return (
<div>
UserId: {data.userId} id: {data.id} title: {data.title}{" "}
completed: {data.completed}
</div>
);
};
module.exports = TestApp;
I want to write a middleware that checks the authentication and entitlement of the user. I get the authentication details from my store:
//store/index.js
const state = () => ({
auth: {
isLoggedIn: false
// and so on
}
});
and the entitlements from a plugin:
//plugins/entitlement.js
import axios from 'axios';
export default (context, inject) => {
const { env: { config: { entitlementUrl } }, store: { state: { auth: { access_token } } } } = context;
const headers = {
Authorization: `Bearer ${access_token}`,
'Content-Type': 'application/json'
};
inject('entitlement', {
isEntitled: (resourceId) => new Promise((resolve, reject) => {
axios.get(`${entitlementUrl}/entitlements`, { headers, params: { resourceId } })
.then(({ data }) => {
resolve(data.Count > 0);
})
.catch((error) => {
reject(error);
});
})
};
This is the middleware that I wrote but it doesn't work:
//middleware/isEntitled.js
export default function ({ app, store }) {
if(store.state.auth.isLoggedIn){
let isEntitled = app.$entitlement.isEntitled('someId');
console.log('entitled? ', isEntitled)
}
}
And then I add it to my config:
//nuxt.config.js
router: {
middleware: 'isEntitled'
},
I get the error isEntitled of undefined. All I want to do is to check on every page of application to see if the user is entitled! How can I achieve that?
If you look at the situation from the plugin side, you can do this:
First create a plugin:
export default ({app}) => {
// Every time the route changes (fired on initialization too)
app.router.beforeEach((to, from, next) => {
if(app.store.state.auth.isLoggedIn){
let isEntitled = app.$entitlement.isEntitled('someId');
console.log('entitled? ', isEntitled)
}
return next();
})
}
then add the plugin to your nuxt.config.js file:
plugins: [
'~/plugins/your-plugin.js',
],
I am trying to load items to my next.js page and it will fail:
import {getadminInfo} from '../../dataFetch/adminInfo'
import {addItem} from '../../dataFetch/catalog'
import {useState} from "react"
import { getList } from '../../dataFetch/catalogList'
export async function getStaticProps() {
const adminData = await getadminInfo()
const catlist = await getList()
return {
props: {
catlist,
adminData
}
}
}
export default function Main({allPostsData, adminData, catlist}) {
}
My function is :
export function getList() {
const pageInfo = {
page_size : "10",
page:"1"
}
const url = "http://localhost:8000/api/catalog/list?page_size="+pageInfo.page_size+"&page="+pageInfo.page;
try {
fetch(url, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
fData=JSON.parse(JSON.stringify(data.response))
console.log("Returned catalog")
return fData
})
.catch(error => console.log(error))
} catch (err) {
console.log(err)
}
}
The API works and I get the right info back but I cannot load it to the page:
Error: Error serializing .catlist returned from getStaticProps in "/admin/main".
Reason: undefined cannot be serialized as JSON. Please use null or omit this value.
I found the issue. I did not implement the fetch correctly. It should have been async.
The reason I did not get the info is because nothing was returned.
I am writing code to call api using axios. So, for this code I have to send an otp to the api along with an authorization token. I am using vuex store.
I am getting an error of 406(not applicable). This is the code I have written.
import { isAuthenticated } from './auth'
import axios from 'axios'
export default ({
state: {
},
mutations: {
},
getters: {
},
actions: {
VERIFY: (payload) => {
const userId = isAuthenticated().user._id
return axios
.post(apilink, payload, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${isAuthenticated().token}`,
Accept: 'application/json'
}
}).then(response => {
console.log(response)
return response.data
})
.catch(error => {
if (error) {
console.log(error)
}
})
}
},
modules: {
}
})
<template>
<mdb-btn color="info" #click="verify()">Verify</mdb-btn>
</template>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js">
data () {
return {
value: ''
}
},
methods: {
verify () {
this.$store.dispatch('VERIFY', {
otp: this.value
}).then(success => {
console.log(success)
}).catch(error => {
console.log(error)
})
}
}
</script>
I think it's the problem with authorization part. Please help me.
isAuthenticated is funtion used to get data from localStorage
export const isAuthenticated = () => {
if (localStorage.getItem('auth')) {
return JSON.parse(localStorage.getItem('auth'))
}
return false
}
406 error is appearing because of Accept parameter in the header try after removing "Accept: 'application/json'"
New to React, I'm currently trying to create a data table with data from an API.
I want to have a first fetch, and then run another with response from the first (id) in order to complete my table.
Here is my code :
class HomePage extends React.Component {
constructor(props) {
super(props);
this.state = {
user: {},
data: []
};
}
componentDidMount() {
this.setState({
user: JSON.parse(localStorage.getItem('user'))
}, function () {
this.loadAllObjectsInfo()
});
}
// Fetch all object info in order to fill the table
loadAllObjectsInfo() {
const requestOptions = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'bbuser': this.state.user.userId,
'bbtoken': this.state.user.secret
},
};
fetch('https://xxxxx/api/objects', requestOptions)
.then(response => response.json())
.then((data) => {
this.setState({ data: data })
})
}
With this code, I have the data I want to render my table but I need to run another fetch to get other info with the id coming from the first request.
How can I do that nested fetch request ?
Thanks a lot,
Matthieu
You can easily manage this with async/await:
async loadAllObjectsInfo() {
const requestOptions = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'bbuser': this.state.user.user
'bbtoken': this.state.user.secret
},
};
let response = await fetch('https://xxxxx/api/objects', requestOptions);
let data = await response.json();
// here is another fetch - change to fit your request parameters (this is just example)
let info = await fetch('https://xxxxx/api/objects/' + data.id);
this.setState({ data });
}
You can read more about async function.
#JourdanM, you should return a new fetch request from one of the then handlers. I've made a simple snippet for you. There are no data validators and spinners. This is a simple showcase. =)
A fetch request returns a promise, and you can chain promises by simply returning them from the then handlers. Here is a good article about it, it has great examples: https://javascript.info/promise-chaining
function fetchUser (user) {
return fetch(`https://api.github.com/users/${user.login}`)
}
class User extends React.Component {
state = {
user: null
}
componentDidMount () {
fetch("https://api.github.com/users")
.then(response => response.json())
.then(users => fetchUser(users[0]))
.then(response => response.json())
.then(user => {
this.setState({user})
})
}
render () {
return (
<div>
<pre>{JSON.stringify(this.state.user, null, 2)}</pre>
</div>
)
}
}
ReactDOM.render(<User />, document.querySelector("#root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
You can write the code as below.
fetch('https://xxxxx/api/objects', requestOptions)
.then(response => response.json())
.then((res1) => {
fetch('https://xxxxx/api/objects', requestOptions)
.then(response => response.json())
.then((res2) => {
this.setState({ data: res2 });
});
});
Hope this will work for you!
You can also use axios like below
axios.post(url, data, header).then(res => {
if(res.status === 200){
console.log('1st data')
axios.post(url, data, header)
.then(response => {
if (response.status === 200) {
console.log('2nd data')
} else {
console.log('2nd error')
}
});
}else{
console.log('1st error')
}
});