Add IUCN API v4 support and token validation. Enhance API token management to include IUCN tokens and improve error handling.
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/c394ef36-207a-4d21-9177-2073a33ff7ed.jpg
This commit is contained in:
@ -7,7 +7,10 @@ import { ZodError } from "zod";
|
||||
import { fromZodError } from "zod-validation-error";
|
||||
|
||||
const CITES_BASE_URL = "https://api.speciesplus.net/api/v1";
|
||||
const IUCN_BASE_URL = "https://apiv3.iucnredlist.org/api/v3";
|
||||
|
||||
// IUCN API versions
|
||||
const IUCN_V3_BASE_URL = "https://apiv3.iucnredlist.org/api/v3";
|
||||
const IUCN_V4_BASE_URL = "https://apiv4.iucnredlist.org/api/v4";
|
||||
|
||||
export async function registerRoutes(app: Express): Promise<Server> {
|
||||
// API Token routes
|
||||
@ -16,7 +19,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
const tokenData = insertApiTokenSchema.parse(req.body);
|
||||
const savedToken = await storage.saveApiToken(tokenData);
|
||||
|
||||
// Validate the token by making a test request to CITES API
|
||||
// Validate the CITES token by making a test request to CITES API
|
||||
try {
|
||||
await axios.get(`${CITES_BASE_URL}/taxon_concepts`, {
|
||||
headers: {
|
||||
@ -24,12 +27,28 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
}
|
||||
});
|
||||
|
||||
// If IUCN token is provided, validate it as well
|
||||
if (tokenData.iucnToken) {
|
||||
try {
|
||||
await axios.get(`${IUCN_V4_BASE_URL}/version`, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${tokenData.iucnToken}`
|
||||
}
|
||||
});
|
||||
} catch (iucnError) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: "Invalid IUCN API token. Please check and try again."
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
res.json({ success: true, token: savedToken });
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error) && error.response) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: "Invalid API token. Please check and try again."
|
||||
message: "Invalid CITES API token. Please check and try again."
|
||||
});
|
||||
}
|
||||
throw error;
|
||||
@ -52,7 +71,10 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
app.get("/api/token", async (req: Request, res: Response) => {
|
||||
try {
|
||||
const token = await storage.getActiveToken();
|
||||
res.json({ token: token?.token || null });
|
||||
res.json({
|
||||
token: token?.token || null,
|
||||
iucnToken: token?.iucnToken || null
|
||||
});
|
||||
} catch (error) {
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
@ -266,6 +288,32 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
// IUCN API Status check endpoint
|
||||
app.get("/api/iucn/status", async (req: Request, res: Response) => {
|
||||
try {
|
||||
// Try V4 API first (with bearer token)
|
||||
const activeToken = await storage.getActiveToken();
|
||||
if (activeToken?.iucnToken) {
|
||||
// Use the version endpoint which is the simplest endpoint
|
||||
const versionUrl = `${IUCN_V4_BASE_URL}/version`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(versionUrl, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${activeToken.iucnToken}`
|
||||
}
|
||||
});
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
connected: true,
|
||||
apiVersion: "v4",
|
||||
message: "IUCN API v4 is connected and responding"
|
||||
});
|
||||
} catch (error) {
|
||||
// If V4 fails, fall back to checking V3 with environment API key
|
||||
console.log("IUCN V4 API check failed, falling back to V3:", error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to V3 API (with query parameter token)
|
||||
const apiKey = process.env.IUCN_API_KEY;
|
||||
if (!apiKey) {
|
||||
return res.status(401).json({
|
||||
@ -275,9 +323,8 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
});
|
||||
}
|
||||
|
||||
// Use the version endpoint which is the simplest endpoint
|
||||
// This is the most reliable endpoint as it doesn't need a species name
|
||||
const versionUrl = `${IUCN_BASE_URL}/version`;
|
||||
// Use the version endpoint for V3
|
||||
const versionUrl = `${IUCN_V3_BASE_URL}/version`;
|
||||
|
||||
try {
|
||||
// Make sure we're not including any parameters in the URL itself - only in params object
|
||||
@ -288,7 +335,8 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
res.json({
|
||||
success: true,
|
||||
connected: true,
|
||||
message: "IUCN API is connected and responding"
|
||||
apiVersion: "v3",
|
||||
message: "IUCN API v3 is connected and responding"
|
||||
});
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error) && error.response) {
|
||||
@ -338,7 +386,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
const simplifiedName = nameParts.slice(0, 2).join(' ');
|
||||
|
||||
try {
|
||||
const response = await axios.get(`${IUCN_BASE_URL}/species/name/${encodeURIComponent(simplifiedName)}`, {
|
||||
const response = await axios.get(`${IUCN_V3_BASE_URL}/species/name/${encodeURIComponent(simplifiedName)}`, {
|
||||
params: { token: apiKey }
|
||||
});
|
||||
|
||||
@ -389,7 +437,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
const simplifiedName = nameParts.slice(0, 2).join(' ');
|
||||
|
||||
try {
|
||||
const response = await axios.get(`${IUCN_BASE_URL}/threats/species/name/${encodeURIComponent(simplifiedName)}`, {
|
||||
const response = await axios.get(`${IUCN_V3_BASE_URL}/threats/species/name/${encodeURIComponent(simplifiedName)}`, {
|
||||
params: { token: apiKey }
|
||||
});
|
||||
|
||||
@ -440,7 +488,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
const simplifiedName = nameParts.slice(0, 2).join(' ');
|
||||
|
||||
try {
|
||||
const response = await axios.get(`${IUCN_BASE_URL}/habitats/species/name/${encodeURIComponent(simplifiedName)}`, {
|
||||
const response = await axios.get(`${IUCN_V3_BASE_URL}/habitats/species/name/${encodeURIComponent(simplifiedName)}`, {
|
||||
params: { token: apiKey }
|
||||
});
|
||||
|
||||
@ -491,7 +539,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
const simplifiedName = nameParts.slice(0, 2).join(' ');
|
||||
|
||||
try {
|
||||
const response = await axios.get(`${IUCN_BASE_URL}/measures/species/name/${encodeURIComponent(simplifiedName)}`, {
|
||||
const response = await axios.get(`${IUCN_V3_BASE_URL}/measures/species/name/${encodeURIComponent(simplifiedName)}`, {
|
||||
params: { token: apiKey }
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user