up demo links and map controls
This commit is contained in:
parent
589235a978
commit
f76bded4e4
13 changed files with 499 additions and 527 deletions
116
doc/ANTI_SPAM_MEASURES.md
Normal file
116
doc/ANTI_SPAM_MEASURES.md
Normal file
|
@ -0,0 +1,116 @@
|
|||
# Anti-Spam and Caching Measures
|
||||
|
||||
This document describes the anti-spam and caching measures implemented in the OpenEventDatabase API to protect against abuse and improve performance.
|
||||
|
||||
## Implemented Measures
|
||||
|
||||
### 1. Rate Limiting
|
||||
|
||||
Rate limiting is implemented using the `RateLimitMiddleware` class, which tracks request rates by IP address and rejects requests that exceed defined limits.
|
||||
|
||||
#### Key Features
|
||||
|
||||
- **Global Rate Limit**: By default, each IP address is limited to 60 requests per minute across all endpoints.
|
||||
- **Endpoint-Specific Limits**:
|
||||
- POST requests to `/event`: Limited to 10 requests per minute
|
||||
- POST requests to `/event/search`: Limited to 20 requests per minute
|
||||
- DELETE requests to `/event`: Limited to 5 requests per minute
|
||||
- **Proper HTTP Responses**: When a rate limit is exceeded, the API returns a `429 Too Many Requests` response with a `Retry-After` header indicating when the client can try again.
|
||||
- **Detailed Logging**: Rate limit violations are logged with details about the client IP, request method, path, and user agent for security analysis.
|
||||
- **Development Mode**: Rate limiting is skipped for local requests (127.0.0.1, localhost) to facilitate development.
|
||||
|
||||
#### Implementation Details
|
||||
|
||||
The rate limiting middleware:
|
||||
1. Tracks request timestamps by IP address
|
||||
2. Cleans up old request timestamps that are outside the current time window
|
||||
3. Counts recent requests within the time window
|
||||
4. Rejects requests that exceed the defined limits
|
||||
5. Handles IP addresses behind proxies by checking the `X-Forwarded-For` header
|
||||
|
||||
### 2. Caching
|
||||
|
||||
Caching is implemented using the `CacheMiddleware` class, which adds appropriate cache-control headers to responses based on the endpoint and request method.
|
||||
|
||||
#### Key Features
|
||||
|
||||
- **Global Default**: By default, GET requests are cached for 60 seconds.
|
||||
- **Endpoint-Specific Caching**:
|
||||
- GET requests to `/event`: Cached for 60 seconds
|
||||
- GET requests to `/stats`: Cached for 300 seconds (5 minutes)
|
||||
- GET requests to `/demo`: Cached for 3600 seconds (1 hour)
|
||||
- POST requests to `/event/search`: Not cached
|
||||
- **No Caching for Write Operations**: POST, PUT, DELETE, and PATCH requests are not cached.
|
||||
- **No Caching for Error Responses**: Responses with status codes >= 400 are not cached.
|
||||
- **Proper HTTP Headers**: The middleware adds appropriate `Cache-Control`, `Vary`, `Pragma`, and `Expires` headers.
|
||||
|
||||
#### Implementation Details
|
||||
|
||||
The caching middleware:
|
||||
1. Determines the appropriate max-age value for the current request based on endpoint and method
|
||||
2. Adds caching headers for cacheable responses
|
||||
3. Adds no-cache headers for non-cacheable responses
|
||||
|
||||
## How These Measures Help
|
||||
|
||||
### Rate Limiting Benefits
|
||||
|
||||
1. **Prevents Abuse**: Limits the impact of malicious users trying to overload the system.
|
||||
2. **Ensures Fair Usage**: Prevents a single user from consuming too many resources.
|
||||
3. **Protects Against Brute Force Attacks**: Makes it harder to use brute force attacks against the API.
|
||||
4. **Reduces Server Load**: Helps maintain server performance during traffic spikes.
|
||||
|
||||
### Caching Benefits
|
||||
|
||||
1. **Improves Performance**: Reduces server load by allowing clients to reuse responses.
|
||||
2. **Reduces Bandwidth Usage**: Minimizes the amount of data transferred between the server and clients.
|
||||
3. **Enhances User Experience**: Provides faster response times for frequently accessed resources.
|
||||
4. **Optimizes Resource Usage**: Allows the server to focus on processing new requests rather than repeating the same work.
|
||||
|
||||
## Suggestions for Future Improvements
|
||||
|
||||
### Rate Limiting Enhancements
|
||||
|
||||
1. **API Key Authentication**: Implement API key authentication to identify users and apply different rate limits based on user roles or subscription levels.
|
||||
2. **Graduated Rate Limiting**: Implement a graduated rate limiting system that reduces the rate limit after suspicious activity is detected.
|
||||
3. **Distributed Rate Limiting**: Use a distributed cache (like Redis) to track rate limits across multiple server instances.
|
||||
4. **Machine Learning for Abuse Detection**: Implement machine learning algorithms to detect and block abusive patterns.
|
||||
5. **CAPTCHA Integration**: Add CAPTCHA challenges for suspicious requests.
|
||||
6. **IP Reputation Checking**: Integrate with IP reputation services to block known malicious IPs.
|
||||
|
||||
### Caching Enhancements
|
||||
|
||||
1. **Server-Side Caching**: Implement server-side caching using a cache like Redis or Memcached to reduce database load.
|
||||
2. **Cache Invalidation**: Implement a cache invalidation system to clear cached responses when the underlying data changes.
|
||||
3. **Conditional Requests**: Support conditional requests using ETags and If-Modified-Since headers.
|
||||
4. **Vary Header Optimization**: Optimize the Vary header to better handle different client capabilities.
|
||||
5. **Cache Partitioning**: Implement cache partitioning based on user roles or other criteria.
|
||||
6. **Content Compression**: Add content compression (gzip, brotli) to reduce bandwidth usage further.
|
||||
|
||||
## How to Monitor and Adjust
|
||||
|
||||
### Monitoring Rate Limiting
|
||||
|
||||
The rate limiting middleware logs detailed information about rate limit violations. You can monitor these logs to:
|
||||
- Identify potential abuse patterns
|
||||
- Adjust rate limits based on actual usage patterns
|
||||
- Detect and block malicious IPs
|
||||
|
||||
### Adjusting Rate Limits
|
||||
|
||||
To adjust the rate limits, modify the `RateLimitMiddleware` class in `oedb/middleware/rate_limit.py`:
|
||||
- Change the `window_size` and `max_requests` parameters in the constructor
|
||||
- Modify the `rate_limit_rules` list to adjust endpoint-specific limits
|
||||
|
||||
### Monitoring Caching
|
||||
|
||||
To monitor the effectiveness of caching:
|
||||
- Use browser developer tools to check if responses are being cached correctly
|
||||
- Monitor server logs to see if the same requests are being processed repeatedly
|
||||
- Use performance monitoring tools to measure response times
|
||||
|
||||
### Adjusting Caching
|
||||
|
||||
To adjust the caching settings, modify the `CacheMiddleware` class in `oedb/middleware/cache.py`:
|
||||
- Change the `default_max_age` parameter in the constructor
|
||||
- Modify the `caching_rules` list to adjust endpoint-specific caching durations
|
196
doc/API_QUERY_PARAMS.md
Normal file
196
doc/API_QUERY_PARAMS.md
Normal file
|
@ -0,0 +1,196 @@
|
|||
# OpenEventDatabase API Query Parameters
|
||||
|
||||
This document describes the query parameters that can be used to search for events in the OpenEventDatabase API.
|
||||
|
||||
## Base URL
|
||||
|
||||
The base URL for the API is:
|
||||
|
||||
```
|
||||
http://api.openeventdatabase.org
|
||||
```
|
||||
|
||||
## Endpoints
|
||||
|
||||
### GET /event
|
||||
|
||||
Returns events that match the specified criteria. By default, it returns the last events which are active "now".
|
||||
|
||||
## Query Parameters
|
||||
|
||||
The following query parameters can be used to filter events:
|
||||
|
||||
### `what`
|
||||
|
||||
Filters events by their category or type.
|
||||
|
||||
- **Format**: String
|
||||
- **Example**: `what=weather.warning`
|
||||
- **Description**: Returns events with a "what" value that starts with the provided string.
|
||||
|
||||
### `when`
|
||||
|
||||
Filters events by a specific timestamp.
|
||||
|
||||
- **Format**: ISO8601 date or keyword
|
||||
- **Default**: "now"
|
||||
- **Keywords**:
|
||||
- `now`: Current time
|
||||
- `today`: Today (00:00 to 23:59)
|
||||
- `yesterday`: Yesterday (00:00 to 23:59)
|
||||
- `tomorrow`: Tomorrow (00:00 to 23:59)
|
||||
- `lasthour`: Last hour
|
||||
- `nexthour`: Next hour
|
||||
- `lastXdays`, `lastXhours`, `lastXminutes`: X days/hours/minutes ago to now
|
||||
- `nextXdays`, `nextXhours`, `nextXminutes`: Now to X days/hours/minutes in the future
|
||||
- **Example**: `when=2025-09-15T12:00:00Z` or `when=yesterday`
|
||||
- **Description**: Returns events that are active at the specified time.
|
||||
|
||||
### `start` and `stop`
|
||||
|
||||
Filters events by a time range.
|
||||
|
||||
- **Format**: ISO8601 date or keyword (same as `when`)
|
||||
- **Default**: "now" for both
|
||||
- **Example**: `start=2025-09-10T00:00:00Z&stop=2025-09-15T23:59:59Z`
|
||||
- **Description**: Returns events that overlap with the specified time range.
|
||||
|
||||
### `bbox`
|
||||
|
||||
Filters events by a geographic bounding box.
|
||||
|
||||
- **Format**: Four comma-separated values representing East, South, West, North coordinates
|
||||
- **Example**: `bbox=-5.0,41.0,10.0,52.0`
|
||||
- **Description**: Returns events located within the specified bounding box.
|
||||
|
||||
### `near`
|
||||
|
||||
Filters events by proximity to a location.
|
||||
|
||||
- **Format**: Two or three comma-separated values representing longitude, latitude, and optionally a maximum distance in meters
|
||||
- **Default distance**: 1 meter if not specified
|
||||
- **Example**: `near=2.3522,48.8566,50000` (events within 50km of Paris)
|
||||
- **Description**: Returns events located within the specified distance from the given coordinates.
|
||||
|
||||
### `polyline`
|
||||
|
||||
Filters events by proximity to a polyline.
|
||||
|
||||
- **Format**: Encoded polyline string (as returned by routing engines like OSRM, GraphHopper, etc.)
|
||||
- **Additional parameters**:
|
||||
- `buffer`: Distance in meters around the polyline (default: 1000)
|
||||
- `polyline_precision`: Precision of the encoded polyline (default: 5)
|
||||
- **Example**: `polyline=_p~iF~ps|U_ulLnnqC_mqNvxq`A&buffer=5000`
|
||||
- **Description**: Returns events located within the specified buffer distance around the encoded polyline.
|
||||
|
||||
### `geom`
|
||||
|
||||
Controls how geometry is returned in the response.
|
||||
|
||||
- **Format**: String or number
|
||||
- **Values**:
|
||||
- `full`: Returns the full geometry
|
||||
- `only`: Returns only the geometry and event ID
|
||||
- Numeric value: Simplifies the geometry to the specified precision (e.g., `geom=0.01`)
|
||||
- **Default**: Returns the centroid of the geometry
|
||||
- **Example**: `geom=full` or `geom=0.01`
|
||||
- **Description**: Controls the level of detail in the geometry portion of the response.
|
||||
|
||||
### `limit`
|
||||
|
||||
Limits the number of results returned.
|
||||
|
||||
- **Format**: Integer
|
||||
- **Default**: 200
|
||||
- **Example**: `limit=50`
|
||||
- **Description**: Limits the number of events returned in the response.
|
||||
|
||||
### `type`
|
||||
|
||||
Filters events by their type.
|
||||
|
||||
- **Format**: String
|
||||
- **Values**: "scheduled", "forecast", "unscheduled"
|
||||
- **Example**: `type=scheduled`
|
||||
- **Description**: Returns events of the specified type.
|
||||
|
||||
## Examples
|
||||
|
||||
### Weather alerts active on a specific date
|
||||
|
||||
```
|
||||
GET /event?when=2025-09-15T12:00:00Z&what=weather.alert
|
||||
```
|
||||
|
||||
Returns weather alerts that were active on September 15, 2025 at 12:00 UTC.
|
||||
|
||||
### Events near a location during a time range
|
||||
|
||||
```
|
||||
GET /event?start=2025-09-15T12:00:00Z&stop=2025-09-15T14:00:00Z&near=2.3522,48.8566,10000
|
||||
```
|
||||
|
||||
Returns events taking place within 10km of Paris on September 15, 2025 from 12:00 to 14:00 UTC.
|
||||
|
||||
### Traffic accidents near a location within the last 10 minutes
|
||||
|
||||
```
|
||||
GET /event?what=traffic.accident&near=2.3522,48.8566,5000&when=last10minutes
|
||||
```
|
||||
|
||||
Returns traffic accidents within 5km of Paris that occurred within the last 10 minutes.
|
||||
|
||||
### Events in a specific region with full geometry
|
||||
|
||||
```
|
||||
GET /event?bbox=-5.0,41.0,10.0,52.0&geom=full
|
||||
```
|
||||
|
||||
Returns events in France with their full geometry.
|
||||
|
||||
### Combining multiple parameters
|
||||
|
||||
```
|
||||
GET /event?what=conference&start=2025-09-01T00:00:00Z&stop=2025-12-31T23:59:59Z&near=2.3522,48.8566,50000&limit=50
|
||||
```
|
||||
|
||||
Returns up to 50 conference events within 50km of Paris between September 1 and December 31, 2025.
|
||||
|
||||
## Response Format
|
||||
|
||||
The API returns a GeoJSON FeatureCollection containing the events that match the query parameters. By default, the geometry portion is replaced by the event geometry centroid, unless you ask for full geometries using the `geom=full` parameter or `geom={snaptogrid}` to simplify the geometry.
|
||||
|
||||
Example response:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [2.3522, 48.8566]
|
||||
},
|
||||
"properties": {
|
||||
"id": "123e4567-e89b-12d3-a456-426614174000",
|
||||
"name": "Conference event in Paris",
|
||||
"description": "Mock conference event for testing",
|
||||
"location": "Paris",
|
||||
"start": "2025-09-10T23:00:00",
|
||||
"stop": "2026-05-10T23:00:00",
|
||||
"createdate": "2025-09-15T23:00:00",
|
||||
"lastupdate": "2025-09-15T23:00:00",
|
||||
"lon": 2.3522,
|
||||
"lat": 48.8566
|
||||
}
|
||||
}
|
||||
],
|
||||
"count": 1
|
||||
}
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
- Only the first 200 events are returned by default. Use the `limit` parameter to adjust this.
|
||||
- The API may return a 500 Internal Server Error if there are issues with the database connection or if the query is malformed.
|
79
doc/DEMO_ENDPOINT.md
Normal file
79
doc/DEMO_ENDPOINT.md
Normal file
|
@ -0,0 +1,79 @@
|
|||
# Demo Endpoint Implementation
|
||||
|
||||
## Overview
|
||||
|
||||
A new endpoint `/demo` has been added to the OpenEventDatabase API. This endpoint serves an interactive HTML page with a MapLibre map that displays current events from the database.
|
||||
|
||||
## Features
|
||||
|
||||
- Interactive MapLibre map showing current events
|
||||
- Events are fetched from the `/event` endpoint with the current date
|
||||
- Each event is displayed as a marker on the map
|
||||
- Clicking on a marker shows a popup with event details
|
||||
- The map automatically zooms to fit all displayed events
|
||||
- Sidebar with links to other API endpoints and the GitHub repository
|
||||
|
||||
## Implementation Details
|
||||
|
||||
The implementation consists of the following components:
|
||||
|
||||
1. **DemoResource Class**: A new resource class in `oedb/resources/demo.py` that handles GET requests to the `/demo` endpoint and returns an HTML page.
|
||||
|
||||
2. **HTML Page**: The HTML page includes:
|
||||
- MapLibre JS and CSS libraries
|
||||
- Custom CSS for styling the page
|
||||
- A full-screen map
|
||||
- A sidebar with information and links
|
||||
|
||||
3. **JavaScript**: The JavaScript code:
|
||||
- Initializes a MapLibre map
|
||||
- Fetches events from the `/event` endpoint
|
||||
- Displays events as markers on the map
|
||||
- Creates popups with event details
|
||||
- Fits the map view to include all events
|
||||
|
||||
4. **Route Registration**: The `/demo` endpoint is registered in `backend.py` with the line:
|
||||
```python
|
||||
app.add_route('/demo', demo)
|
||||
```
|
||||
|
||||
5. **Documentation**: The root endpoint (`/`) has been updated to include information about the demo endpoint.
|
||||
|
||||
## How to Test
|
||||
|
||||
To test the demo endpoint:
|
||||
|
||||
1. Start the server:
|
||||
```bash
|
||||
python3 backend.py
|
||||
```
|
||||
|
||||
2. Open a web browser and navigate to:
|
||||
```
|
||||
http://127.0.0.1:8080/demo
|
||||
```
|
||||
|
||||
3. Verify that:
|
||||
- The page loads correctly with a MapLibre map
|
||||
- Events are displayed on the map (if there are events for the current date)
|
||||
- Clicking on a marker shows a popup with event details
|
||||
- Links to other endpoints work correctly
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If no events appear on the map:
|
||||
|
||||
1. Check if there are events for the current date in the database
|
||||
2. Try adding a test event using the `/event` endpoint
|
||||
3. Check the browser console for any JavaScript errors
|
||||
4. Verify that the `/event` endpoint is working correctly by accessing it directly
|
||||
|
||||
## Future Improvements
|
||||
|
||||
Potential future improvements for the demo page:
|
||||
|
||||
1. Add date selection to view events from different dates
|
||||
2. Add filtering options (by event type, location, etc.)
|
||||
3. Add a search box to find specific events
|
||||
4. Improve the mobile experience
|
||||
5. Add more interactive features to the map
|
201
doc/SEARCH_ENDPOINT.md
Normal file
201
doc/SEARCH_ENDPOINT.md
Normal file
|
@ -0,0 +1,201 @@
|
|||
# OpenEventDatabase Search Endpoint Documentation
|
||||
|
||||
This document describes the `/event/search` endpoint of the OpenEventDatabase API, which allows you to search for events using a GeoJSON geometry.
|
||||
|
||||
## Overview
|
||||
|
||||
The search endpoint provides a way to search for events using a GeoJSON geometry in the request body. This is particularly useful when you need to search for events within a complex shape that cannot be easily expressed using query parameters like `bbox` or `near`.
|
||||
|
||||
## Endpoint
|
||||
|
||||
```
|
||||
POST /event/search
|
||||
```
|
||||
|
||||
## Request Format
|
||||
|
||||
The request body should be a JSON object containing a `geometry` field with a valid GeoJSON geometry. The geometry can be any valid GeoJSON geometry type (Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, or GeometryCollection).
|
||||
|
||||
Example request body:
|
||||
|
||||
```json
|
||||
{
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[2.3, 48.8],
|
||||
[2.4, 48.8],
|
||||
[2.4, 48.9],
|
||||
[2.3, 48.9],
|
||||
[2.3, 48.8]
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Query Parameters
|
||||
|
||||
The search endpoint supports all the same query parameters as the `/event` endpoint. These parameters can be used to further refine your search beyond the geometric constraints.
|
||||
|
||||
For detailed information about the available query parameters, see the [API Query Parameters Documentation](API_QUERY_PARAMS.md).
|
||||
|
||||
### Additional Parameters
|
||||
|
||||
In addition to the parameters documented in the API Query Parameters Documentation, the search endpoint also supports the following parameters:
|
||||
|
||||
#### `where:osm`
|
||||
|
||||
Filters events by OpenStreetMap ID.
|
||||
|
||||
- **Format**: String
|
||||
- **Example**: `where:osm=R12345`
|
||||
- **Description**: Returns events associated with the specified OpenStreetMap ID.
|
||||
|
||||
#### `where:wikidata`
|
||||
|
||||
Filters events by Wikidata ID.
|
||||
|
||||
- **Format**: String
|
||||
- **Example**: `where:wikidata=Q90`
|
||||
- **Description**: Returns events associated with the specified Wikidata ID.
|
||||
|
||||
## Response Format
|
||||
|
||||
The response format is the same as for the `/event` endpoint. It returns a GeoJSON FeatureCollection containing the events that match the query parameters and intersect with the provided geometry.
|
||||
|
||||
Example response:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [2.35, 48.85]
|
||||
},
|
||||
"properties": {
|
||||
"id": "123e4567-e89b-12d3-a456-426614174000",
|
||||
"label": "Conference event in Paris",
|
||||
"what": "event.conference",
|
||||
"where": "Paris",
|
||||
"start": "2025-09-10T23:00:00",
|
||||
"stop": "2026-05-10T23:00:00",
|
||||
"createdate": "2025-09-15T23:00:00",
|
||||
"lastupdate": "2025-09-15T23:00:00"
|
||||
}
|
||||
}
|
||||
],
|
||||
"count": 1
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Search for events within a polygon
|
||||
|
||||
```
|
||||
POST /event/search
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[2.3, 48.8],
|
||||
[2.4, 48.8],
|
||||
[2.4, 48.9],
|
||||
[2.3, 48.9],
|
||||
[2.3, 48.8]
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Returns events located within the specified polygon.
|
||||
|
||||
### Search for events within a polygon with additional filters
|
||||
|
||||
```
|
||||
POST /event/search?what=sport.match&when=today
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[2.3, 48.8],
|
||||
[2.4, 48.8],
|
||||
[2.4, 48.9],
|
||||
[2.3, 48.9],
|
||||
[2.3, 48.8]
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Returns sports matches taking place today within the specified polygon.
|
||||
|
||||
### Search for events near a point with a buffer
|
||||
|
||||
```
|
||||
POST /event/search?buffer=5000
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [2.3522, 48.8566]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Returns events within 5km of the specified point (Paris).
|
||||
|
||||
## Caching and Rate Limiting
|
||||
|
||||
The OpenEventDatabase API implements caching and rate limiting to improve performance and prevent abuse.
|
||||
|
||||
### Caching
|
||||
|
||||
- POST requests to `/event/search` are not cached.
|
||||
- The results of GET requests to `/event` are cached for 60 seconds.
|
||||
- If you need fresh data, you can bypass the cache by adding a unique query parameter (e.g., `?_=timestamp`).
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
- POST requests to `/event/search` are limited to 20 requests per minute per IP address.
|
||||
- If you exceed this limit, you will receive a `429 Too Many Requests` response with a `Retry-After` header indicating when you can try again.
|
||||
|
||||
For more information about the anti-spam and caching measures implemented in the API, see the [Anti-Spam and Caching Measures Documentation](ANTI_SPAM_MEASURES.md).
|
||||
|
||||
## Error Handling
|
||||
|
||||
The search endpoint may return the following error responses:
|
||||
|
||||
- `400 Bad Request`: If the request body is not valid JSON or does not contain a `geometry` field.
|
||||
- `429 Too Many Requests`: If you have exceeded the rate limit.
|
||||
- `500 Internal Server Error`: If there is an error processing the request.
|
||||
|
||||
Error responses include a JSON object with an `error` field containing a description of the error.
|
||||
|
||||
Example error response:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "Request body must contain a 'geometry' field"
|
||||
}
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
- Only the first 200 events are returned by default. Use the `limit` parameter to adjust this.
|
||||
- Complex geometries may result in slower query performance.
|
||||
- The API may return a 500 Internal Server Error if there are issues with the database connection or if the query is malformed.
|
216
doc/TEST_PLAN.md
Normal file
216
doc/TEST_PLAN.md
Normal file
|
@ -0,0 +1,216 @@
|
|||
# Test Plan for OpenEventDatabase Enhancements
|
||||
|
||||
This document outlines a test plan for verifying the functionality of the caching, rate limiting, and search features implemented in the OpenEventDatabase API.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- The OpenEventDatabase server is running on `http://127.0.0.1:8080`
|
||||
- The database is properly configured and contains some test events
|
||||
- You have a tool for making HTTP requests (e.g., curl, Postman, or a web browser)
|
||||
|
||||
## 1. Testing Caching Behavior
|
||||
|
||||
### 1.1 Test GET /event Caching
|
||||
|
||||
1. Make a GET request to `/event`:
|
||||
```bash
|
||||
curl -v http://127.0.0.1:8080/event
|
||||
```
|
||||
2. Check the response headers for `Cache-Control` header with `max-age=60`
|
||||
3. Make the same request again within 60 seconds and observe the response time (should be faster)
|
||||
4. Make the same request with a unique query parameter to bypass the cache:
|
||||
```bash
|
||||
curl -v "http://127.0.0.1:8080/event?_=$(date +%s)"
|
||||
```
|
||||
5. Observe that the response is not served from cache (response time should be slower)
|
||||
|
||||
### 1.2 Test GET /stats Caching
|
||||
|
||||
1. Make a GET request to `/stats`:
|
||||
```bash
|
||||
curl -v http://127.0.0.1:8080/stats
|
||||
```
|
||||
2. Check the response headers for `Cache-Control` header with `max-age=300`
|
||||
3. Make the same request again within 300 seconds and observe the response time (should be faster)
|
||||
|
||||
### 1.3 Test GET /demo Caching
|
||||
|
||||
1. Open `http://127.0.0.1:8080/demo` in a web browser
|
||||
2. Check the network tab in the browser's developer tools for `Cache-Control` header with `max-age=3600`
|
||||
3. Refresh the page within 3600 seconds and observe that resources are loaded from the browser cache
|
||||
|
||||
### 1.4 Test POST /event/search No-Caching
|
||||
|
||||
1. Make a POST request to `/event/search`:
|
||||
```bash
|
||||
curl -v -X POST -H "Content-Type: application/json" -d '{"geometry":{"type":"Point","coordinates":[2.3522, 48.8566]}}' http://127.0.0.1:8080/event/search
|
||||
```
|
||||
2. Check the response headers for `Cache-Control` header with `no-store, no-cache, must-revalidate, max-age=0`
|
||||
3. Make the same request again and observe that the response is not served from cache (response time should be similar)
|
||||
|
||||
### 1.5 Test Error Response No-Caching
|
||||
|
||||
1. Make a request that will result in an error (e.g., invalid JSON):
|
||||
```bash
|
||||
curl -v -X POST -H "Content-Type: application/json" -d '{invalid json}' http://127.0.0.1:8080/event/search
|
||||
```
|
||||
2. Check the response headers for `Cache-Control` header with `no-store, no-cache, must-revalidate, max-age=0`
|
||||
|
||||
## 2. Testing Rate Limiting
|
||||
|
||||
### 2.1 Test Global Rate Limit
|
||||
|
||||
1. Make 61 GET requests to `/event` within 60 seconds:
|
||||
```bash
|
||||
for i in {1..61}; do curl -v http://127.0.0.1:8080/event; sleep 1; done
|
||||
```
|
||||
2. Observe that the 61st request returns a `429 Too Many Requests` response with a `Retry-After` header
|
||||
|
||||
### 2.2 Test POST /event Rate Limit
|
||||
|
||||
1. Make 11 POST requests to `/event` within 60 seconds:
|
||||
```bash
|
||||
for i in {1..11}; do curl -v -X POST -H "Content-Type: application/json" -d '{"type":"Feature","geometry":{"type":"Point","coordinates":[2.3522, 48.8566]},"properties":{"type":"scheduled","what":"test.event","start":"2025-09-16T00:00:00","stop":"2025-09-16T23:59:59","label":"Test Event"}}' http://127.0.0.1:8080/event; sleep 5; done
|
||||
```
|
||||
2. Observe that the 11th request returns a `429 Too Many Requests` response with a `Retry-After` header
|
||||
|
||||
### 2.3 Test POST /event/search Rate Limit
|
||||
|
||||
1. Make 21 POST requests to `/event/search` within 60 seconds:
|
||||
```bash
|
||||
for i in {1..21}; do curl -v -X POST -H "Content-Type: application/json" -d '{"geometry":{"type":"Point","coordinates":[2.3522, 48.8566]}}' http://127.0.0.1:8080/event/search; sleep 2; done
|
||||
```
|
||||
2. Observe that the 21st request returns a `429 Too Many Requests` response with a `Retry-After` header
|
||||
|
||||
### 2.4 Test DELETE /event Rate Limit
|
||||
|
||||
1. Create a test event and note its ID:
|
||||
```bash
|
||||
curl -v -X POST -H "Content-Type: application/json" -d '{"type":"Feature","geometry":{"type":"Point","coordinates":[2.3522, 48.8566]},"properties":{"type":"scheduled","what":"test.event","start":"2025-09-16T00:00:00","stop":"2025-09-16T23:59:59","label":"Test Event"}}' http://127.0.0.1:8080/event
|
||||
```
|
||||
2. Make 6 DELETE requests to `/event/{id}` within 60 seconds:
|
||||
```bash
|
||||
for i in {1..6}; do curl -v -X DELETE http://127.0.0.1:8080/event/{id}; sleep 10; done
|
||||
```
|
||||
3. Observe that the 6th request returns a `429 Too Many Requests` response with a `Retry-After` header
|
||||
|
||||
## 3. Testing Search Functionality
|
||||
|
||||
### 3.1 Test Basic Search with Point Geometry
|
||||
|
||||
1. Make a POST request to `/event/search` with a Point geometry:
|
||||
```bash
|
||||
curl -v -X POST -H "Content-Type: application/json" -d '{"geometry":{"type":"Point","coordinates":[2.3522, 48.8566]}}' http://127.0.0.1:8080/event/search
|
||||
```
|
||||
2. Verify that the response contains events near the specified point
|
||||
|
||||
### 3.2 Test Search with Polygon Geometry
|
||||
|
||||
1. Make a POST request to `/event/search` with a Polygon geometry:
|
||||
```bash
|
||||
curl -v -X POST -H "Content-Type: application/json" -d '{"geometry":{"type":"Polygon","coordinates":[[[2.3, 48.8],[2.4, 48.8],[2.4, 48.9],[2.3, 48.9],[2.3, 48.8]]]}}' http://127.0.0.1:8080/event/search
|
||||
```
|
||||
2. Verify that the response contains events within the specified polygon
|
||||
|
||||
### 3.3 Test Search with Buffer
|
||||
|
||||
1. Make a POST request to `/event/search` with a Point geometry and a buffer:
|
||||
```bash
|
||||
curl -v -X POST -H "Content-Type: application/json" -d '{"geometry":{"type":"Point","coordinates":[2.3522, 48.8566]}}' "http://127.0.0.1:8080/event/search?buffer=5000"
|
||||
```
|
||||
2. Verify that the response contains events within 5km of the specified point
|
||||
|
||||
### 3.4 Test Search with Time Filter
|
||||
|
||||
1. Make a POST request to `/event/search` with a Point geometry and a time filter:
|
||||
```bash
|
||||
curl -v -X POST -H "Content-Type: application/json" -d '{"geometry":{"type":"Point","coordinates":[2.3522, 48.8566]}}' "http://127.0.0.1:8080/event/search?when=today"
|
||||
```
|
||||
2. Verify that the response contains events near the specified point that are active today
|
||||
|
||||
### 3.5 Test Search with Category Filter
|
||||
|
||||
1. Make a POST request to `/event/search` with a Point geometry and a category filter:
|
||||
```bash
|
||||
curl -v -X POST -H "Content-Type: application/json" -d '{"geometry":{"type":"Point","coordinates":[2.3522, 48.8566]}}' "http://127.0.0.1:8080/event/search?what=sport"
|
||||
```
|
||||
2. Verify that the response contains events near the specified point with a "what" value that starts with "sport"
|
||||
|
||||
### 3.6 Test Search with Type Filter
|
||||
|
||||
1. Make a POST request to `/event/search` with a Point geometry and a type filter:
|
||||
```bash
|
||||
curl -v -X POST -H "Content-Type: application/json" -d '{"geometry":{"type":"Point","coordinates":[2.3522, 48.8566]}}' "http://127.0.0.1:8080/event/search?type=scheduled"
|
||||
```
|
||||
2. Verify that the response contains events near the specified point with a "type" value of "scheduled"
|
||||
|
||||
### 3.7 Test Search with Limit
|
||||
|
||||
1. Make a POST request to `/event/search` with a Point geometry and a limit:
|
||||
```bash
|
||||
curl -v -X POST -H "Content-Type: application/json" -d '{"geometry":{"type":"Point","coordinates":[2.3522, 48.8566]}}' "http://127.0.0.1:8080/event/search?limit=5"
|
||||
```
|
||||
2. Verify that the response contains at most 5 events
|
||||
|
||||
### 3.8 Test Search with Full Geometry
|
||||
|
||||
1. Make a POST request to `/event/search` with a Point geometry and a request for full geometry:
|
||||
```bash
|
||||
curl -v -X POST -H "Content-Type: application/json" -d '{"geometry":{"type":"Point","coordinates":[2.3522, 48.8566]}}' "http://127.0.0.1:8080/event/search?geom=full"
|
||||
```
|
||||
2. Verify that the response contains events with their full geometry
|
||||
|
||||
### 3.9 Test Search with OSM ID
|
||||
|
||||
1. Make a POST request to `/event/search` with a Point geometry and an OSM ID filter:
|
||||
```bash
|
||||
curl -v -X POST -H "Content-Type: application/json" -d '{"geometry":{"type":"Point","coordinates":[2.3522, 48.8566]}}' "http://127.0.0.1:8080/event/search?where:osm=R12345"
|
||||
```
|
||||
2. Verify that the response contains events associated with the specified OSM ID
|
||||
|
||||
### 3.10 Test Search with Wikidata ID
|
||||
|
||||
1. Make a POST request to `/event/search` with a Point geometry and a Wikidata ID filter:
|
||||
```bash
|
||||
curl -v -X POST -H "Content-Type: application/json" -d '{"geometry":{"type":"Point","coordinates":[2.3522, 48.8566]}}' "http://127.0.0.1:8080/event/search?where:wikidata=Q90"
|
||||
```
|
||||
2. Verify that the response contains events associated with the specified Wikidata ID
|
||||
|
||||
## 4. Testing Error Handling
|
||||
|
||||
### 4.1 Test Invalid JSON
|
||||
|
||||
1. Make a POST request to `/event/search` with invalid JSON:
|
||||
```bash
|
||||
curl -v -X POST -H "Content-Type: application/json" -d '{invalid json}' http://127.0.0.1:8080/event/search
|
||||
```
|
||||
2. Verify that the response is a `400 Bad Request` with an error message
|
||||
|
||||
### 4.2 Test Missing Geometry
|
||||
|
||||
1. Make a POST request to `/event/search` without a geometry field:
|
||||
```bash
|
||||
curl -v -X POST -H "Content-Type: application/json" -d '{}' http://127.0.0.1:8080/event/search
|
||||
```
|
||||
2. Verify that the response is a `400 Bad Request` with an error message about the missing geometry field
|
||||
|
||||
## 5. Testing Demo Page
|
||||
|
||||
### 5.1 Test Demo Page with Real Events
|
||||
|
||||
1. Open `http://127.0.0.1:8080/demo` in a web browser
|
||||
2. Verify that the map shows real events from the database
|
||||
3. Click on an event marker and verify that the popup shows the event details
|
||||
4. Verify that the map is centered on the events
|
||||
|
||||
### 5.2 Test Event Form
|
||||
|
||||
1. Open `http://127.0.0.1:8080/demo/add` in a web browser
|
||||
2. Verify that the form has default values for the date fields (current date) and the map is centered on France
|
||||
3. Fill out the form with test data and submit it
|
||||
4. Verify that the event is created successfully
|
||||
5. Go back to the demo page and verify that the new event is displayed on the map
|
||||
|
||||
## Conclusion
|
||||
|
||||
This test plan covers the key functionality of the caching, rate limiting, and search features implemented in the OpenEventDatabase API. By following these tests, you can verify that the implementations work as expected and meet the requirements specified in the issue description.
|
Loading…
Add table
Add a link
Reference in a new issue