javascript – How to access JSON API from a link in another API (Json Data have link to another Json)

Im not sure if you got your problem resolved so I created a demo to point you in the right direction. To simulate your api and use your data table, I used a cat fact api with cat breeds as business names, string lengths as prices, and random strings as business ids. To simulate an api giving a link to another api I created this:

// api to simulate your api
export default async function (url,{query={},onSuccess,onFail,onComplete}){
  let res, json ={};
  try{
    url= new URL(url)
    res = await fetch(url)
    res = await res?.join?.() || res;
    res = await res.json();
    json = {
      articles:res.articles || generateArticles(res.data),
      nextLink:res.next_page_url,
      prevLink:res.prev_page_url,
      page:res.current_page
    }
    //hipolab api was having network resource issues
    const apiIsWorking = false
    // if hipo api doesnt work just load the github json
    json.otherApi = apiIsWorking 
      ?'http://universities.hipolabs.com/search'
      :'https://raw.githubusercontent.com/Hipo/university-domains-list/master/world_universities_and_domains.json';
    // here would be where you setData
    onSuccess?.(json);
    
  }catch(err){
    onFail(err)
  }finally{
    // here would be where you setLoading
    onComplete?.(json)
  }
}
// to simulate your api i will try to convert cat facts
// into something your data table will render
const generateArticles = data=>{
  return data.map(item=>{
    let keys = Object.keys(item)
    return {
      businessid:getRandomChars(3)+'-'+Math.floor(getRandom(0,999)).toString().padStart(3,'0'),
      title:item.breed || item[keys[0]],
      price:item.pattern.length ||  item[keys[1]].length,
      country:item.country
    }
  })
}
export const getRandomChars=(len=1)=>{
  const characters="abcdefghijklmnopqrstuvwxyz"
  let str=""
  while (str.length < len){
    let index = Math.floor(getRandom(0,characters.length))
    str+=characters[index].toUpperCase()
  }
  return str
}
const getRandom = (min=0,max=1)=>{
  let range = max - min
  return Math.random() * range + min
}

Which is imported here:

import React,{
  useEffect,
  useState
} from 'react';
import { 
  Text,
  View,
  StyleSheet,
  SafeAreaView,
  ScrollView,
  FlatList,
} from 'react-native';
import Constants from 'expo-constants';
import { Card, DataTable } from 'react-native-paper';

import api from '../api/first';
import COLORS from '../colors';
import RenderCollection from '../components/ListItem';
import Button from '../components/Button'
import ListHeader from '../components/ListHeader'

export default function List({navigation,route}) {
  const [data,setData] = useState([])
  const [loading,setLoading]= useState(true);

  const fetchData = (url="https://catfact.ninja/breeds")=>{
    api(url,{
      onSuccess:res=>{
        // console.log('Success!n',JSON.stringify(res,null,2))
        setData(res)
      },
      onFail:err=>{
        console.log('Failure!n',err)
      },
      onComplete:res=>{
        // console.log('Success!n',JSON.stringify(res,null,2))
        setLoading(false)
      }
    })
  }
  const next=()=>{
    if(data.nextLink){
      fetchData(data.nextLink)   
    }
  }
  const prev=()=>{
    if(data.prevLink){
      fetchData(data.prevLink)
    }
  }
  const RenderItem=({item,index})=>{
    return (
      <RenderCollection otherApi={data.otherApi} item={item} navigation={navigation} index={index}/>
    )
  }

  useEffect(()=>{
    fetchData()
  },[])
  // listen for route param changes and update
  // data when it does change
  useEffect(()=>{
    const {item, index} = route.params || {}
    if(!item ){
      console.log('no item to update')
      return
    }
    if(isNaN(index)){
      console.log('no index passed to update')
      return
    }
    const articles = [...data.articles];
    articles[index] = item
    setData({...data,articles})
  },[route.params?.item])
  return (
   <SafeAreaView style={{ flex: 1}}>
      <Text style={{color: COLORS.black, fontSize: 40, fontWeight: 'bold', fontFamily: 'Roboto',textAlign: 'center'}}>
        List of Companies
      </Text>
      <Text style={{color: COLORS.grey, fontSize: 18, marginVertical: 10, fontFamily: 'Roboto', textAlign: 'center'}}>
        Check Our Companies Details
      </Text>
        <View style={styles.buttonRow}>
        <View style={styles.rowItem}>
          <Button title="Prev" onPress={prev} disabled={!data.prevLink}/>
        </View>
        <View style={styles.rowItem}>
          <Text>Page {data.page}</Text>
        </View>
        <View style={styles.rowItem}>
          <Button title="Next" onPress={next} disabled={!data.nextLink}/>
        </View>
      </View>
      <View style={styles.dataTableWrapper}>
        <DataTable style={{flex:1}}>
          <FlatList
            style={{flex:1}}
            data={data.articles}
            renderItem={RenderItem}
            keyExtractor={item=>item.businessid}
            onRefresh={()=>fetchData()}
            refreshing={loading}
            ListHeaderComponent={ListHeader}
            stickyHeaderIndices={[0]}
          />
        </DataTable>
      </View>
  </SafeAreaView>
  );
}

