Api fetch on gatsby producing error in GraphQL - javascript

This is the code I tried in gatsby-node.js, using gatsby develop to interface with graphql... I'm trying to source data from a blockchain indexer to display on my website.
const fetch = require('node-fetch');
const NODE_TYPE = 'objkt';
exports.sourceNodes = async ({ actions, createContentDigest, createNodeId }) => {
const { createNode } = actions;
const response = await fetch('https://staging.api.tzkt.io/v1/bigmaps/523/keys?value.issuer=tz1V9ZviaGUWZjGx4U7cGYFEyUGyqpFnVGXx&active=true');
const json = await response.json();
const { results = [] } = json;
const objkt = await Promise.all(results.map(async result => {
const { url } = result;
const objResponse = await fetch(url);
return await objResponse.json();
}));
objkt.forEach((node, index) => {
createNode({
...node,
id: createNodeId(`${NODE_TYPE}-${node.id}`),
parent: null,
children: null,
internal: {
type: NODE_TYPE,
content: JSON.stringify(node),
contentDigest: createContentDigest(node)
}
});
});
};
creates error:
{
"errors": [
{
"message": "Syntax Error: Expected Name, found \"}\".",
"locations": [
{
"line": 4,
"column": 3
}
],
"stack": [
"GraphQLError: Syntax Error: Expected Name, found \"}\".",
data I'm trying to source
I'm very lost as to why this error happens...

SOLUTION:
const fetch = require("node-fetch")
const NODE_TYPE = `objkt`
exports.sourceNodes = async ({
actions,
createContentDigest,
createNodeId,
}) => {
const { createNode } = actions
const response = await fetch(
"https://staging.api.tzkt.io/v1/bigmaps/523/keys?value.issuer=tz1V9ZviaGUWZjGx4U7cGYFEyUGyqpFnVGXx&active=true"
)
const objkt = await response.json()
objkt.forEach((node, index) => {
createNode({
...node,
id: createNodeId(`${NODE_TYPE}-${node.id}`),
parent: null,
children: [],
internal: {
type: NODE_TYPE,
content: JSON.stringify(node),
contentDigest: createContentDigest(node),
},
})
})
}
exports.onPreInit = () => console.log("Loaded gatsby-node")
GraphQL code:
query MyQuery {
objkt {
value {
issuer
objkt_id
objkt_amount
xtz_per_objkt
}
internal {
content
contentDigest
}
}
}

Related

How to fetch data from the Jikanapi

I want to call an API here
https://api.jikan.moe/v4/top/anime to get the data in raw format and then create an array of only useful data out of it. What is the reason the data is not being consoled
const initialAnime = {
anime: [],
genresLoaded: false,
genres: [],
};
function createAnimeFromRawData(rawData, animeArray) {
const data = rawData.data;
data.forEach((animeData) => {
const anime = {
mal_id: animeData.mal_id,
title: animeData.title,
title_english: animeData.title_english,
type: animeData.type,
episodes: animeData.episodes,
status: animeData.status,
duration: animeData.duration,
rating: animeData.rating,
rank: animeData.rank,
synopsis: animeData.synopsis,
};
console.log(animeArray);
animeArray.push(anime);
});
}
const RawdataAnime = async (api, genre, paging) => {
const Animearray = [];
for (let i = 1; Animearray.length < 60 && i < 10; i++) {
const {
data: { results },
} = await axios.get(`${api}`);
createAnimeFromRawData(results, Animearray);
}
return Animearray;
};
export const fetchAnime = createAsyncThunk(
"myanimelist/topAnime",
async (thunkAPI) => {
const {
myanimelist: { genres },
} = thunkAPI.getState();
return RawdataAnime(`https://api.jikan.moe/v4/top/anime`, genres, false);
}
);
const animeSlice = createSlice({
name: "Myanimelist",
initialState: initialAnime,
extraReducers: (builder) => {
builder.addCase(getGenresAnime.fulfilled, (state, action) => {
state.genres = action.payload;
state.genresLoaded = true;
});
builder.addCase(fetchAnime.fulfilled, (state, action) => {
state.anime = action.payload;
});
},
});
export const store = configureStore({
reducer: {
netflix: netflixSlice.reducer,
anime: animeSlice.reducer,
},
});
I tried the code above to get an array of only useful parts of data in the code but there was nothing in the console. There was no error and no output.
Whereas the response.data will be something similar to the json below::
{
"pagination":{
...
},
"data":[
...
],
"links":{
...
},
"meta":{
...
}
}
I believe the error is in the snippet
const { data: { results }} = await axios.get(`${api}`); // There are no results in the returned content
createAnimeFromRawData(results, Animearray);
Try something like
const { data } = await axios.get(`${api}`); // Equivalent to response.data
const results = data?.data || []
createAnimeFromRawData(results, Animearray);

Firestore : why using serverTimestamp gives different results?

I am having a hard time understanding serverTimestamp in firestore.
When I save a document in database in a firebase function using Fieldvalue.serverTimestamp() or in a javascript client code using serverTimestamp() it sometimes doesn't save the same thing in the database.
See screenshots below :
Sometime I get an object with {nanoseconds: xxx, seconds: xxx} and sometimes I get a timestamp formatted date...
The problem is when I try to query my orders using query(collectionRefOrders, orderBy('createdAt', 'desc'), limit(10)).
The orders with the object appears before the others ones even if they are created after...
Any clue why this happens ? What am I doing wrong ?
Thanks a lot.
EDIT :
Here is the code I use to add documents in the my firebase function (it is a request function I call in a website) :
const { getFirestore, FieldValue } = require('firebase-admin/firestore');
const firebaseDB = getFirestore();
exports.createOrderFromTunnel = functions.region('europe-west3')
.runWith({
timeoutSeconds: 10,
memory: "4GB",
})
.https
.onRequest(async (req, res) => {
cors(req, res, async () => {
try {
const { apiKey } = req.body;
const project = await getProjectFromApiKey(apiKey);
if (!project) {
return res.json({
success: false,
error: 'Unauthorized: invalid or missing api key'
});
}
const contactData = {
address: {},
createdAt: FieldValue.serverTimestamp()
};
const orderData = {
accounting: {
totalHT: 0,
totalTTC: 0,
totalTVA: 0,
},
createdAt: FieldValue.serverTimestamp(),
status: 'NEW',
};
const refProject = firebaseDB
.collection('projects')
.doc(project.id);
const colOrder = firebaseDB.collection(`projects/${project.id}/orders`)
const refOrder = colOrder.doc();
const colContact = firebaseDB.collection(`projects/${project.id}/contacts`)
const refContact = colContact.doc();
await firebaseDB.runTransaction(async transaction => {
const snapProject = await transaction.get(refProject);
const dataProject = snapProject.data();
const sequenceContact = dataProject.sequenceContact;
const sequenceOrder = dataProject.sequenceOrder;
contactData.sequence = sequenceContact;
orderData.sequenceNumber = sequenceOrder;
await transaction.set(refContact, contactData);
orderData.customer.id = refContact.id;
orderData.customer.sequence = sequenceContact;
await transaction.set(refOrder, orderData);
await transaction.update(refProject, {
sequenceContact: sequenceContact + 1,
sequenceOrder: sequenceOrder + 1,
totalContacts: dataProject.totalContacts + 1,
totalOrders: dataProject.totalOrders + 1,
});
return refOrder.id;
});
return res.json({
success: true
});
} catch (err) {
functions.logger.error(err);
return res.json({
success: false,
err
});
}
});
});
Here is the code I use to add documents in my client code (it is a web app in javascript) :
const createOrder = async (projectId) => {
try {
const orderData = {
accounting: {
totalHT: 0,
totalTTC: 0,
totalTVA: 0,
},
createdAt: serverTimestamp(),
status: 'NEW',
surface: 0,
};
const refProject = doc(firebaseDB, 'projects', projectId);
const colOrder = collection(firebaseDB, `projects/${projectId}/orders`)
const refOrder = doc(colOrder);
return await runTransaction(firebaseDB, async (transaction) => {
const snapProject = await transaction.get(refProject);
if (!snapProject.exists()) {
throw "Document does not exist!";
}
const dataProject = snapProject.data();
const sequence = dataProject.sequenceOrder;
orderData.sequenceNumber = sequence;
transaction.set(refOrder, orderData);
transaction.update(refProject, { sequenceOrder: sequence + 1, totalOrders: dataProject.totalOrders + 1 });
return refOrder.id;
});
} catch (e) {
console.error(e);
return null;
}
};

React.Js and Typescript how to read data from JSON?

everyone.
I am using MongoDB with mongoose and React.Js.
I have a page where the user can display a post.
I am sending fetch request to the backend where I am getting this json data as response.
{
"post": {
"_id": "62cd5b5ef2a39582f96ad514",
"title": "asdadsad",
"description": "sdasdasdasda",
"imageURL": "image 1",
"creator_id": "62cd5b1bf2a39582f96ad500",
"createdAt": "2022-07-12T11:30:38.255Z",
"updatedAt": "2022-07-12T11:30:38.255Z",
"__v": 0,
"id": "62cd5b5ef2a39582f96ad514"
}
}
And on the frontend I am using Fetch API, to get this data, what I am trying to do is I want to be able to read every single key and value from the JSON response as I want to use this data to display title, content etc...
const { isLoading, error, sendRequest, clearError } = useHttpRequest();
const [getPost, setPost] = useState([]);
const userID = useParams().id;
useEffect(() => {
const fetchPosts = async () => {
try {
const url: string = `http://localhost:8000/api/posts/${userID}`;
const responseData = await sendRequest(url);
console.log(responseData);
setPost(responseData);
} catch (err) { }}
fetchPosts();
}, [sendRequest]);
Now I had tried using the getPost.map(.......), however I got error that said getPost.map is not a function event when I did setPost(responseData.post) I got the same error.
So how can I access different data in the JSON response ?
In case this helps here is my sendRequest function.
and this is my sendRequest that is located in totaly different file
const useHttpRequest = () => {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const activeHttpRequests: any = useRef([]);
const sendRequest = useCallback( async (url: string, method: string = 'GET', body: any = null, headers: {} = {}) => {
setIsLoading(true);
const httpAbort = new AbortController();
activeHttpRequests.current.push(httpAbort);
try {
const response = await fetch(url, {
method: method,
headers: headers,
body: body,
signal: httpAbort.signal //FIX FOR CROSS REQUEST SENDING
});
const responseData = await response.json();
activeHttpRequests.current = activeHttpRequests.current.filter((requests: any) => requests !== httpAbort);
if (!response.ok){
throw new Error("Error fetch failed !");
}
setIsLoading(false);
return responseData;
} catch (err: any) {
console.log(err.message)
setError(err.message);
setIsLoading(false);
throw err;
};
}, [])
const clearError = () => {
setError(null);
}
useEffect(() => {
return () => {
activeHttpRequests.current.forEach((abortRequest: any) => abortRequest.abort()) //ABORT CURRENT REQUEST
};
}, []);
return { isLoading, error, sendRequest, clearError }
}
export default useHttpRequest
The map function is only present on arrays, but the data you gave is an Object. You can access it using subscript notation or iterate over the keys of the object.
const data = {
"post": {
"_id": "62cd5b5ef2a39582f96ad514",
"title": "asdadsad",
"description": "sdasdasdasda",
"imageURL": "image 1",
"creator_id": "62cd5b1bf2a39582f96ad500",
"createdAt": "2022-07-12T11:30:38.255Z",
"updatedAt": "2022-07-12T11:30:38.255Z",
"__v": 0,
"id": "62cd5b5ef2a39582f96ad514"
}
}
// access a single field
console.log(data.post.title) // asdadsad
// iterate over all fields in "post"
Object.keys(data.post).forEach((key, value) => console.log(`${key}: ${data.post[key]}`))
Your return Object would look something like this:
export interface Posts {
post: Post[];
}
export interface Post {
_id: string;
title: string;
description: string;
imageURL: string;
creator_id: string;
createdAt: Date;
updatedAt: Date;
__v: number;
id: string;
}
To simplify your work and make sure you get the correct data back, you should consider doing this below:
const { isLoading, error, sendRequest, clearError } = useHttpRequest();
const [getPost, setPost] = useState<Posts>([]);
const userID = useParams().id;
const fetchPosts = async () => {
try {
const url: string = `http://localhost:8000/api/posts/${userID}`;
const responseData = await sendRequest(url);
console.log(responseData);
setPost(responseData);
} catch (err) { }}
useEffect(() => {
fetchPosts();
}, [sendRequest]);
return (
<div>
<h1>get Data</h1>
{getPost.post.map((value,index) => (
<li key={`${index}-${value}`}>{value}</li>
))}
</div>
)

How can I receive the async data as the resolved value?

I'm trying to read files and convert them to a json, then upload them to a server. But I can't seem to be able to get the data back that isn't a promise. Can you point to what I'm doing wrong?
const onSubmit = async (formData: FormValues) => {
remove();
append(defaultFormValues.documents[0] as object);
setIsLoading(true);
const objToUpload = {
name: formData.documentName,
type: formData.documentType,
contents: [
formData.documents.map(async (document) => {
return {
language: document.language,
data: await readFromFile(document.file[0]),
actions: await readFromFile(document.actions[0]),
};
}),
],
};
console.log(objToUpload);
}
};
const onSubmit = async (formData: FormValues) => {
remove();
append(defaultFormValues.documents[0] as object);
setIsLoading(true);
const data = await Promise.all(formData.documents.map(async (document) => {
return {
language: document.language,
data: await readFromFile(document.file[0]),
actions: await readFromFile(document.actions[0]),
};
}));
const objToUpload = {
name: formData.documentName,
type: formData.documentType,
contents: data,
};
console.log(objToUpload);
};

Got error when I type special symbol in input

When I type ";/" in search input I will get this error:
Unhandled Runtime Error TypeError: invitees.filter is not a function
Here is my following code in front-end:
const { tab, teamId, privateTeamId, fetchTeamData } = props;
const [searchQuery, setSearchQuery] = useState("");
const [invitees, setInvitees] = useState([]);
const handleChange = (event) => {
event.preventDefault();
setSearchQuery(event.target.value);
};
const getUserToInvite = async () => {
const res = await axios.get(
`/api/v1/search/users/invite/${searchQuery}/${teamId}`
);
setInvitees(res.data[0]);
setShowInvitees(!showInvitees);
};
<>
{invitees
?.filter(
(user) =>
user.Memberships.length < 1 ||
(user.Memberships.every(
(member) => member.teamId !== privateTeamId
) &&
user.InvitesApplications.response !== "Waiting on response")
)
.sort(
(a, b) =>
new Date(a.InvitesApplications[0]?.createdAt) -
new Date(b.InvitesApplications[0]?.createdAt)
)
...
</>
and here is my following code in searchController in back-end:
exports.searchUserToInvite = async (req, res) => {
// Grab query
const query = req.params.q;
// Search for users
const usersFound = await models.User.findAll({
where: {
[Op.or]: [
{
fullname: {
[Op.iLike]: query + "%",
},
},
],
},
attributes: [
"id",
"fullname",
"public_user_id",
"institution",
"location",
"webpage",
"linkedin",
"major",
"picture",
"verifiedDT",
],
include: [
{
model: models.Rating,
attributes: ["skillset_rating", "team_member_rating"],
},
{
model: models.Skill,
attributes: ["skill"],
},
{
model: models.Membership,
attributes: ["teamId"],
},
{
model: models.SubMembership,
attributes: ["subTeamId"],
},
{
model: models.InvitesApplications,
attributes: [
"id",
"response",
"teamId",
"subTeamId",
"createdAt",
"updatedAt",
],
},
],
});
// Run searches
const searchData = await Promise.all([usersFound]);
// Return results
if (query.length <= 0) {
return res.status(200).json([]);
}
res.status(200).json(searchData);
};
How can I fix this error? Is this because my backend code is wrong or I need to improve my front end code?
Putting your search query as a path parameter seems quite odd but your problem is that you are not encoding the value correctly for use in an URL.
Run the values through encodeURIComponent()...
const res = await axios.get(
`/api/v1/search/users/invite/${encodeURIComponent(searchQuery)}/${encodeURIComponent(teamId)}`
);
IMO, search parameters are best handled through query parameters which Axios encodes correctly automatically
const res = await axios.get(url, {
params: {
q: searchQuery
}
})
On the server-side, you would read this through req.query.q

Categories

Resources