Enhance IUCN API integration: Add support for v4 API, improve error handling, and clarify authentication instructions in README.

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/fe2c55e5-ba3a-4d5e-84f0-b14bbe529292.jpg
This commit is contained in:
Magnus-SmariSma
2025-03-20 23:04:52 +00:00
parent 9ae5646a64
commit 7ebec06486
3 changed files with 72 additions and 28 deletions

View File

@ -61,10 +61,22 @@ The application requires a CITES+ API token for authentication. To obtain a toke
4. Enter the token in the application's authentication panel 4. Enter the token in the application's authentication panel
### IUCN Red List API ### IUCN Red List API
The application requires an IUCN Red List API key for accessing conservation data. To obtain a key: The application supports both IUCN Red List API v3 and v4 versions:
#### IUCN API v3 (Legacy)
To use the v3 API:
1. Visit [https://apiv3.iucnredlist.org/api/v3/docs](https://apiv3.iucnredlist.org/api/v3/docs) 1. Visit [https://apiv3.iucnredlist.org/api/v3/docs](https://apiv3.iucnredlist.org/api/v3/docs)
2. Register for an account and request an API key 2. Register for an account and request an API key
3. The key will be automatically configured in the application's environment variables 3. The key will be automatically configured in the application's environment variables (`IUCN_API_KEY`)
#### IUCN API v4 (Recommended)
For enhanced functionality with the v4 API:
1. Visit [https://apiv3.iucnredlist.org/api/v4/docs](https://apiv3.iucnredlist.org/api/v4/docs)
2. Register for an account and request access to the v4 API
3. Generate a bearer token for the v4 API
4. Enter the token in the application's authentication panel (IUCN tab)
The application will intelligently use v4 if available, with automatic fallback to v3 when needed.
## Getting Started ## Getting Started
@ -101,8 +113,10 @@ The application requires an IUCN Red List API key for accessing conservation dat
### Using the Application ### Using the Application
1. **API Authentication**: 1. **API Authentication**:
- Enter your CITES+ API token in the authentication panel - Click the "API Token" button to open the authentication panel
- The API status indicators will show if both APIs are successfully connected - In the CITES tab, enter your CITES+ API token
- In the IUCN tab, enter your IUCN v4 bearer token (if available)
- The API status indicators will show if both APIs are successfully connected, including which version of the IUCN API is active
2. **Searching for Species**: 2. **Searching for Species**:
- Enter a scientific name (e.g., "Panthera tigris") in the search box - Enter a scientific name (e.g., "Panthera tigris") in the search box
@ -180,9 +194,24 @@ npm test
## Limitations and Known Issues ## Limitations and Known Issues
- IUCN API may return 414 errors for very long scientific names
- Some species may not have data in all API sources - Some species may not have data in all API sources
- API rate limits may apply (refer to API documentation for details) - API rate limits may apply (refer to API documentation for details)
- IUCN API v3 may return 414 errors for very long scientific names (this is minimized in the implementation)
- IUCN API v4 requires a separate bearer token authentication
## API Version Handling
The application intelligently manages API versions with the following approach:
- **IUCN API Version Selection**:
- The system first attempts to use IUCN API v4 if a bearer token is available
- If v4 returns an error or isn't available, the system automatically falls back to v3
- All API responses include an `apiVersion` field indicating which version was used
- **Version-Specific Authentication**:
- CITES+ API: Uses a token-based authentication via query parameter
- IUCN v3: Uses an API key via environment variable and query parameter
- IUCN v4: Uses OAuth 2.0 Bearer token authentication via headers
## Future Enhancements ## Future Enhancements

View File

@ -75,12 +75,12 @@ export default function ApiStatus({ citesToken }: ApiStatusProps) {
</Badge> </Badge>
</div> </div>
</TooltipTrigger> </TooltipTrigger>
<TooltipContent side="bottom"> <TooltipContent side="bottom" className="max-w-md">
{citesStatus === 'connected' {citesStatus === 'connected'
? 'CITES+ API is connected and working' ? 'CITES+ API is connected and working'
: citesStatus === 'checking' : citesStatus === 'checking'
? 'Checking CITES+ API connection...' ? 'Checking CITES+ API connection...'
: citesApiData?.message || 'CITES+ API is not connected. Please add your API token.'} : citesApiData?.message || 'CITES+ API is not connected. Click "API Token" and add your CITES+ API token.'}
</TooltipContent> </TooltipContent>
</Tooltip> </Tooltip>
</TooltipProvider> </TooltipProvider>
@ -101,12 +101,12 @@ export default function ApiStatus({ citesToken }: ApiStatusProps) {
</Badge> </Badge>
</div> </div>
</TooltipTrigger> </TooltipTrigger>
<TooltipContent side="bottom"> <TooltipContent side="bottom" className="max-w-md">
{iucnStatus === 'connected' {iucnStatus === 'connected'
? `IUCN Red List API ${iucnApiVersion} is connected and working` ? `IUCN Red List API ${iucnApiVersion} is connected and working`
: iucnStatus === 'checking' : iucnStatus === 'checking'
? 'Checking IUCN Red List API connection...' ? 'Checking IUCN Red List API connection...'
: iucnApiData?.message || 'IUCN Red List API connection issue. Check the API key.'} : iucnApiData?.message || 'IUCN Red List API connection issue. To use IUCN API features, click "API Token" and add your API key on the IUCN tab.'}
</TooltipContent> </TooltipContent>
</Tooltip> </Tooltip>
</TooltipProvider> </TooltipProvider>

View File

@ -291,10 +291,10 @@ export async function registerRoutes(app: Express): Promise<Server> {
// Try V4 API first (with bearer token) // Try V4 API first (with bearer token)
const activeToken = await storage.getActiveToken(); const activeToken = await storage.getActiveToken();
if (activeToken?.iucnToken) { if (activeToken?.iucnToken) {
// Use the version endpoint which is the simplest endpoint
const versionUrl = `${IUCN_V4_BASE_URL}/version`;
try { try {
// Use a simpler endpoint to check if the API is working - we'll just ping the version endpoint
const versionUrl = `${IUCN_V4_BASE_URL}/version`;
const response = await axios.get(versionUrl, { const response = await axios.get(versionUrl, {
headers: { headers: {
"Authorization": `Bearer ${activeToken.iucnToken}` "Authorization": `Bearer ${activeToken.iucnToken}`
@ -308,46 +308,61 @@ export async function registerRoutes(app: Express): Promise<Server> {
message: "IUCN API v4 is connected and responding" message: "IUCN API v4 is connected and responding"
}); });
} catch (error: any) { } catch (error: any) {
// If V4 fails, fall back to checking V3 with environment API key console.log("IUCN V4 API check failed:", error.message);
console.log("IUCN V4 API check failed, falling back to V3:", error.message);
// If token is invalid, return a useful message
if (error.response?.status === 401) {
return res.status(401).json({
success: false,
connected: false,
message: "IUCN API v4 token is invalid. Please check your token and try again."
});
}
// For other errors, continue to try v3
console.log("Falling back to IUCN v3 API check");
} }
} }
// Fallback to V3 API (with query parameter token) // If no v4 token or v4 check failed, try v3
const apiKey = process.env.IUCN_API_KEY; const apiKey = process.env.IUCN_API_KEY;
if (!apiKey) { if (!apiKey) {
return res.status(401).json({ return res.status(401).json({
success: false, success: false,
connected: false, connected: false,
message: "IUCN API key is not configured" message: "No IUCN API credentials found. Please add your IUCN API key."
}); });
} }
// Use the version endpoint for V3
const versionUrl = `${IUCN_V3_BASE_URL}/version`;
try { try {
// Make sure we're not including any parameters in the URL itself - only in params object // For v3, use a really simple request to avoid the 414 error
const response = await axios.get(versionUrl, { const response = await axios.get(`${IUCN_V3_BASE_URL}/version`, {
params: { token: apiKey } params: { token: apiKey }
}); });
res.json({ return res.json({
success: true, success: true,
connected: true, connected: true,
apiVersion: "v3", apiVersion: "v3",
message: "IUCN API v3 is connected and responding" message: "IUCN API v3 is connected and responding"
}); });
} catch (error) { } catch (error: any) {
if (axios.isAxiosError(error) && error.response) { // Handle v3 API errors
return res.status(error.response.status).json({ console.log("IUCN V3 API check failed:", error.message);
if (error.response?.status === 401) {
return res.status(401).json({
success: false, success: false,
connected: false, connected: false,
message: "Failed to connect to IUCN API: " + (error.response?.data?.message || error.message), message: "IUCN API v3 key is invalid. Please check your environment variables."
status: error.response.status
}); });
} }
throw error;
return res.status(error.response?.status || 500).json({
success: false,
connected: false,
message: "Failed to connect to IUCN API: " + (error.response?.data?.message || error.message)
});
} }
} catch (error) { } catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error); const errorMessage = error instanceof Error ? error.message : String(error);