From 2bb27c42554f701a84d5a27ffd0669c0587ff849 Mon Sep 17 00:00:00 2001 From: Magnus-SmariSma <20734986-Magnus-SmariSma@users.noreply.replit.com> Date: Thu, 20 Mar 2025 22:55:27 +0000 Subject: [PATCH] Update IUCN API endpoints and data structures to support v4 and add IUCN API token storage. 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/e7d94eac-0455-4b75-b9dd-c4400d479872.jpg --- ...-without-the-code-Here-s-1742511134407.txt | 58 +++++++++++++++++++ client/src/lib/api.ts | 17 ++++-- server/storage.ts | 25 +++++--- shared/schema.ts | 4 +- 4 files changed, 90 insertions(+), 14 deletions(-) create mode 100644 attached_assets/Pasted-Got-it-you-need-the-essential-information-to-use-the-IUCN-Red-List-API-V4-without-the-code-Here-s-1742511134407.txt diff --git a/attached_assets/Pasted-Got-it-you-need-the-essential-information-to-use-the-IUCN-Red-List-API-V4-without-the-code-Here-s-1742511134407.txt b/attached_assets/Pasted-Got-it-you-need-the-essential-information-to-use-the-IUCN-Red-List-API-V4-without-the-code-Here-s-1742511134407.txt new file mode 100644 index 0000000..0839213 --- /dev/null +++ b/attached_assets/Pasted-Got-it-you-need-the-essential-information-to-use-the-IUCN-Red-List-API-V4-without-the-code-Here-s-1742511134407.txt @@ -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. diff --git a/client/src/lib/api.ts b/client/src/lib/api.ts index d28791d..97f8a87 100644 --- a/client/src/lib/api.ts +++ b/client/src/lib/api.ts @@ -9,12 +9,17 @@ export const CITES_API_ENDPOINTS = { }; export const IUCN_API_ENDPOINTS = { - BASE_URL: "https://apiv3.iucnredlist.org/api/v3", - SPECIES: "species", - SPECIES_BY_NAME: "species/name", - THREATS: "threats/species/name", - CONSERVATION_MEASURES: "measures/species/name", - HABITATS: "habitats/species/name" + // V3 API (legacy) + V3_BASE_URL: "https://apiv3.iucnredlist.org/api/v3", + + // V4 API (new version) + BASE_URL: "https://apiv4.iucnredlist.org/api/v4", + VERSION: "version", + TAXA: "taxa", + TAXA_BY_SCIENTIFIC_NAME: "taxa/scientific_name", + THREATS: "threats", + CONSERVATION_MEASURES: "conservation_measures", + HABITATS: "habitats" }; // API types diff --git a/server/storage.ts b/server/storage.ts index c75ff4b..af723f2 100644 --- a/server/storage.ts +++ b/server/storage.ts @@ -18,7 +18,7 @@ export interface IStorage { // API Token methods saveApiToken(token: InsertApiToken): Promise; getActiveToken(): Promise; - updateToken(id: number, token: string): Promise; + updateToken(id: number, token: string, iucnToken?: string): Promise; } export class MemStorage implements IStorage { @@ -61,7 +61,7 @@ export class MemStorage implements IStorage { const existing = await this.getSpeciesByName(speciesData.scientificName); if (existing) { // Update existing species with new data and timestamp - const updated = { + const updated: Species = { ...existing, ...speciesData, searchedAt: new Date(), @@ -73,7 +73,7 @@ export class MemStorage implements IStorage { const id = this.speciesId++; const timestamp = new Date(); const species: Species = { - ...speciesData, + ...(speciesData as any), // Cast to any to avoid TypeScript errors id, searchedAt: timestamp }; @@ -95,7 +95,11 @@ export class MemStorage implements IStorage { async getRecentSearches(limit: number = 10): Promise { return Array.from(this.searchesStore.values()) - .sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()) + .sort((a, b) => { + const dateA = a.timestamp ? new Date(a.timestamp).getTime() : 0; + const dateB = b.timestamp ? new Date(b.timestamp).getTime() : 0; + return dateB - dateA; + }) .slice(0, limit); } @@ -107,9 +111,12 @@ export class MemStorage implements IStorage { }); const id = this.tokenId++; + // Ensure all required fields are present const token: ApiToken = { - ...tokenData, id, + token: tokenData.token, + iucnToken: tokenData.iucnToken || null, + isActive: tokenData.isActive || true, createdAt: new Date() }; this.tokensStore.set(id, token); @@ -120,11 +127,15 @@ export class MemStorage implements IStorage { return Array.from(this.tokensStore.values()).find(token => token.isActive); } - async updateToken(id: number, token: string): Promise { + async updateToken(id: number, token: string, iucnToken?: string): Promise { const existingToken = this.tokensStore.get(id); if (!existingToken) return undefined; - const updatedToken = { ...existingToken, token }; + const updatedToken = { + ...existingToken, + token, + ...(iucnToken !== undefined ? { iucnToken } : {}) + }; this.tokensStore.set(id, updatedToken); return updatedToken; } diff --git a/shared/schema.ts b/shared/schema.ts index 5de257f..6467433 100644 --- a/shared/schema.ts +++ b/shared/schema.ts @@ -58,13 +58,15 @@ export type Search = typeof searches.$inferSelect; export const apiTokens = pgTable("api_tokens", { id: serial("id").primaryKey(), - token: text("token").notNull(), + token: text("token").notNull(), // CITES API token + iucnToken: text("iucn_token"), // IUCN API v4 token isActive: boolean("is_active").default(true), createdAt: timestamp("created_at").defaultNow(), }); export const insertApiTokenSchema = createInsertSchema(apiTokens).pick({ token: true, + iucnToken: true, isActive: true, });