Remove support for IUCN API v3; update to use only v4 and improve token validation.
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/c86608db-9b9f-432d-9898-0faedcc6199e.jpg
This commit is contained in:
@ -0,0 +1,58 @@
|
|||||||
|
Got it, you need the essential information to use the IUCN Red List API V4, without the code. Here's a concise guide:
|
||||||
|
|
||||||
|
**1. Base URL:**
|
||||||
|
|
||||||
|
* The base URL for all API requests is: `https://apiv4.iucnredlist.org`
|
||||||
|
|
||||||
|
**2. Authentication:**
|
||||||
|
|
||||||
|
* The API uses Bearer token authentication.
|
||||||
|
* You'll need to include an `Authorization` header in your HTTP requests.
|
||||||
|
* The header value should be: `Bearer YOUR_API_TOKEN` (replace `YOUR_API_TOKEN` with your actual token).
|
||||||
|
|
||||||
|
**3. Common Endpoints and Parameters:**
|
||||||
|
|
||||||
|
Here are a few common endpoints with examples of parameters you can pass:
|
||||||
|
|
||||||
|
* **Get a list of biogeographical realms:**
|
||||||
|
* Endpoint: `GET /api/v4/biogeographical_realms/`
|
||||||
|
* No parameters needed.
|
||||||
|
* **Get assessments for a biogeographical realm:**
|
||||||
|
* Endpoint: `GET /api/v4/biogeographical_realms/{code}` (replace `{code}` with the realm code, e.g., `NT`)
|
||||||
|
* Parameters (query parameters):
|
||||||
|
* `page`: Page number (integer).
|
||||||
|
* `year_published`: Filter by year published (integer).
|
||||||
|
* `latest`: Filter by latest (boolean).
|
||||||
|
* `possibly_extinct`: Filter by possibly extinct (boolean).
|
||||||
|
* `possibly_extinct_in_the_wild`: Filter by possibly extinct in the wild (boolean).
|
||||||
|
* `scope_code`: Filter by scope code (integer).
|
||||||
|
* **Get taxa by scientific name:**
|
||||||
|
* Endpoint: `GET /api/v4/taxa/scientific_name`
|
||||||
|
* Parameters (query parameters):
|
||||||
|
* `genus_name`: The genus name (string, required).
|
||||||
|
* `species_name`: The species name (string, required).
|
||||||
|
* `infra_name`: The infra-name (string, optional).
|
||||||
|
* `subpopulation_name`: The subpopulation name (string, optional).
|
||||||
|
* **Get assessments by kingdom name:**
|
||||||
|
* Endpoint: `GET /api/v4/taxa/kingdom/{kingdom_name}` (replace `{kingdom_name}` with the kingdom name, e.g., `Animalia`)
|
||||||
|
* Parameters (query parameters):
|
||||||
|
* `page`: Page number (integer).
|
||||||
|
* `year_published`: Filter by year published (integer).
|
||||||
|
* `latest`: Filter by latest (boolean).
|
||||||
|
* `scope_code`: Filter by scope code (integer).
|
||||||
|
|
||||||
|
**4. Request Example (using cURL):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -H "Authorization: Bearer YOUR_API_TOKEN" "https://apiv4.iucnredlist.org/api/v4/biogeographical_realms/NT?page=1"
|
||||||
|
```
|
||||||
|
|
||||||
|
**5. Response Format:**
|
||||||
|
|
||||||
|
* The API returns JSON responses.
|
||||||
|
|
||||||
|
**Important Notes:**
|
||||||
|
|
||||||
|
* Replace `YOUR_API_TOKEN` with your actual token.
|
||||||
|
* Refer to the official API documentation for a complete list of endpoints and parameters.
|
||||||
|
* The API documentation will also provide example responses, which will help you understand the returned data.
|
@ -9,17 +9,14 @@ export const CITES_API_ENDPOINTS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const IUCN_API_ENDPOINTS = {
|
export const IUCN_API_ENDPOINTS = {
|
||||||
// V3 API (legacy)
|
// V4 API only
|
||||||
V3_BASE_URL: "https://apiv3.iucnredlist.org/api/v3",
|
|
||||||
|
|
||||||
// V4 API (new version)
|
|
||||||
BASE_URL: "https://apiv4.iucnredlist.org/api/v4",
|
BASE_URL: "https://apiv4.iucnredlist.org/api/v4",
|
||||||
VERSION: "version",
|
VERSION: "version",
|
||||||
TAXA: "taxa",
|
TAXA: "taxa",
|
||||||
TAXA_BY_SCIENTIFIC_NAME: "taxa/scientific_name",
|
TAXA_BY_SCIENTIFIC_NAME: "taxa/scientific_name",
|
||||||
THREATS: "threats",
|
THREATS_BY_TAXON_ID: "threats/species/id",
|
||||||
CONSERVATION_MEASURES: "conservation_measures",
|
HABITATS_BY_TAXON_ID: "habitats/species/id",
|
||||||
HABITATS: "habitats"
|
MEASURES_BY_TAXON_ID: "measures/species/id"
|
||||||
};
|
};
|
||||||
|
|
||||||
// API types
|
// API types
|
||||||
|
@ -8,16 +8,17 @@ import { fromZodError } from "zod-validation-error";
|
|||||||
|
|
||||||
const CITES_BASE_URL = "https://api.speciesplus.net/api/v1";
|
const CITES_BASE_URL = "https://api.speciesplus.net/api/v1";
|
||||||
|
|
||||||
// IUCN API versions
|
// IUCN API V4 only
|
||||||
const IUCN_V3_BASE_URL = "https://apiv3.iucnredlist.org/api/v3";
|
const IUCN_API_BASE_URL = "https://apiv4.iucnredlist.org/api/v4";
|
||||||
const IUCN_V4_BASE_URL = "https://apiv4.iucnredlist.org/api/v4";
|
|
||||||
|
|
||||||
export async function registerRoutes(app: Express): Promise<Server> {
|
export async function registerRoutes(app: Express): Promise<Server> {
|
||||||
// API Token routes
|
// API Token routes
|
||||||
app.post("/api/token", async (req: Request, res: Response) => {
|
app.post("/api/token", async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const tokenData = insertApiTokenSchema.parse(req.body);
|
const tokenData = insertApiTokenSchema.parse(req.body);
|
||||||
const savedToken = await storage.saveApiToken(tokenData);
|
let citesValid = false;
|
||||||
|
let iucnValid = false;
|
||||||
|
let warnings = [];
|
||||||
|
|
||||||
// Validate the CITES token by making a test request to CITES API
|
// Validate the CITES token by making a test request to CITES API
|
||||||
try {
|
try {
|
||||||
@ -26,8 +27,15 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
"X-Authentication-Token": tokenData.token
|
"X-Authentication-Token": tokenData.token
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
citesValid = true;
|
||||||
|
} catch (error) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: "Invalid CITES API token. Please check and try again."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// If IUCN token is provided, validate it as well
|
// If IUCN token is provided, try to validate it but don't fail if invalid
|
||||||
if (tokenData.iucnToken) {
|
if (tokenData.iucnToken) {
|
||||||
try {
|
try {
|
||||||
await axios.get(`${IUCN_V4_BASE_URL}/version`, {
|
await axios.get(`${IUCN_V4_BASE_URL}/version`, {
|
||||||
@ -35,24 +43,34 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
"Authorization": `Bearer ${tokenData.iucnToken}`
|
"Authorization": `Bearer ${tokenData.iucnToken}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
iucnValid = true;
|
||||||
} catch (iucnError) {
|
} catch (iucnError) {
|
||||||
return res.status(400).json({
|
warnings.push("The IUCN v4 token could not be validated. The system will fall back to IUCN v3 API.");
|
||||||
success: false,
|
// Don't store the invalid token
|
||||||
message: "Invalid IUCN API token. Please check and try again."
|
tokenData.iucnToken = null;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json({ success: true, token: savedToken });
|
// Save the validated token
|
||||||
} catch (error) {
|
const savedToken = await storage.saveApiToken(tokenData);
|
||||||
if (axios.isAxiosError(error) && error.response) {
|
|
||||||
return res.status(400).json({
|
// Return appropriate response based on validation results
|
||||||
success: false,
|
if (warnings.length > 0) {
|
||||||
message: "Invalid CITES API token. Please check and try again."
|
return res.json({
|
||||||
|
success: true,
|
||||||
|
token: savedToken,
|
||||||
|
warnings,
|
||||||
|
message: "CITES API token validated and saved. The IUCN token validation failed - the system will use IUCN v3 API instead."
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
throw error;
|
|
||||||
}
|
res.json({
|
||||||
|
success: true,
|
||||||
|
token: savedToken,
|
||||||
|
message: tokenData.iucnToken
|
||||||
|
? "Both CITES and IUCN API tokens validated and saved successfully!"
|
||||||
|
: "CITES API token validated and saved successfully!"
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof ZodError) {
|
if (error instanceof ZodError) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
@ -61,6 +79,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.error("Error saving API token:", error);
|
||||||
res.status(500).json({
|
res.status(500).json({
|
||||||
success: false,
|
success: false,
|
||||||
message: "Failed to save API token"
|
message: "Failed to save API token"
|
||||||
|
Reference in New Issue
Block a user