I am trying to fetch JSON data from the WordPress Developer Reference site. I need to search a keyword without knowing if it's a function, class, hook, or method, which is part of the url I need to fetch. So I'm using Promise.all to cycle through all possible urls. It works if the response.status <= 299, throwing the error immediately, and if the response is ok, then it continues to .then. Fine, but occasionally it will return an ok status if the JSON exists and only returns an empty array. So I need to check if the JSON data is an empty array, which I can't seem to do in the first part. I can only check in the second part as far as I know. And if it throws the error it doesn't continue trying the other urls. Any suggestions?
var keyword = 'AtomParser';
const refs = ['function', 'hook', 'class', 'method'];
// Store the promises
let promises = [];
// Cycle through each type until we find one we're looking for
for (let t = 0; t < refs.length; t++) {
const url =
'https://developer.wordpress.org/wp-json/wp/v2/wp-parser-' +
refs[t] +
'?search=' +
keyword;
// console.log(url);
promises.push(fetch(url));
}
Promise.all(promises)
.then(function(response) {
console.log(response[0]);
// Get the status
console.log('Status code: ' + response[0].status);
if (response[0].status <= 299) {
// The API call was successful!
return response[0].json();
} else {
throw new Error('Broken link status code: ' + response[0].status);
}
})
.then(function(data) {
// This is the HTML from our response as a text string
console.log(data);
// Make sure we have data
if (data.length == 0) {
throw new Error('Empty Array');
}
// ref
const reference = data[0];
// Only continue if not null or empty
if (reference !== null && reference !== undefined && data.length > 0) {
// Success
// Return what I want from the reference
}
})
.catch(function handleError(error) {
console.log('Error' + error);
});
Is there some way to get the JSON data in the first part so I can check if it's in an array while I'm checking the response status?
I would recommend encapsulating the success / failure logic for individual requests, then you can determine all the resolved and rejected responses based on the result of that encapsulation.
For example
const checkKeyword = async (ref, keyword) => {
const params = new URLSearchParams({ search: keyword });
const res = await fetch(
`https://developer.wordpress.org/wp-json/wp/v2/wp-parser-${encodeURIComponent(
ref
)}?${params}`
);
if (!res.ok) {
throw new Error(`${res.status}: ${await res.text()}`);
}
const data = await res.json();
if (data.length === 0) {
throw new Error(`Empty results for '${ref}'`);
}
return { ref, data };
};
Now you can use something like Promise.any() or Promise.allSettled() to find the first successful request or all successful requests, respectively
const keyword = "AtomParser";
const refs = ["function", "hook", "class", "method"];
const promises = refs.map((ref) => checkKeyword(ref, keyword));
// First success
Promise.any(promises)
.then(({ ref, data }) => {
console.log(ref, data);
})
.catch(console.error);
// All successes
Promise.allSettled(promises)
.then((responses) =>
responses.reduce(
(arr, { status, value }) =>
status === "fulfilled" ? [...arr, value] : arr,
[]
)
)
.then((results) => {
// results has all the successful responses
});
For whatever reason I couldn't get Phil's answer to work, so I ended up doing the following which works fine for me. (This is for a discord bot in case you're wondering what the other stuff is all about).
var keyword = 'AtomParser';
const refs = ['function', 'hook', 'class', 'method'];
// Store the successful result or error
let final: any[] = [];
let finalError = '';
// Cycle through each type until we find one we're looking for
for (let t = 0; t < refs.length; t++) {
const url =
'https://developer.wordpress.org/wp-json/wp/v2/wp-parser-' +
refs[t] +
'?search=' +
keyword;
console.log(url);
// Try to fetch it
await fetch(url)
.then(function (response) {
console.log(response);
// Get the status
console.log('Status code: ' + response.status);
if (response.status > 299) {
finalError = '`' + refs[t] + '` does not exist.';
throw new Error(finalError);
} else {
// The API call was successful!
return response.json();
}
})
.then(function (data) {
// This is the HTML from our response as a text string
console.log(data);
// Make sure we have data
if (data.length == 0) {
finalError = "Sorry, I couldn't find `" + keyword + '`';
throw new Error(finalError);
}
// Only continue if not null or empty
if (data[0] !== null && data[0] !== undefined && data.length > 0) {
for (let d = 0; d < data.length; d++) {
// Add it to the final array
final.push(data[d]);
}
}
})
.catch(function handleError(error) {
console.log(error);
});
}
if (final.length > 0) {
for (let f = 0; f < final.length; f++) {
// ref
const reference = final[f];
// Get the link
const link = reference.link;
// Get the title
var title = reference.title.rendered;
title = excerpt.replace('>', '>');
// Get the excerpt
var excerpt = reference.excerpt.rendered;
excerpt = excerpt.replace('<p>', '');
excerpt = excerpt.replace('</p>', '');
excerpt = excerpt.replace('<b>', '**');
excerpt = excerpt.replace('</b>', '**');
console.log(excerpt);
message.reply(
new discord.Embed({
title: `${title}`,
url: link,
description: `${excerpt}\n\n`,
footer: {
text: `WordPress Developer Code Reference\nhttps://developer.wordpress.org/`,
},
})
);
}
} else if (finalError != '') {
message.reply(finalError);
} else {
message.reply('Something went wrong...');
}
wp module
#Phil's answer puts you on the right track but I want to expand on some of his ideas. Use of URLSearchParamas is great but you can improve by using the high-level URL API and forego encodeURIComponent and constructing search params manually. Notice I'm putting this code in its own wp module so I can separate concerns more easily. We don't want all of this code leaking into your main program.
// wp.js
import { fetch } from "whatwg-fetch" // or your chosen implementation
const baseURL = "https://developer.wordpress.org"
async function search1(path, query) {
const u = new URL(path, baseURL)
u.searchParams.set("search", query)
const result = await fetch(u)
if (!result.ok) throw Error(`Search failed (${result.status}): ${u}`)
return result.json()
}
search1 searches one path, but we can write search to search all the necessary paths. I don't think there's any reason to get fancy with each path here, so just write them out -
// wp.js (continued)
function search(query) {
const endpoints = [
"/wp-json/wp/v2/wp-parser-function",
"/wp-json/wp/v2/wp-parser-hook",
"/wp-json/wp/v2/wp-parser-class",
"/wp-json/wp/v2/wp-parser-method"
]
return Promise
.all(endpoints.map(e => search1(e, query)))
.then(results => results.flat())
}
export { search }
main module
Notice we only exported search as search1 is internal to the wp module. Let's see how we can use it in our main module now -
// main.js
import { search } from "./wp.js"
for (const result of await search("database"))
if(result.guid.rendered)
console.log(`${result.title.rendered}\n${result.guid.rendered}\n`)
In this example, we first search for "database" -
wp_should_replace_insecure_home_url()
https://developer.wordpress.org/reference/functions/wp_should_replace_insecure_home_url/
wp_delete_signup_on_user_delete()
https://developer.wordpress.org/reference/functions/wp_delete_signup_on_user_delete/
get_post_datetime()
https://developer.wordpress.org/reference/functions/get_post_datetime/
wp_ajax_health_check_get_sizes()
https://developer.wordpress.org/reference/functions/wp_ajax_health_check_get_sizes/
wp_should_replace_insecure_home_url
https://developer.wordpress.org/reference/hooks/wp_should_replace_insecure_home_url/
comments_pre_query
https://developer.wordpress.org/reference/hooks/comments_pre_query/
users_pre_query
https://developer.wordpress.org/reference/hooks/users_pre_query/
WP_Object_Cache
http://developer.wordpress.org/reference/classes/wp_object_cache/
wpdb
http://developer.wordpress.org/reference/classes/wpdb/
WP_REST_Menu_Items_Controller::prepare_item_for_database()
https://developer.wordpress.org/reference/classes/wp_rest_menu_items_controller/prepare_item_for_database/
WP_REST_Global_Styles_Controller::prepare_item_for_database()
https://developer.wordpress.org/reference/classes/wp_rest_global_styles_controller/prepare_item_for_database/
WP_REST_Menus_Controller::prepare_item_for_database()
https://developer.wordpress.org/reference/classes/wp_rest_menus_controller/prepare_item_for_database/
WP_REST_Templates_Controller::prepare_item_for_database()
https://developer.wordpress.org/reference/classes/wp_rest_templates_controller/prepare_item_for_database/
WP_REST_Application_Passwords_Controller::prepare_item_for_database()
https://developer.wordpress.org/reference/classes/wp_rest_application_passwords_controller/prepare_item_for_database/
wpdb::db_server_info()
https://developer.wordpress.org/reference/classes/wpdb/db_server_info/
WP_REST_Attachments_Controller::insert_attachment()
https://developer.wordpress.org/reference/classes/wp_rest_attachments_controller/insert_attachment/
WP_Debug_Data::get_database_size()
https://developer.wordpress.org/reference/classes/wp_debug_data/get_database_size/
WP_REST_Meta_Fields::update_multi_meta_value()
https://developer.wordpress.org/method/wp_rest_meta_fields/update_multi_meta_value/
another search example
Now let's search for "image" -
for (const result of await search("image"))
if(result.guid.rendered)
console.log(`${result.title.rendered}\n${result.guid.rendered}\n`)
get_adjacent_image_link()
https://developer.wordpress.org/reference/functions/get_adjacent_image_link/
get_next_image_link()
https://developer.wordpress.org/reference/functions/get_next_image_link/
get_previous_image_link()
https://developer.wordpress.org/reference/functions/get_previous_image_link/
wp_robots_max_image_preview_large()
https://developer.wordpress.org/reference/functions/wp_robots_max_image_preview_large/
wp_getimagesize()
https://developer.wordpress.org/reference/functions/wp_getimagesize/
is_gd_image()
https://developer.wordpress.org/reference/functions/is_gd_image/
wp_show_heic_upload_error()
https://developer.wordpress.org/reference/functions/wp_show_heic_upload_error/
wp_image_src_get_dimensions()
https://developer.wordpress.org/reference/functions/wp_image_src_get_dimensions/
wp_image_file_matches_image_meta()
https://developer.wordpress.org/reference/functions/wp_image_file_matches_image_meta/
_wp_check_existing_file_names()
https://developer.wordpress.org/reference/functions/_wp_check_existing_file_names/
edit_custom_thumbnail_sizes
https://developer.wordpress.org/reference/hooks/edit_custom_thumbnail_sizes/
get_header_image_tag_attributes
https://developer.wordpress.org/reference/hooks/get_header_image_tag_attributes/
image_editor_output_format
https://developer.wordpress.org/reference/hooks/image_editor_output_format/
wp_image_src_get_dimensions
https://developer.wordpress.org/reference/hooks/wp_image_src_get_dimensions/
wp_get_attachment_image
https://developer.wordpress.org/reference/hooks/wp_get_attachment_image/
image_sideload_extensions
https://developer.wordpress.org/reference/hooks/image_sideload_extensions/
wp_edited_image_metadata
https://developer.wordpress.org/reference/hooks/wp_edited_image_metadata/
wp_img_tag_add_loading_attr
https://developer.wordpress.org/reference/hooks/wp_img_tag_add_loading_attr/
wp_image_file_matches_image_meta
https://developer.wordpress.org/reference/hooks/wp_image_file_matches_image_meta/
get_custom_logo_image_attributes
https://developer.wordpress.org/reference/hooks/get_custom_logo_image_attributes/
Custom_Image_Header
http://developer.wordpress.org/reference/classes/custom_image_header/
WP_Image_Editor_Imagick
http://developer.wordpress.org/reference/classes/wp_image_editor_imagick/
WP_Embed
http://developer.wordpress.org/reference/classes/wp_embed/
WP_Image_Editor
http://developer.wordpress.org/reference/classes/wp_image_editor/
WP_Customize_Background_Image_Setting
http://developer.wordpress.org/reference/classes/wp_customize_background_image_setting/
WP_Customize_Header_Image_Setting
http://developer.wordpress.org/reference/classes/wp_customize_header_image_setting/
WP_Image_Editor_GD
http://developer.wordpress.org/reference/classes/wp_image_editor_gd/
WP_Customize_Header_Image_Control
http://developer.wordpress.org/reference/classes/wp_customize_header_image_control/
WP_REST_Server::add_image_to_index()
https://developer.wordpress.org/reference/classes/wp_rest_server/add_image_to_index/
WP_REST_URL_Details_Controller::get_image()
https://developer.wordpress.org/reference/classes/wp_rest_url_details_controller/get_image/
WP_Image_Editor::get_default_quality()
https://developer.wordpress.org/reference/classes/wp_image_editor/get_default_quality/
WP_Theme_JSON::get_blocks_metadata()
https://developer.wordpress.org/reference/classes/wp_theme_json/get_blocks_metadata/
WP_Image_Editor_Imagick::pdf_load_source()
https://developer.wordpress.org/reference/classes/wp_image_editor_imagick/pdf_load_source/
WP_Image_Editor_Imagick::write_image()
https://developer.wordpress.org/reference/classes/wp_image_editor_imagick/write_image/
WP_Image_Editor_Imagick::maybe_exif_rotate()
https://developer.wordpress.org/reference/classes/wp_image_editor_imagick/maybe_exif_rotate/
WP_Image_Editor_Imagick::make_subsize()
https://developer.wordpress.org/reference/classes/wp_image_editor_imagick/make_subsize/
WP_Image_Editor_GD::make_subsize()
https://developer.wordpress.org/reference/classes/wp_image_editor_gd/make_subsize/
empty search result
Searching for "zzz" will yield no results -
for (const result of await search("zzz"))
if(result.guid.rendered)
console.log(`${result.title.rendered}\n${result.guid.rendered}\n`)
<empty result>
I've been trying to make a program that spits out the definitions of a word list for a project. I am using https://dictionaryapi.dev/. I've never worked with web apis before, so can I get some help with this.
I've tried
var data = $.getJSON("https://api.dictionaryapi.dev/api/v2/entries/en/hello")
then
document.getElementById('output').innerHTML = data.meanings[1].definition
but it doesn't work. It says it can't find what meanings is.
You could use flatMap to retrieve just the definitions from the response:
const DICTIONARY_API_BASE_URL =
'https://api.dictionaryapi.dev/api/v2/entries/en/';
const DEFINITIONS_DIV = document.getElementById('definitions');
const fetchWordDefinitions = async word => {
console.log(`Making request for definitions of ${word}...`);
const response = await fetch(DICTIONARY_API_BASE_URL + word);
const json = await response.json();
return json[0].meanings
.flatMap(m => m.definitions)
.flatMap(d => d.definition);
};
const getWordDefinitions = () => {
const word = document.getElementById('word').value;
if (word == null || word == '') {
return alert('Error: You must enter a word to fetch');
}
DEFINITIONS_DIV.innerHTML = '';
fetchWordDefinitions(word)
.then(defintions => {
defintions.forEach(d => {
DEFINITIONS_DIV.innerHTML += `<p>${d}</p>`;
});
})
.catch(_ => {
DEFINITIONS_DIV.innerHTML += `<p>Error: Could not retrive any defintions for ${word}.</p>`;
});
};
* {
font-family: sans-serif
}
<!DOCTYPE html>
<html>
<body>
<h1>Fetch the definitions for a word!</h1>
<input type="text" id="word" name="word">
<input type="button" value="Fetch" onClick="getWordDefinitions()">
<div id="definitions"></div>
</body>
</html>
What I usually do with cases like this is to make use of the console.log() function.
fetch('https://api.dictionaryapi.dev/api/v2/entries/en/english')
.then(response => {
return response.json();
})
.then(word => {
console.log(word);
})
You can use Chrome developer tools by pressing F12. A console window will open in your browser, here you can expand the JSON response request returned from console.log(word); this will allow you to view each of the child elements. This should give you a better idea of how the structure of the JSON is formatted. Once you understand the structure you can remove the console.log(word); and assign it to a variable
var singleWordDefinition = word[0].meanings[0].definitions[0].definition;
Example Code:
function returnDefinition() {
fetch('https://api.dictionaryapi.dev/api/v2/entries/en/hello')
.then(response => {
return response.json();
})
.then(word => {
var singleWordDefinition = word[0].meanings[0].definitions[0].definition;
console.log("SINGLE: " + singleWordDefinition);
const wordDefinitionArr = word[0].meanings;
wordDefinitionArr.forEach(wordDefinition => {
console.log("FROM ARRAY: " + wordDefinition.definitions[0].definition);
});
})
};
Console output
I tried to get the data from the json file with javascript but it doesn't output the data
here is my code:
fetch('https://raw.githubusercontent.com/trvodi/test/main/json1.json')
.then((res) => res.json())
.then((data) => {
var json = data;
var i;
var iLength = json.data.item.length;
for (i = 0; i < iLength; i++) {
alert(json.data.item[i].FromMember);
}
}).catch((err) => {
console.log(err)
})
please help me. thank you
If you'd add the following line:
console.log(json.data.item, json.data.item.length);
You'll see that json.data.item.length is undefined because json.data.item is an object.
I'd recommend using
for (let i in json.data.item) {
let item = json.data.item[i];
console.log(item.FromMember);
}
To loop over the objects as shown in this demo:
fetch('https://raw.githubusercontent.com/trvodi/test/main/json1.json')
.then((res) => res.json())
.then((data) => {
for (let i in data.data.item) {
let item = data.data.item[i];
console.log(item.FromMember);
}
})
.catch((err) => {
console.log(err)
})
For more info about why (and alternatives) I'd choose for (let i in json.data.item), please see the following question/answer:
How to loop through a plain JavaScript object with the objects as members?
I'm trying to get my code to output an api object to the html file.
const container = document.createElement('div');
container.setAttribute('class', 'container');
obj = fetch('https://apis.is/concerts')
.then(function(response) {
return response.json();
})
.then(function(data) {
return obj = data;
})
.then(() => idk())
function idk() {
let count = 0;
for(key in obj.results) {
count++;
};
console.log(count);
for(let i = 0; i < count; i++) {
const card = document.createElement('div');
card.setAttribute('class', 'card');
const h1 = document.createElement('h1');
h1.textContent = obj.results[i].eventDateName;
const p = document.createElement('p');
p.textContent = obj.results[i].dateOfShow;
container.appendChild(card);
card.appendChild(h1);
card.appendChild(p);
};
};
I have been trying to use DOM to create elements for the html file but it's like some of the code is being ignored.
If you want to render all the DOM you are creating you have to somehow add it to the DOM tree that browser is displaying. The simples way would be to add it to body node. document.querySelector('body').appendChild(container); once you're done with data processing.
But I would suggest to refactor your code a bit. For instance in this step you are assigning results to the original object where you are saving the promise with the results. Also that is a global object so pretty quick you might end up with a race condition.
.then(function(data) {
return obj = data;
})
Also the idk() function is coupled to that very specific variable obj which would make it really hard to test.
obj = fetch('https://apis.is/concerts')
.then(function(response) {
return response.json(); //subscribe to response stream
})
.then((response) => {
const allEvents = eventsDomTree(response.results); // create the events DOM tree based on response
document.querySelector('body').appendChild(allEvents); //append the created list to document DOM tree
});
function eventsDomTree(events) {
const allEvents = document.createElement('div');
events.forEach((event) => {
const card = document.createElement('div');
card.setAttribute('class', 'card');
const eventName = document.createElement('h1');
eventName.textContent = event.eventDateName;
const dateOfShow = document.createElement('p');
dateOfShow.textContent = event.dateOfShow
card.appendChild(eventName);
card.appendChild(dateOfShow);
allEvents.appendChild(card);
});
return allEvents;
}
I have most of my code written but I'm not sure what I'm doing wrong on this:
let url = 'https://cors-anywhere.herokuapp.com/https://newsapi.org/v2/top-headlines?sources=hacker-news&apiKey=3dcfcd098261443dae7c7d002f25c062';
fetch(url)
.then(r =>{
return r.json();
})
.then(data => {
let articles = data.articles;
let storyList = document.createElement("ul");
let body = document.querySelector("body");
body.appendChild(storyList);
})
articles.map(articles => {
let storyItem = document.createElement("li");
storyItem.innerHTML = 'a href = "' + articles.href + '">' + articles.title + "</a>";
storyList.appendChild(storyItem);
})
.catch(e => {
console.log('An error has occurred: ${e}');
});
I had taken out the < > from the API code and tried switching things around like switching some properties to say something different but could someone help me understand this a bit better? Thanks in advance!
There were several things that you were doing wrong.
No need to use a proxy when the API you are consuming allows cors requests.
You were trying to access the "articles" out of scope and before the promise was resolved
You were using the wrong method, IMO, on the "articles" array. From here: Array.prototype.map()
The map() method creates a new array with the results of calling a provided function on every element in the calling array.
but you were not trying create a new array, you just wanted to iterate the array's elements. That is what Array.prototype.forEach() is for.
You used single quotes ' on your template literal instead of back-ticks `
let url = 'https://newsapi.org/v2/top-headlines?sources=hacker-news&apiKey=3dcfcd098261443dae7c7d002f25c062';
fetch(url)
.then(response => {
return response.json();
})
.then(data => {
let list = document.createElement('ul');
document.querySelector("body").appendChild(list);
data.articles.forEach(article => {
let item = document.createElement('li');
item.innerHTML = '' + article.title + "";
list.appendChild(item);
});
})
.catch(e => {
console.log(`An error has occurred: ${e}`);
});