const styles = StyleSheet.create({

  dataTableWrapper:{
    height:'40%',
    width:'100%',
    overflow:'hidden'

  },
  buttonRow:{
    marginVertical:5,
    flexDirection:'row',
    width:'100%',
    justifyContent:'space-between'
  },
  rowItem:{
    justifyContent:'center',
    alignItems:'center',
  },

});

To summarize, the first api returns a list of cat breeds, links to the prev/next page of the list, and a link to an api for getting universities of a country. Each cat breed has a country property. So I joined the two:

import React from 'react';
import {
  StyleSheet
} from 'react-native';
import {DataTable, useTheme} from 'react-native-paper';
import tableStyle from './tableStlye';
import {lightenColor} from '../colors'
export default function({item,index,navigation,otherApi}){
  const colors = useTheme().colors
  const mainColor = colors.primary;
  const lightColor1 = lightenColor(mainColor,0.35)
  const lightColor2 = lightenColor(mainColor,0.5)
  let themedStyle ={
    borderBottomWidth:1,
    backgroundColor:index%2== 0  ?lightColor2 : lightColor1
  }
  return(
    <DataTable.Row style={[styles.tableRow,themedStyle]} key={item.businessid}>
      <DataTable.Cell 
        textStyle={{color: '#777777',fontFamily: 'Roboto'}}
        style={tableStyle.id}
        onPress={() => navigation.navigate("Edit",{item,key:'businessid',index})}
      >
        {item.businessid}
      </DataTable.Cell>
      {/* HERE THE API IS SENT TO THE NEXT SCREEN */}
      <DataTable.Cell 
        textStyle={{color: '#FEB296', fontFamily: 'Roboto'}}
        style={tableStyle.title}
        onPress={()=>navigation.navigate("Universities",{item,otherApi})}
      >
        {item.title}
      </DataTable.Cell>
      <DataTable.Cell 
        style={tableStyle.price}
        textStyle={{color: '#777777', fontFamily: 'Roboto'}}
      >
        {item.price}
      </DataTable.Cell>
    </DataTable.Row>
  )
}

const styles = StyleSheet.create({
  tableHeader: {
    backgroundColor: '#50E3C2',
  },
  tableRow: {
    backgroundColor: '#fff',
  },
})

And finally the universities screen:

import React,{
  useState,
  useEffect,
  useRef
} from 'react';
import {
  View,
  StyleSheet,
  Text,
  FlatList
} from 'react-native';
import {useTheme, Headline} from 'react-native-paper';
import {getRandomChars} from '../api/first';
import api from '../api/second';
import UniversityItem from '../components/UniversityItem';
import TextInput from '../components/TextInput';
import Button from '../components/Button';
import {lightenColor} from '../colors';
const fakeRouteParams = {
  item:{
    country:"United States",
  },
  otherApi:'https://raw.githubusercontent.com/Hipo/university-domains-list/master/world_universities_and_domains.json'
}
export default function Universities({navigaton,route}){
  const {item,otherApi} = route?.params || fakeRouteParams;
  const [universities, setUniversites] = useState([]);

  const [isLoading, setIsLoading] = useState(false);
  const [uniFilter, setUniFilter] = useState('');
  const filteredUniversities = uniFilter
    ? universities.filter(uni=>uni.name.toLowerCase().includes(uniFilter.toLowerCase()))
    : universities
  const colors = useTheme().colors;
  const mainColor = colors.primary;
  const lightColor = lightenColor(mainColor,0.5)
 
  const fetchData = async()=>{
    setIsLoading(true);
    await api(otherApi,{
      query:{
        country:item.country,
        limit:50
      },
      onSuccess:res=>{
        setUniversites(res)
      },
      onFail:err=>{
        console.log(err)
        alert(err)
        setIsLoading(false)
      },
      onComplete:()=>{
        setIsLoading(false)
      }
    })
  }
  
  useEffect(()=>{
    fetchData()
  },[])
  useEffect(()=>{
    
  },[uniFilter])
  return (
    <View style={styles.container}>
      <View style={[styles.title,{borderColor:colors.primary}]}>
        <Text style={styles.titleText}>{item.country+"'s"} Universities</Text>
      </View>

      <View style={styles.flatListContainer}>
        <TextInput
          label="Search By Name"
          style={{width:'95%'}}
          onChangeText={setUniFilter}
          value={uniFilter}
          dense
        />
        <FlatList
          style={{flex:1}}
          data={filteredUniversities}
          renderItem={props=><UniversityItem {...props} colors={[mainColor,lightColor]}/>}
          keyExtractor={(item,index)=>index+'-'+getRandomChars(10)}
          refreshing={isLoading}
          onRefresh={fetchData}
        />
      </View>
    </View>
  )
}

const styles=StyleSheet.create({
  container:{
    flex:1,
    // justifyContent:'center',
    // alignItems:'center'
  },
  flatListContainer:{
    width:'95%',
    height:'60%',
    alignItems:'center'
  },
  title:{
    width:'100%',
    borderBottomWidth:2
  },
  titleText:{
    fontWeight:'bold',
    fontSize:20,
    textAlign:'center'
  },
  header:{
    flexDirection:'row',
    width:'95%',
    alignItems:'center',
    justifyContent:'space-between',
    padding:5,
  }
})

Leave a Comment