i want to do the following: get a random name with fetch from this website https://swapi.dev/api/people/, which i did and i can see it in my html page then i want also to get a random planet, here i need to access the homeworld key, and to return the link, before returning the link i formatted to get a random url and from this one i also have to show the name of the planet on my page. The first fetch works fine, at least i think but the 3rd .then() is not working or at least i don't know how to access the information from the homeworld url. This is my first time trying fetch() and it will be nice if you guys can help me telling where i did wrong in code and maybe different solutions but not so complicated :D tnks
let randomNumber = Math.floor(Math.random()*9)
const fetchPromise = fetch("https://swapi.dev/api/people/");
let test
let test2
let planets = document.querySelector('#age')
fetchPromise
.then((response) => {
if (!response.ok) {
throw new Error(`Http error: ${response.status}`);
}
return response.json();
})
.then((json) => {
console.log(json.results[randomNumber].name)
showRandomUserData(json)
test = json.results[0].homeworld
test = test.slice(0, -2)
// console.log(test + randomNumber + "/");
// console.log(test + "/" + randomNumber + "/");
test = test + randomNumber + "/";
return fetch(test)
// return fetch("https://swapi.dev/api/planets/2/");
})
.then(response => response.json()).then(json =>
{ test2=json.name
console.log(test2);
planets.innerHTML = test2
})
showRandomUserData = (randomUser) => {
document.querySelector("#name").innerHTML =
randomUser.results[randomNumber].name;
}
Solved
Here's a simple solution that uses fetch() to grab data from both those URLs and then insert all the people and the one planet that is returned into your web page:
function myFetch(...args) {
return fetch(...args).then(response => {
if (!response.ok) {
throw new Error(`fetch failed with status ${response.status}`);
}
return response.json();
});
}
Promise.all([
myFetch("https://swapi.dev/api/people/"),
myFetch("https://swapi.dev/api/planets/2/")
]).then(([people, planet]) => {
const peopleDiv = document.getElementById("people");
let peopleHTML = "";
for (let p of people.results) {
peopleHTML += `<div>${p.name}</div>`;
}
peopleDiv.innerHTML = peopleHTML;
const planetDiv = document.getElementById("planets");
let planetHTML = `<div>${planet.name}</div>`;
planetDiv.innerHTML = planetHTML;
}).catch(err => {
console.log(err);
});
<div id="people"></div>
<hr>
<div id="planets"></div>
As for using the results, the people URL returns a structure that looks like this:
{
count: 82,
next: 'https://swapi.dev/api/people/?page=2',
previous: null,
results: [
{
name: 'Luke Skywalker',
height: '172',
mass: '77',
hair_color: 'blond',
skin_color: 'fair',
eye_color: 'blue',
birth_year: '19BBY',
gender: 'male',
homeworld: 'https://swapi.dev/api/planets/1/',
films: [Array],
species: [],
vehicles: [Array],
starships: [Array],
created: '2014-12-09T13:50:51.644000Z',
edited: '2014-12-20T21:17:56.891000Z',
url: 'https://swapi.dev/api/people/1/'
},
{
name: 'C-3PO',
height: '167',
mass: '75',
hair_color: 'n/a',
skin_color: 'gold',
eye_color: 'yellow',
birth_year: '112BBY',
gender: 'n/a',
homeworld: 'https://swapi.dev/api/planets/1/',
films: [Array],
species: [Array],
vehicles: [],
starships: [],
created: '2014-12-10T15:10:51.357000Z',
edited: '2014-12-20T21:17:50.309000Z',
url: 'https://swapi.dev/api/people/2/'
}
}
So, you have people.results which is an array and you can access people.results[n] to get an item from that array. That item will be an object which has properties like .name, .height, etc...
The specific planet URL you show returns a single planet object like this:
{
name: 'Alderaan',
rotation_period: '24',
orbital_period: '364',
diameter: '12500',
climate: 'temperate',
gravity: '1 standard',
terrain: 'grasslands, mountains',
surface_water: '40',
population: '2000000000',
residents: [
'https://swapi.dev/api/people/5/',
'https://swapi.dev/api/people/68/',
'https://swapi.dev/api/people/81/'
],
films: [
'https://swapi.dev/api/films/1/',
'https://swapi.dev/api/films/6/'
],
created: '2014-12-10T11:35:48.479000Z',
edited: '2014-12-20T20:58:18.420000Z',
url: 'https://swapi.dev/api/planets/2/'
}
So, you access properties on that object as in planet.name.
Notice that the people results are paged. There are 82 total results, but only 10 come in this first result. The rest come with results for other pages such as https://swapi.dev/api/people/?page=2.
Similar to this answer but using async/await to avoid callback hell. If you can, try using this approach. Why?
Excellent recommendation in that answer by jfriend00 to use Promise.all instead of separate fetch calls, as that enables fetching to happen in parallel. To know more.
sandbox to test and try
const fetchData = async (...args) => {
try {
const response = await fetch(...args);
return response.json();
} catch (err) {
throw new Error(`fetch failed with status ${err?.message}`);
}
};
const updateDOM = (people, planet) => {
document.getElementById("people").innerHTML =
people.results.reduce((s, p) => s + `<div>${p.name}</div>`, "");
document.getElementById("planets").innerHTML = `<div>${planet.name}</div>`;
};
const populateData = async () => {
try {
const [people, planet] = await Promise.all([
fetchData("https://swapi.dev/api/people/"),
fetchData("https://swapi.dev/api/planets/2/"),
]);
// do stuff with 'people' or 'planet'
// example, get
// const firstPersonsHomeworld = people.results[0].homeworld;
// console.log(firstPersonsHomeworld);
// or
// const planetName = planet.name;
// console.log(planetName);
updateDOM(people, planet);
} catch (err) {
// errorHandler(err);
console.error(err);
}
};
// start app
populateData();
Related
I need help trying to access the data the is fetched from an API? The only thing I can do is game.results which I show lower. Everything else I try just outputs "undefined". I'm not sure what else to try that is why I am asking because I have runout of ways to fix this.
function showGames()
{
const options = {
method: 'GET',
headers: {
'X-RapidAPI-Host': 'sportspage-feeds.p.rapidapi.com',
'X-RapidAPI-Key': '<KEY>'
}
};
let url = 'https://sportspage-feeds.p.rapidapi.com/games?league=NBA&date=2022-04-28';
fetch(url, options)
.then(res => {
return res.json();
})
.then((data) => {
const games = data;
let game = games;
let result = `<h2> NBA GAMES</h2>`;
console.log(game.results);
for(let i = 0; i < game.length; i++)
{
thisGame = game[i];
result += `
<div>
<h1>${game.results.summary}</h1>
</div>
`;
}
document.getElementById("games").innerHTML = result;
});
}
window.onload=showGames();
This is what one of the outputs of data.results looks like. I'm not sure how I can access the data in here like summary. I've tried using game.results.summary but it just outputs undefined.
[ { schedule: { date: '2022-04-28T23:00:00.000Z', tbaTime: false },
summary: 'Philadelphia 76ers # Toronto Raptors',
details:
{ league: 'NBA',
seasonType: 'postseason',
season: 2021,
conferenceGame: true,
divisionGame: true },
status: 'final',
teams: { away: [Object], home: [Object] },
lastUpdated: '2022-04-29T01:38:41.138Z',
gameId: 284279,
venue:
{ name: 'Scotiabank Arena',
city: 'Toronto',
state: 'ON',
neutralSite: false },
odds: [ [Object] ],
scoreboard:
{ score: [Object],
currentPeriod: 4,
periodTimeRemaining: '0:00' } },
This statement in your loop:
game = game[i];
overwrites the array game and breaks the whole thing. You need a variable to use in the loop that is separate from the game array:
let thisGame = game[i];
I'm trying to render a page with some details I get from a api call.
useEffect(() =>{
getCards();
}, [])
const [userCards, setCards] = useState([])
const getCards = async (event) => {
let token = localStorage.getItem("user");
await api
.get("/fetch-card-balance",
{headers:{"token":`${token}`}})
.then((response) => {
console.log(response);
if (response.data.success === false) {
toast.error(response.data.message);
setCards(false);
} else if (response.data.success === true) {
console.log(response.data.payload)
setCards(response.data.payload)
}
})
.catch((err) => {
toast.error(err.response.data.message);
});
};
console.log(userCards)
Here userCards is logged as
[
{
balance: 0.00,
cifNumber: "0001111222",
createdAt: "2021-08-03T12:19:51.000Z",
first6: "123456",
id: 1234,
last4: "7890"
},
{
balance: 20.00,
cifNumber: "0002222333",
createdAt: "2021-07-03T12:19:51.000Z",
first6: "234567",
id: 2345,
last4: "8901"
}
]
Then I try to use forEach to filter the properties I need
const cardDetails = []
userCards.forEach(option => cardDetails.push(
{
cardNumber: `${option.first6}******${option.last4}`,
balance: `${option.balance}`
}
))
But when I run
console.log(cardDetails[0].balance)
I get "Uncaught TypeError: Cannot read property 'balance' of undefined". I've gone over it several times and the only conclusion I have is that I'm missing something that may not be so obvious. Could someone help point out what it is.
Using cardDetails[0].balance will only work when there is at least one element in cardDetails. Otherwise getting the first element in the array yields undefined, causing your error message. Since you only fill the array after the API request returns, at least your first render will be done with an empty array.
An easy way to handle this would be checking for if (cardDetails.length > 0) first.
Try this out
const cardDetails = userCards.map(function(option) { return {cardNumber: ${option.first6}******${option.last4}, balance: ${option.balance}}});
I am calling a recursive function that is returning an object, the object is being returned on each iteration.
I wish to only return an object once the recursive operation has completed. rather than on each iteration.
async fetchRecipe(recipe: any) {
console.log("fetchRecipe");
// Start with a root recipe
let rootRecipe: Recipe = {
id: recipe.id,
name: recipe.name,
ingredients: [],
childRecipes: []
}
// Kick off recursive function
let result = await this.recursivelyBuildRecipe(rootRecipe);
console.log("Fetch Recipe returned");
return result
}
async recursivelyBuildRecipe(recipe: Recipe) {
// fetches using the API
console.log("recursivelyBuildRecipe");
this.fetchChildren('http:///recipes/get_children', 'id=' + recipe.id)
.then(async x => {
await x.data.children.forEach((async(child: { type: any; ItemId: string; name: string; }) => {
switch (child.type) {
case 'ingredient':
// if ingredient
let ingredient: Ingredient = {
id: child.ItemId,
name: child.name,
unit: 1
}
this.allIngredients.push(ingredient);
recipe.ingredients.push(ingredient);
break
case 'recipe':
let subRecipe: Recipe = {
id: child.ItemId,
name: child.name,
ingredients: [],
childRecipes: []
}
await this.recursivelyBuildRecipe(subRecipe)
recipe.childRecipes.push(subRecipe)
break
}
}))
})
// This is returning the same amount of times the recursive function is called, I want it to only return once complete.
var obj = { "recipes": recipe, "ingredients": this.allIngredients }
return await obj;
async recursivelyBuildRecipe(recipe: Recipe) {
const fetch = await this.fetchChildren('http:///recipes/get_children', 'id=' + recipe.id);
const asyncRecipe = await fetch.data.children.reduce(async (accPromise,child) => {
const recipe = await accPromise;
switch(child.type) {
case 'ingredient':
let ingredient: Ingredient = {
id: child.ItemId,
name: child.name,
unit: 1
}
this.allIngredients.push(ingredient);
recipe.ingredients.push(ingredient);
break;
case 'recipe':
let subRecipe: Recipe = {
id: child.ItemId,
name: child.name,
ingredients: [],
childRecipes: []
}
await this.recursivelyBuildRecipe(subRecipe)
recipe.childRecipes.push(subRecipe)
break;
}
return recipe;
},Promise.resolve(recipe));
return { "recipes": asyncRecipe, "ingredients": this.allIngredients }
}
Don't mix Promises and async/await syntax. There's nothing technically incorrect about it, but it's terribly confusing.
You need to iterate over each of the children retrieved and await them. The easiest way to do this, in my opinion, is in a reduce. Although this results in serial retrieval of children - it returns a single object at the end and is easier to reason about. If it's not fast enough, you could do it better with a Promise.all and merge the results yourself.
I'm not sure that the above syntax is 100% correct, but you should be able to get the idea:
I'm not sure I understand specifics here, but it seems what you can do in general is:
Add await for the this.fetchChildren (otherwise it seems like you're getting results because of mutation, not on time).
Add a second boolean parameter to the recursive function (i.e isMainCall), pass it only for the first time (when you start recursion) and add the return in the end into if (isMainCall) return obj
I am chaining a bunch of axios get request to different endpoints of an API and I'm trying to create an array like this from the data (simplified):
[
{
name: "John",
id: 1,
gender: "male"
},
{
name: "Anna",
id: 2,
gender: "female"
},
]
In one of the requests I retrieve each person's name and id in an array like this:
[
{
name: "John",
id: 1
},
{
name: "Anna",
id: 2
},
]
Now I only need to get their gender by sending each persons's id in two separate requests to an endpoint.
I have spent hours trying to construct the array at the top with push() and then() but I just can't get it right.
How do I go about this?
I'm chaining the axios requests like this btw:
axios.get('api/' + endpoint1]).then(response => {
axios.get('api/' + endpoint2).then(response => {
axios.get('api/' + endpoint3).then(response => {
// and so on...
});
});
});
UPDATE 1:
I feel like I didn't explain the problem properly. This is what my code looks like right now, starting from the last promise. How can I change it in order to get the array at the top of my question?
.then(response => {
people= response.data; // Array of people including their name id (not their gender though)
for (var key in people) {
var person = {};
person["name"] = people[key].node.name;
person["id"] = people[key].node.id;
finalArray.push(person);
axios.get('api/' + endpoint3, { // Endpoint for getting a persons gender from id
params: {
personId: person.id
}
}).then(response => {
// I don't know what to do here...
});
}
console.log(finalArray); // Gives me an array of objects without "gender".
});
UPDATE 2:
Thanks alot for your answers!
I've combined some of your solutions and this is how my real code looks right now. The requests to http://api.ntjp.se/coop/api/v1/serviceProducers.json are not sent. Why?
I also don't want to keep the whole objects within the cooperations response array before calling http://api.ntjp.se/coop/api/v1/serviceProducers.json. I just want to save two specific key/value pairs from each object. These two key/value pairs are both within an object called "serviceContract" within in each response object. How do I save them?
<html>
<head>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<script>
getConnectionStatusData();
async function getConnectionStatusData() {
let serviceDomains = await axios.get('http://api.ntjp.se/coop/api/v1/serviceDomains.json', {
params: {
namespace: "crm:scheduling"
}
});
serviceDomainId = serviceDomains.data[0].id;
let connectionPoints = await axios.get('http://api.ntjp.se/coop/api/v1/connectionPoints.json', {
params: {
platform: "NTJP",
environment: "PROD"
}
});
connectionPointId = connectionPoints.data[0].id;
let logicalAddresss = await axios.get('http://api.ntjp.se/coop/api/v1/logicalAddresss.json', {
params: {
logicalAdress: "SE2321000016-167N",
serviceConsumerHSAId: "SE2321000016-92V4",
connectionPointId: connectionPointId
}
});
logicalAddressId = logicalAddresss.data[0].id;
let serviceConsumers = await axios.get('http://api.ntjp.se/coop/api/v1/serviceConsumers.json', {
params: {
connectionPointId: connectionPointId,
logicalAddressId: logicalAddressId
}
});
consumer = serviceConsumers.data.filter(obj => {
return obj.hsaId === "SE2321000016-92V4"
});
serviceConsumerId = consumer[0].id;
let cooperations = await axios.get('http://api.ntjp.se/coop/api/v1/cooperations.json', {
params: {
connectionPointId: connectionPointId,
logicalAddressId: logicalAddressId,
serviceDomainId: serviceDomainId,
serviceConsumerId: serviceConsumerId,
include: "serviceContract"
}
});
for(var idx in cooperations.data) {
var data = async () => { return await axios.get('http://api.ntjp.se/coop/api/v1/serviceProducers.json', {
params: {
connectionPointId: connectionPointId,
logicalAddressId: logicalAddressId,
serviceDomainId: serviceDomainId,
serviceConsumerId: serviceConsumerId,
serviceContractId: cooperations.data[idx].serviceContract.id
}
}) }
cooperations.data[idx].producerDescription = data.description;
cooperations.data[idx].producerHSAId = data.hsaId;
}
console.log(cooperations.data);
}
</script>
</body>
UPDATE 3
I finally made it work but why do I have to reference to the data like response.data[0].description when I push it into finalResult in the end? I mean, why doesn't just response.data.description work, as it does for #Cold Cerberus?
Other than that, is my code ok in or have I done something wrong?
Thanks guys!
<html>
<head>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<script>
getConnectionStatusData();
async function getConnectionStatusData() {
let serviceDomains = await axios.get('http://api.ntjp.se/coop/api/v1/serviceDomains.json', {
params: {
namespace: "crm:scheduling"
}
});
serviceDomainId = serviceDomains.data[0].id;
let connectionPoints = await axios.get('http://api.ntjp.se/coop/api/v1/connectionPoints.json', {
params: {
platform: "NTJP",
environment: "PROD"
}
});
connectionPointId = connectionPoints.data[0].id;
let logicalAddresss = await axios.get('http://api.ntjp.se/coop/api/v1/logicalAddresss.json', {
params: {
logicalAdress: "SE2321000016-167N",
serviceConsumerHSAId: "SE2321000016-92V4",
connectionPointId: connectionPointId
}
});
logicalAddressId = logicalAddresss.data[0].id;
let serviceConsumers = await axios.get('http://api.ntjp.se/coop/api/v1/serviceConsumers.json', {
params: {
connectionPointId: connectionPointId,
logicalAddressId: logicalAddressId
}
});
consumer = serviceConsumers.data.filter(obj => {
return obj.hsaId === "SE2321000016-92V4"
});
serviceConsumerId = consumer[0].id;
let cooperations = await axios.get('http://api.ntjp.se/coop/api/v1/cooperations.json', {
params: {
connectionPointId: connectionPointId,
logicalAddressId: logicalAddressId,
serviceDomainId: serviceDomainId,
serviceConsumerId: serviceConsumerId,
include: "serviceContract"
}
});
var finalData = [];
cooperations.data.forEach(function(cooperation) {
axios.get('http://api.ntjp.se/coop/api/v1/serviceProducers.json', {
params: {
connectionPointId: connectionPointId,
logicalAddressId: logicalAddressId,
serviceDomainId: serviceDomainId,
serviceConsumerId: serviceConsumerId,
serviceContractId: cooperation.serviceContract.id
}
}).then(response => {
finalData.push({serviceContract: cooperation.serviceContract.namespace, serviceProducerDescription: response.data[0].description, serviceProducerHSAId: response.data[0].hsaId});
});
});
console.log(finalData);
}
</script>
</body>
I'm not quite sure of your specific problem. But assuming that what you mean is you have two endpoints, first is the one that returns an array of object (lets call it 'getPeopleArray'):
[
{
name: "John",
id: 1
},
{
name: "Anna",
id: 2
}
]
and second endpoint returns the gender of the given id (lets call it 'getGender' with one param id), .push will not do the job for you.
Your problem can be solved with something like this:
let peopleArray = [];
axios.get('api/' + 'getPeopleArray').then(people => {
peopleArray = people;
people.forEach((person, index) => {
axios.get('api/' + 'getGender?id='.concat(person.id.toString()))
.then(gender => {
peopleArray[index].gender = gender;
});
});
});
First is you save the returned array of your first request and then you will have to loop through each object in that array to get and assign their genders from your second endpoint using the index argument of your [].forEach(callbackfn). As long as there is no manipulation with peopleArray during or before all requests are finished, the index will be correct.
Update 2:
In response to your question in the comments "why .push doesn't work?", I decided to make another approach If you want to end your algorithm with using .push and go without tracking indexes.
let peopleArray = [];
axios.get('api/' + 'getPeopleArray').then(people => {
people.forEach((person) => {
axios.get('api/' + 'getGender?id='.concat(person.id.toString()))
.then(gender => {
peopleArray.push({id: person.id, name: person.name, gender, gender});
});
});
});
This way you will only push your object to your collection peopleArray when its respective gender is also fetched. This will also eliminate having to use .map (as suggested in the comments) for storing only the individual object's properties you desire to keep since you pushed a new structured object on line peopleArray.push({id: person.id, name: person.name, gender, gender});.
I do not like to read chained promises and prefer to use async/await instead. You could get your list first and then loop through that list with a map and request the gender for each name. Remember that you have to wait for all promises to resolve inside your map before you can proceed.
const axios = require('axios');
async function getPeople() {
let firstResult = await axios.get('api/path/endpoint1');
// firstResult = [{name: "John", id: 1}, {name: "Anna", id: 2}]
let updatedResult = firstResult.map(async item => {
let people = await axios.get('api/path/endpoint2' + item.name); // or however your endpoint is designed
// people = {name: "John", id: 1, gender: male}
item.gender = people.gender;
return item;
});
// updatedResult = undefined
Promise.all(updatedResult)
.then(finalResult => console.log(finalResult));
// [{name: "John", id: 1, gender: male}, {name: "Anna", id: 2, gender: female}]
}
You can use async/awaits and reassign gender key to first endpoint data ...
var users;
axios.get('api/' + endpoint1]).then(response => {
users = response; // assume all user id list
for(var idx in users) {
var data = async () => { return await axios.get('api/' + users[idx].id) } //get gender api by user id
users[idx].gender = data.gender; //create gender key value
}
console.log(users);
});
I'm using the Star Wars API to practice, but I am running into a weird bug. I'm pretty sure I am the problem here but I don't know enough about these processes to find the issue.
I am creating profile cards with this info, but when I try to replace the homeworld url with the actual name, I am unable to change the value that appears in my react element.
This is a smaller version of the JSON object that I get from the API.
{
"name": "Luke Skywalker",
"height": "172",
"mass": "77",
"birth_year": "19BBY",
"gender": "male",
"homeworld": "https://swapi.co/api/planets/1/",
},
I was trying to replace the url value of homeworld with the name of the actual homeworld before saving it to my this.state array. I've tried making the fetch calls from the element files (that didn't really feel proper). So I hacked some code together and watched it change with console.log();. It's not the prettiest.
fetch('https://swapi.co/api/people/')
.then(response => {
return response.json();
})
.then(array => {
console.log(array.results);
Promise.all(array.results.map(character => {
console.log(character.homeworld)
let home_url = character.homeworld;
fetch(home_url)
.then(home => {return home.json()})
.then(home_json => character.homeworld = home_json.name)
}))
.then(() => {
console.log(array.results)
this.setState({characters:array.results})
});
});
The console.log(); shows that the value for homeworld was changed to the string 'Tatooine'. This is the same all the way down to the profile card. So I was expecting this to be the value in the card to be 'Tatooine', but I end up with "https://swapi.co/api/planets/1/".
At this point I don't know where my lack of knowledge is. I'm not sure if it is an issue with JSON, React, Fetch/Promises. So if anyone is able to offer some insight on this issue that would be great. I can add more code to the post if needed. Cheers!
You need to return something in each .then call in order to keep passing updated data along. Also in Promise.all( array.results.map( you should return each element so that you don't end up with an array full of undefined.
Here is an example of how you can do this (note I'd recommend using async/await for at least the Promise.all section):
componentDidMount() {
fetch("https://swapi.co/api/people/")
.then(response => response.json())
.then(array => {
console.log(array.results);
return Promise.all(array.results.map(async character => {
console.log(character.homeworld);
const homeUrl = character.homeworld;
const home = await fetch(homeUrl);
const homeJson = await home.json();
return {
...character,
homeworld: homeJson,
}
}));
})
.then(characters => {
console.log(characters);
this.setState({ characters });
})
}
Again using async/await everywhere:
componentDidMount() {
this.fetchData();
}
async fetchData() {
const response = await fetch("https://swapi.co/api/people/");
const array = await response.json();
console.log(array.results);
const characters = await Promise.all(array.results.map(async character => {
console.log(character.homeworld);
const homeUrl = character.homeworld;
const home = await fetch(homeUrl);
const homeJson = await home.json();
return {
...character,
homeworld: homeJson,
}
}));
console.log(characters);
this.setState({ characters });
}
Then this.state.characters is an array of length 10. Here is a sample element:
{
birth_year: "41.9BBY"
created: "2014-12-10T15:18:20.704000Z"
edited: "2014-12-20T21:17:50.313000Z"
eye_color: "yellow"
films: (4) ["https://swapi.co/api/films/2/", "https://swapi.co/api/films/6/", "https://swapi.co/api/films/3/", "https://swapi.co/api/films/1/"]
gender: "male"
hair_color: "none"
height: "202"
homeworld: {name: "Tatooine", rotation_period: "23", orbital_period: "304", diameter: "10465", climate: "arid", …}
mass: "136"
name: "Darth Vader"
skin_color: "white"
species: ["https://swapi.co/api/species/1/"]
starships: ["https://swapi.co/api/starships/13/"]
url: "https://swapi.co/api/people/4/"
vehicles: []
}