From 30607e78fd33ce9517979c7ded933c60dc54d218 Mon Sep 17 00:00:00 2001 From: Magnus-SmariSma <20734986-Magnus-SmariSma@users.noreply.replit.com> Date: Thu, 20 Mar 2025 23:14:23 +0000 Subject: [PATCH] Refactor: Update IUCN API integration to use v4 API and handle token authentication. Replit-Commit-Author: Agent Replit-Commit-Session-Id: e931b5ab-041b-42e7-baf1-50017869cef6 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/e19c6a51-7e4c-4bb8-a6a6-46dc00f0ec99/7e887f15-a417-4702-b9ec-027ae572bb88.jpg --- server/routes.ts | 333 +++++++++++++++++++++-------------------------- 1 file changed, 150 insertions(+), 183 deletions(-) diff --git a/server/routes.ts b/server/routes.ts index a1371b3..4826c07 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -438,85 +438,74 @@ export async function registerRoutes(app: Express): Promise { }); } - // To avoid 414 errors, we'll limit the name parameter to just the genus and species + // Extract genus and species for v4 API query const nameParts = String(name).split(' '); - const simplifiedName = nameParts.slice(0, 2).join(' '); const [genusName, speciesName] = nameParts; - // Try with v4 API first if we have a token + // Get IUCN token const activeToken = await storage.getActiveToken(); - if (activeToken?.iucnToken) { - try { - // First, we need to find the species taxon ID using scientific name lookup - const taxaResponse = await axios.get(`${IUCN_V4_BASE_URL}/taxa/scientific_name`, { - headers: { - "Authorization": `Bearer ${activeToken.iucnToken}` - }, - params: { - genus_name: genusName, - species_name: speciesName || "" - } - }); - - // Check if we found the species - if (taxaResponse.data && taxaResponse.data.result && taxaResponse.data.result.length > 0) { - const taxonId = taxaResponse.data.result[0].taxonid; - - // Now retrieve the threats using the taxon ID - const threatsResponse = await axios.get(`${IUCN_V4_BASE_URL}/threats/species/id/${taxonId}`, { - headers: { - "Authorization": `Bearer ${activeToken.iucnToken}` - } - }); - - return res.json({ - success: true, - data: threatsResponse.data, - apiVersion: "v4" - }); - } - // If no species found, fall back to v3 - console.log("IUCN V4 API: No species found with the given scientific name, falling back to V3"); - } catch (error: any) { - console.log("IUCN V4 API threats lookup failed, falling back to V3:", error.message); - // Continue to v3 fallback - } - } - - // Fallback to v3 API - const apiKey = process.env.IUCN_API_KEY; - if (!apiKey) { + if (!activeToken?.iucnToken) { return res.status(401).json({ success: false, - connected: false, - message: "IUCN API key is not configured" + message: "IUCN API v4 token is not configured. Please set your token in the API Token panel." }); } try { - const response = await axios.get(`${IUCN_V3_BASE_URL}/threats/species/name/${encodeURIComponent(simplifiedName)}`, { - params: { token: apiKey } + // First, we need to find the species taxon ID using scientific name lookup + const taxaResponse = await axios.get("https://apiv4.iucnredlist.org/api/v4/taxa/scientific_name", { + headers: { + "Authorization": `Bearer ${activeToken.iucnToken}` + }, + params: { + genus_name: genusName, + species_name: speciesName || "" + } }); - res.json({ - success: true, - data: response.data, - apiVersion: "v3" - }); - } catch (error) { - if (axios.isAxiosError(error) && error.response) { - return res.status(error.response.status).json({ - success: false, - message: error.response.data?.message || "Error from IUCN Red List API", - status: error.response.status + // Check if we found the species + if (!taxaResponse.data?.result || taxaResponse.data.result.length === 0) { + return res.status(404).json({ + success: false, + message: `No species found with the name "${name}" in the IUCN Red List database.` }); } - throw error; + + const taxonId = taxaResponse.data.result[0].taxonid; + + // Now retrieve the threats using the taxon ID + const threatsResponse = await axios.get(`https://apiv4.iucnredlist.org/api/v4/threats/species/id/${taxonId}`, { + headers: { + "Authorization": `Bearer ${activeToken.iucnToken}` + } + }); + + return res.json({ + success: true, + data: threatsResponse.data, + apiVersion: "v4" + }); + } catch (error: any) { + console.log("IUCN API threats lookup failed:", error.message); + + if (error.response?.status === 401) { + return res.status(401).json({ + success: false, + message: "IUCN API v4 token is invalid. Please check your token and try again." + }); + } + + return res.status(error.response?.status || 500).json({ + success: false, + message: error.response?.data?.message || "Error from IUCN Red List API: " + error.message, + status: error.response?.status + }); } } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); res.status(500).json({ success: false, - message: "Failed to retrieve IUCN threats data" + message: "Failed to retrieve IUCN threats data: " + errorMessage }); } }); @@ -532,85 +521,74 @@ export async function registerRoutes(app: Express): Promise { }); } - // To avoid 414 errors, we'll limit the name parameter to just the genus and species + // Extract genus and species for v4 API query const nameParts = String(name).split(' '); - const simplifiedName = nameParts.slice(0, 2).join(' '); const [genusName, speciesName] = nameParts; - // Try with v4 API first if we have a token + // Get IUCN token const activeToken = await storage.getActiveToken(); - if (activeToken?.iucnToken) { - try { - // First, we need to find the species taxon ID using scientific name lookup - const taxaResponse = await axios.get(`${IUCN_V4_BASE_URL}/taxa/scientific_name`, { - headers: { - "Authorization": `Bearer ${activeToken.iucnToken}` - }, - params: { - genus_name: genusName, - species_name: speciesName || "" - } - }); - - // Check if we found the species - if (taxaResponse.data && taxaResponse.data.result && taxaResponse.data.result.length > 0) { - const taxonId = taxaResponse.data.result[0].taxonid; - - // Now retrieve the habitats using the taxon ID - const habitatsResponse = await axios.get(`${IUCN_V4_BASE_URL}/habitats/species/id/${taxonId}`, { - headers: { - "Authorization": `Bearer ${activeToken.iucnToken}` - } - }); - - return res.json({ - success: true, - data: habitatsResponse.data, - apiVersion: "v4" - }); - } - // If no species found, fall back to v3 - console.log("IUCN V4 API: No species found with the given scientific name, falling back to V3"); - } catch (error: any) { - console.log("IUCN V4 API habitats lookup failed, falling back to V3:", error.message); - // Continue to v3 fallback - } - } - - // Fallback to v3 API - const apiKey = process.env.IUCN_API_KEY; - if (!apiKey) { + if (!activeToken?.iucnToken) { return res.status(401).json({ success: false, - connected: false, - message: "IUCN API key is not configured" + message: "IUCN API v4 token is not configured. Please set your token in the API Token panel." }); } try { - const response = await axios.get(`${IUCN_V3_BASE_URL}/habitats/species/name/${encodeURIComponent(simplifiedName)}`, { - params: { token: apiKey } + // First, we need to find the species taxon ID using scientific name lookup + const taxaResponse = await axios.get("https://apiv4.iucnredlist.org/api/v4/taxa/scientific_name", { + headers: { + "Authorization": `Bearer ${activeToken.iucnToken}` + }, + params: { + genus_name: genusName, + species_name: speciesName || "" + } }); - res.json({ - success: true, - data: response.data, - apiVersion: "v3" - }); - } catch (error) { - if (axios.isAxiosError(error) && error.response) { - return res.status(error.response.status).json({ - success: false, - message: error.response.data?.message || "Error from IUCN Red List API", - status: error.response.status + // Check if we found the species + if (!taxaResponse.data?.result || taxaResponse.data.result.length === 0) { + return res.status(404).json({ + success: false, + message: `No species found with the name "${name}" in the IUCN Red List database.` }); } - throw error; + + const taxonId = taxaResponse.data.result[0].taxonid; + + // Now retrieve the habitats using the taxon ID + const habitatsResponse = await axios.get(`https://apiv4.iucnredlist.org/api/v4/habitats/species/id/${taxonId}`, { + headers: { + "Authorization": `Bearer ${activeToken.iucnToken}` + } + }); + + return res.json({ + success: true, + data: habitatsResponse.data, + apiVersion: "v4" + }); + } catch (error: any) { + console.log("IUCN API habitats lookup failed:", error.message); + + if (error.response?.status === 401) { + return res.status(401).json({ + success: false, + message: "IUCN API v4 token is invalid. Please check your token and try again." + }); + } + + return res.status(error.response?.status || 500).json({ + success: false, + message: error.response?.data?.message || "Error from IUCN Red List API: " + error.message, + status: error.response?.status + }); } } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); res.status(500).json({ success: false, - message: "Failed to retrieve IUCN habitats data" + message: "Failed to retrieve IUCN habitats data: " + errorMessage }); } }); @@ -626,85 +604,74 @@ export async function registerRoutes(app: Express): Promise { }); } - // To avoid 414 errors, we'll limit the name parameter to just the genus and species + // Extract genus and species for v4 API query const nameParts = String(name).split(' '); - const simplifiedName = nameParts.slice(0, 2).join(' '); const [genusName, speciesName] = nameParts; - // Try with v4 API first if we have a token + // Get IUCN token const activeToken = await storage.getActiveToken(); - if (activeToken?.iucnToken) { - try { - // First, we need to find the species taxon ID using scientific name lookup - const taxaResponse = await axios.get(`${IUCN_V4_BASE_URL}/taxa/scientific_name`, { - headers: { - "Authorization": `Bearer ${activeToken.iucnToken}` - }, - params: { - genus_name: genusName, - species_name: speciesName || "" - } - }); - - // Check if we found the species - if (taxaResponse.data && taxaResponse.data.result && taxaResponse.data.result.length > 0) { - const taxonId = taxaResponse.data.result[0].taxonid; - - // Now retrieve the conservation measures using the taxon ID - const measuresResponse = await axios.get(`${IUCN_V4_BASE_URL}/measures/species/id/${taxonId}`, { - headers: { - "Authorization": `Bearer ${activeToken.iucnToken}` - } - }); - - return res.json({ - success: true, - data: measuresResponse.data, - apiVersion: "v4" - }); - } - // If no species found, fall back to v3 - console.log("IUCN V4 API: No species found with the given scientific name, falling back to V3"); - } catch (error: any) { - console.log("IUCN V4 API conservation measures lookup failed, falling back to V3:", error.message); - // Continue to v3 fallback - } - } - - // Fallback to v3 API - const apiKey = process.env.IUCN_API_KEY; - if (!apiKey) { + if (!activeToken?.iucnToken) { return res.status(401).json({ success: false, - connected: false, - message: "IUCN API key is not configured" + message: "IUCN API v4 token is not configured. Please set your token in the API Token panel." }); } try { - const response = await axios.get(`${IUCN_V3_BASE_URL}/measures/species/name/${encodeURIComponent(simplifiedName)}`, { - params: { token: apiKey } + // First, we need to find the species taxon ID using scientific name lookup + const taxaResponse = await axios.get("https://apiv4.iucnredlist.org/api/v4/taxa/scientific_name", { + headers: { + "Authorization": `Bearer ${activeToken.iucnToken}` + }, + params: { + genus_name: genusName, + species_name: speciesName || "" + } }); - res.json({ - success: true, - data: response.data, - apiVersion: "v3" - }); - } catch (error) { - if (axios.isAxiosError(error) && error.response) { - return res.status(error.response.status).json({ - success: false, - message: error.response.data?.message || "Error from IUCN Red List API", - status: error.response.status + // Check if we found the species + if (!taxaResponse.data?.result || taxaResponse.data.result.length === 0) { + return res.status(404).json({ + success: false, + message: `No species found with the name "${name}" in the IUCN Red List database.` }); } - throw error; + + const taxonId = taxaResponse.data.result[0].taxonid; + + // Now retrieve the conservation measures using the taxon ID + const measuresResponse = await axios.get(`https://apiv4.iucnredlist.org/api/v4/measures/species/id/${taxonId}`, { + headers: { + "Authorization": `Bearer ${activeToken.iucnToken}` + } + }); + + return res.json({ + success: true, + data: measuresResponse.data, + apiVersion: "v4" + }); + } catch (error: any) { + console.log("IUCN API conservation measures lookup failed:", error.message); + + if (error.response?.status === 401) { + return res.status(401).json({ + success: false, + message: "IUCN API v4 token is invalid. Please check your token and try again." + }); + } + + return res.status(error.response?.status || 500).json({ + success: false, + message: error.response?.data?.message || "Error from IUCN Red List API: " + error.message, + status: error.response?.status + }); } } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); res.status(500).json({ success: false, - message: "Failed to retrieve IUCN conservation measures data" + message: "Failed to retrieve IUCN conservation measures data: " + errorMessage }); } });