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
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,12 +9,17 @@ export const CITES_API_ENDPOINTS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const IUCN_API_ENDPOINTS = {
|
export const IUCN_API_ENDPOINTS = {
|
||||||
BASE_URL: "https://apiv3.iucnredlist.org/api/v3",
|
// V3 API (legacy)
|
||||||
SPECIES: "species",
|
V3_BASE_URL: "https://apiv3.iucnredlist.org/api/v3",
|
||||||
SPECIES_BY_NAME: "species/name",
|
|
||||||
THREATS: "threats/species/name",
|
// V4 API (new version)
|
||||||
CONSERVATION_MEASURES: "measures/species/name",
|
BASE_URL: "https://apiv4.iucnredlist.org/api/v4",
|
||||||
HABITATS: "habitats/species/name"
|
VERSION: "version",
|
||||||
|
TAXA: "taxa",
|
||||||
|
TAXA_BY_SCIENTIFIC_NAME: "taxa/scientific_name",
|
||||||
|
THREATS: "threats",
|
||||||
|
CONSERVATION_MEASURES: "conservation_measures",
|
||||||
|
HABITATS: "habitats"
|
||||||
};
|
};
|
||||||
|
|
||||||
// API types
|
// API types
|
||||||
|
@ -18,7 +18,7 @@ export interface IStorage {
|
|||||||
// API Token methods
|
// API Token methods
|
||||||
saveApiToken(token: InsertApiToken): Promise<ApiToken>;
|
saveApiToken(token: InsertApiToken): Promise<ApiToken>;
|
||||||
getActiveToken(): Promise<ApiToken | undefined>;
|
getActiveToken(): Promise<ApiToken | undefined>;
|
||||||
updateToken(id: number, token: string): Promise<ApiToken | undefined>;
|
updateToken(id: number, token: string, iucnToken?: string): Promise<ApiToken | undefined>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MemStorage implements IStorage {
|
export class MemStorage implements IStorage {
|
||||||
@ -61,7 +61,7 @@ export class MemStorage implements IStorage {
|
|||||||
const existing = await this.getSpeciesByName(speciesData.scientificName);
|
const existing = await this.getSpeciesByName(speciesData.scientificName);
|
||||||
if (existing) {
|
if (existing) {
|
||||||
// Update existing species with new data and timestamp
|
// Update existing species with new data and timestamp
|
||||||
const updated = {
|
const updated: Species = {
|
||||||
...existing,
|
...existing,
|
||||||
...speciesData,
|
...speciesData,
|
||||||
searchedAt: new Date(),
|
searchedAt: new Date(),
|
||||||
@ -73,7 +73,7 @@ export class MemStorage implements IStorage {
|
|||||||
const id = this.speciesId++;
|
const id = this.speciesId++;
|
||||||
const timestamp = new Date();
|
const timestamp = new Date();
|
||||||
const species: Species = {
|
const species: Species = {
|
||||||
...speciesData,
|
...(speciesData as any), // Cast to any to avoid TypeScript errors
|
||||||
id,
|
id,
|
||||||
searchedAt: timestamp
|
searchedAt: timestamp
|
||||||
};
|
};
|
||||||
@ -95,7 +95,11 @@ export class MemStorage implements IStorage {
|
|||||||
|
|
||||||
async getRecentSearches(limit: number = 10): Promise<Search[]> {
|
async getRecentSearches(limit: number = 10): Promise<Search[]> {
|
||||||
return Array.from(this.searchesStore.values())
|
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);
|
.slice(0, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,9 +111,12 @@ export class MemStorage implements IStorage {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const id = this.tokenId++;
|
const id = this.tokenId++;
|
||||||
|
// Ensure all required fields are present
|
||||||
const token: ApiToken = {
|
const token: ApiToken = {
|
||||||
...tokenData,
|
|
||||||
id,
|
id,
|
||||||
|
token: tokenData.token,
|
||||||
|
iucnToken: tokenData.iucnToken || null,
|
||||||
|
isActive: tokenData.isActive || true,
|
||||||
createdAt: new Date()
|
createdAt: new Date()
|
||||||
};
|
};
|
||||||
this.tokensStore.set(id, token);
|
this.tokensStore.set(id, token);
|
||||||
@ -120,11 +127,15 @@ export class MemStorage implements IStorage {
|
|||||||
return Array.from(this.tokensStore.values()).find(token => token.isActive);
|
return Array.from(this.tokensStore.values()).find(token => token.isActive);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateToken(id: number, token: string): Promise<ApiToken | undefined> {
|
async updateToken(id: number, token: string, iucnToken?: string): Promise<ApiToken | undefined> {
|
||||||
const existingToken = this.tokensStore.get(id);
|
const existingToken = this.tokensStore.get(id);
|
||||||
if (!existingToken) return undefined;
|
if (!existingToken) return undefined;
|
||||||
|
|
||||||
const updatedToken = { ...existingToken, token };
|
const updatedToken = {
|
||||||
|
...existingToken,
|
||||||
|
token,
|
||||||
|
...(iucnToken !== undefined ? { iucnToken } : {})
|
||||||
|
};
|
||||||
this.tokensStore.set(id, updatedToken);
|
this.tokensStore.set(id, updatedToken);
|
||||||
return updatedToken;
|
return updatedToken;
|
||||||
}
|
}
|
||||||
|
@ -58,13 +58,15 @@ export type Search = typeof searches.$inferSelect;
|
|||||||
|
|
||||||
export const apiTokens = pgTable("api_tokens", {
|
export const apiTokens = pgTable("api_tokens", {
|
||||||
id: serial("id").primaryKey(),
|
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),
|
isActive: boolean("is_active").default(true),
|
||||||
createdAt: timestamp("created_at").defaultNow(),
|
createdAt: timestamp("created_at").defaultNow(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const insertApiTokenSchema = createInsertSchema(apiTokens).pick({
|
export const insertApiTokenSchema = createInsertSchema(apiTokens).pick({
|
||||||
token: true,
|
token: true,
|
||||||
|
iucnToken: true,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user