Alright, I believe I have solved the issue you were facing. Let me walk you through my thought process so you can understand the objective. You can find my solution by following this link: https://codesandbox.io/s/thirsty-minsky-g6959f?file=/assets/edit-book.json:0-752
First off, the JSON data provided doesn't seem quite right. It shows multiple authors but only one "book". I assume you actually want multiple books instead. Also, make sure to wrap it within curly braces as demonstrated below:
{
"books": [
{
"id": 1,
"title": "The Shining",
"authorId": 1,
"tags": [{ "name": "new" }, { "name": "test" }]
},
{
"id": 2,
"title": "The Wendigo",
"authorId": 2,
"tags": [{ "name": "Horror" }]
}
],
"authors": [
{
"id": 1,
"prename": "Stephen",
"surname": "King"
},
{
"id": 3,
"prename": "Algernon",
"surname": "Blackwood"
},
{
"id": 4,
"prename": "Edgar Allan",
"surname": "Poe"
},
{
"id": 5,
"prename": "Howard Phillips",
"surname": "Lovecraft"
}
],
"tags": [
{
"name": "new"
},
{
"name": "Horror"
},
{
"name": "Romance"
}
]
}
Next, in your Typescript code, let's establish typings for the JSON data you'll be fetching. This will enhance readability, provide intellisense, and help catch errors beforehand. Define the properties of the JSON like so:
type Tag = {
name: string;
};
type Book = {
id: number;
title: string;
authorId: number;
tags: Tag[];
};
type Author = {
id: number;
prename: string;
surname: string;
};
type BookData = {
books: Book[];
authors: Author[];
tags: Tag[];
};
In essence, we have bookdata comprised of books, authors, and tags. Each entity has its own set of properties defined under their respective types.
Now onto the actual implementation, we'll utilize the fetch API to retrieve the JSON data from the specified URL.
async function getBookTags(n: string): Promise<Book[]> {
return fetch(url)
.then<BookData>((res) => res.json())
.then((data) => data.books)
.then((books) => books.filter((b) => doesBookHaveTag(b, n)));
}
The initial step involves fetching the data via the API, resulting in a promise. Upon resolution, we parse the response into JSON format. Subsequently, after another promise resolution, we filter out books based on matching tags.
The helper function doesBookHaveTag
is simply designed to determine if a book contains a specific tag:
function doesBookHaveTag(book: Book, n: string): boolean {
// check if book has at least one tag matching n
return book.tags.some((t) => t.name.toLowerCase() === n.toLowerCase());
}
If promises are unclear, consider watching tutorials to grasp the concept. Essentially, the browser sends an http request which resolves into executing functions specified within .then when there's availability. To call your async function and log all books tagged as "horror", execute the following:
getBookTags("horror").then(console.log); // displays the relevant book
This should elucidate how to retrieve data, handle its promise, and define your responses. While Angular specifics may vary (I'm more proficient with React), the core principles discussed apply universally to Javascript/Typescript coding.
[endnote]: When referring to a function in .then, it implies passing a function inside the .then method. For instance, data => data.books
signifies a function, equivalent to:
function(data: BookData): Book[] {
return data.books
}