-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merge Aquaveo master which includes V2 PR #22
base: master
Are you sure you want to change the base?
Conversation
Helm docker update See merge request geoglows/gsp_rest_api!4
build commit only on merge to master See merge request geoglows/gsp_rest_api!5
reversed ci triggers See merge request geoglows/gsp_rest_api!6
This reverts commit c71f3b1.
Consolidate v2 change See merge request geoglows/gsp_rest_api!13
updated to harbor v2 endpoint for uploads See merge request geoglows/gsp_rest_api!14
updated to harbor v2 endpoint for uploads See merge request geoglows/gsp_rest_api!15
Warning Rate Limit Exceeded@rileyhales has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 4 minutes and 10 seconds before requesting another review. How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. WalkthroughThis update enhances the project by refining configurations, improving the Flask application, and ensuring consistency in documentation. Key changes include the integration of new Flask blueprints for web pages and API endpoints, CI/CD pipeline optimizations, Dockerfile improvements, and standardization of the GEOGLOWS name across all materials. The update also introduces logging capabilities and better organization for managing forecast and historical data, resulting in a more robust and user-friendly application. Changes
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (invoked as PR comments)
Additionally, you can add CodeRabbit Configration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review Status
Actionable comments generated: 10
Configuration used: CodeRabbit UI
Files ignored due to path filters (45)
app/geometry/1_simplified_region_boundary_geojsons.zip
is excluded by:!**/*.zip
app/geometry/africa-geoglows-comid_lat_lon_z.pickle
is excluded by:!**/*.pickle
app/geometry/australia-geoglows-comid_lat_lon_z.pickle
is excluded by:!**/*.pickle
app/geometry/boundaries.pickle
is excluded by:!**/*.pickle
app/geometry/central_america-geoglows-comid_lat_lon_z.pickle
is excluded by:!**/*.pickle
app/geometry/central_asia-geoglows-comid_lat_lon_z.pickle
is excluded by:!**/*.pickle
app/geometry/east_asia-geoglows-comid_lat_lon_z.pickle
is excluded by:!**/*.pickle
app/geometry/europe-geoglows-comid_lat_lon_z.pickle
is excluded by:!**/*.pickle
app/geometry/islands-geoglows-comid_lat_lon_z.pickle
is excluded by:!**/*.pickle
app/geometry/japan-geoglows-comid_lat_lon_z.pickle
is excluded by:!**/*.pickle
app/geometry/middle_east-geoglows-comid_lat_lon_z.pickle
is excluded by:!**/*.pickle
app/geometry/north_america-geoglows-comid_lat_lon_z.pickle
is excluded by:!**/*.pickle
app/geometry/region_coordinate_files/africa-geoglows/comid_lat_lon_z.csv
is excluded by:!**/*.csv
app/geometry/region_coordinate_files/australia-geoglows/comid_lat_lon_z.csv
is excluded by:!**/*.csv
app/geometry/region_coordinate_files/bounding_boxes.csv
is excluded by:!**/*.csv
app/geometry/region_coordinate_files/central_america-geoglows/comid_lat_lon_z.csv
is excluded by:!**/*.csv
app/geometry/region_coordinate_files/central_asia-geoglows/comid_lat_lon_z.csv
is excluded by:!**/*.csv
app/geometry/region_coordinate_files/east_asia-geoglows/comid_lat_lon_z.csv
is excluded by:!**/*.csv
app/geometry/region_coordinate_files/europe-geoglows/comid_lat_lon_z.csv
is excluded by:!**/*.csv
app/geometry/region_coordinate_files/global_coordinate_file.csv
is excluded by:!**/*.csv
app/geometry/region_coordinate_files/islands-geoglows/comid_lat_lon_z.csv
is excluded by:!**/*.csv
app/geometry/region_coordinate_files/japan-geoglows/comid_lat_lon_z.csv
is excluded by:!**/*.csv
app/geometry/region_coordinate_files/middle_east-geoglows/comid_lat_lon_z.csv
is excluded by:!**/*.csv
app/geometry/region_coordinate_files/north_america-geoglows/comid_lat_lon_z.csv
is excluded by:!**/*.csv
app/geometry/region_coordinate_files/south_america-geoglows/comid_lat_lon_z.csv
is excluded by:!**/*.csv
app/geometry/region_coordinate_files/south_asia-geoglows/comid_lat_lon_z.csv
is excluded by:!**/*.csv
app/geometry/region_coordinate_files/west_asia-geoglows/comid_lat_lon_z.csv
is excluded by:!**/*.csv
app/geometry/south_america-geoglows-comid_lat_lon_z.pickle
is excluded by:!**/*.pickle
app/geometry/south_asia-geoglows-comid_lat_lon_z.pickle
is excluded by:!**/*.pickle
app/geometry/west_asia-geoglows-comid_lat_lon_z.pickle
is excluded by:!**/*.pickle
app/static/images/about1.jpg
is excluded by:!**/*.jpg
app/static/images/about2.jpg
is excluded by:!**/*.jpg
app/static/images/about3.jpg
is excluded by:!**/*.jpg
app/static/images/about4.jpg
is excluded by:!**/*.jpg
app/static/images/aquaveologo.png
is excluded by:!**/*.png
app/static/images/byulogo.png
is excluded by:!**/*.png
app/static/images/ecmwflogo.png
is excluded by:!**/*.png
app/static/images/favicon.ico
is excluded by:!**/*.ico
app/static/images/geoglowslogo.png
is excluded by:!**/*.png
assets/streamflow_animation.png
is excluded by:!**/*.png
demos/input_example.json
is excluded by:!**/*.json
docker-compose.yml
is excluded by:!**/*.yml
docs/swagger_doc.yaml
is excluded by:!**/*.yaml
environment.yaml
is excluded by:!**/*.yaml
helm/gsprestapi/Chart.yaml
is excluded by:!**/*.yaml
Files selected for processing (33)
- .gitignore (1 hunks)
- .gitlab-ci.yml (5 hunks)
- Dockerfile (1 hunks)
- README.md (1 hunks)
- app/app.py (1 hunks)
- app/blueprint_pages.py (1 hunks)
- app/templates/about.html (3 hunks)
- app/templates/base_template.html (5 hunks)
- app/templates/documentation.html (2 hunks)
- app/templates/home.html (1 hunks)
- app/templates/license.html (3 hunks)
- app/templates/publications.html (1 hunks)
- app/templates/resources.html (2 hunks)
- app/v1/init.py (1 hunks)
- app/v1/analytics.py (1 hunks)
- app/v1/blueprint.py (1 hunks)
- app/v1/v1_controllers_forecasts.py (1 hunks)
- app/v1/v1_controllers_historical.py (1 hunks)
- app/v1/v1_functions.py (1 hunks)
- app/v1/v1_utilities.py (1 hunks)
- app/v2/init.py (1 hunks)
- app/v2/analytics.py (1 hunks)
- app/v2/blueprint.py (1 hunks)
- app/v2/constants.py (1 hunks)
- app/v2/controllers_forecasts.py (5 hunks)
- app/v2/controllers_historical.py (1 hunks)
- app/v2/controllers_misc.py (1 hunks)
- app/v2/data.py (1 hunks)
- app/v2/response_formatters.py (1 hunks)
- check_helm_chart (1 hunks)
- docs/index.html (2 hunks)
- docs/swagger_yml_to_html.py (1 hunks)
- supervisord.conf (1 hunks)
Files not summarized due to errors (1)
- docs/index.html: Error: Message exceeds token limit
Files skipped from review due to trivial changes (8)
- app/templates/about.html
- app/templates/base_template.html
- app/templates/home.html
- app/templates/resources.html
- app/v1/init.py
- app/v1/v1_functions.py
- app/v1/v1_utilities.py
- app/v2/init.py
Additional comments: 49
app/v2/constants.py (2)
- 3-3: The conversion factor from cubic meters to cubic feet is accurate.
- 4-4: Ensure
NUM_DECIMALS
is applied consistently across the application for numerical precision.Verification successful
The usage of
NUM_DECIMALS
inapp/v2/controllers_forecasts.py
for rounding operations confirms that it is applied consistently across the application for numerical precision. This aligns with the intended use of ensuring numerical precision is maintained uniformly.Scripts Executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Search for usage of NUM_DECIMALS across Python files to ensure consistent application. rg "NUM_DECIMALS" --type pyLength of output: 736
supervisord.conf (1)
- 5-6: The updated
uwsgi
configuration points to a specific virtual environment, which is a common practice. Ensure the new configuration is tested and works as expected in the deployment environment.app/app.py (1)
- 12-30: The Flask app configuration and blueprint registrations follow standard practices. Consider adding comments to explain the purpose of each major section (e.g., CORS setup, blueprint registrations) for better clarity and maintainability.
Dockerfile (1)
- 8-13: The updates to the conda environment creation command and the reference to
environment.yaml
are correct. Ensure the environment setup is tested and works as expected in the Docker container.app/blueprint_pages.py (1)
- 1-53: The Flask blueprint setup, routes, and error handling in
blueprint_pages.py
follow standard practices. Consider adding comments to explain the purpose of each route and the custom 404 error handler for better clarity and maintainability.check_helm_chart (1)
- 27-32: Consider enhancing the error handling by providing more detailed messages based on the HTTP status code returned by the server. This can help in diagnosing issues with chart uploads more effectively.
elif [ ${RESULT} -ne 200 ]; then - echo "Unknown error while trying to retrieve chart from remote" >&2 + case ${RESULT} in + 401) + echo "Unauthorized: Check if the ECCR_USER and ECCR_PASSWORD environment variables are correctly set." >&2 + ;; + 403) + echo "Forbidden: The user does not have permission to access the chart repository." >&2 + ;; + 500) + echo "Internal Server Error: There might be a problem with the chart repository server." >&2 + ;; + *) + echo "An unexpected error occurred while trying to retrieve the chart from remote. HTTP status code: ${RESULT}" >&2 + ;; + esac exit -2 fiapp/v2/response_formatters.py (3)
- 10-14: The implementation of
df_to_csv_flask_response
is correct and follows best practices for generating CSV responses in Flask.- 17-25: The
df_to_jsonify_response
function correctly formats DataFrame data into a JSON response. Consider explicitly documenting the choice to replace NaN values with empty strings, as this might impact consumers of the API depending on the context.- 28-42: The
new_json_template
function is well-implemented, providing a clear and reusable structure for JSON responses.app/v1/analytics.py (1)
- 23-28: > 📝 NOTE
This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [1-44]
The
log_request
function correctly logs requests to AWS CloudWatch. Consider adding error handling for the AWS CloudWatch logging operation to gracefully handle potential issues with logging, such as network errors or misconfigurations..gitignore (1)
- 185-190: The updates to
.gitignore
are appropriate and follow best practices for excluding editor configurations and sensitive configuration files from the repository.docs/swagger_yml_to_html.py (1)
- 21-21: The update to the title block in the HTML template aligns with the naming consistency objective of the PR.
app/v2/data.py (2)
- 47-54: The
get_return_periods_dataframe
function is well-implemented, correctly retrieving and processing return period data from an S3 bucket.- 57-61: The
find_available_dates
function correctly identifies available forecast dates using file listing and sorting. Good use ofglob
andnatsort
..gitlab-ci.yml (3)
- 5-11: The inclusion of
helm-check.yml
andkaniko-build.yml
enhances the CI/CD pipeline by integrating additional checks and builds. This aligns with best practices for CI/CD pipeline configuration.- 17-34: The updates to variables for the Helm stages are appropriate and improve the clarity and maintainability of the CI/CD pipeline configuration.
- 52-57: The
before_script
configuration for Docker authentication in theBuild Tag
stage is a good security practice. Verify that the Docker authentication works as expected in the CI/CD environment.app/templates/license.html (2)
- 2-2: Ensure the updated title aligns with the project's naming conventions and accurately reflects the content of the page.
- 25-63: > 📝 NOTE
This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [28-80]
The update to the data license and the addition of a disclaimer are significant improvements. It's important to verify that the Creative Commons license chosen (CC BY 4.0) is appropriate for the data being shared and that the disclaimer is clear and understandable to users.
app/v2/controllers_historical.py (5)
- 16-27: The function
_get_retrospective_df
efficiently retrieves retrospective data from an S3 bucket using xarray and pandas. Ensure that error handling is in place for potential issues with data access or transformation.- 51-63: The
daily_averages
function demonstrates good use of pandas for data manipulation. Ensure consistency in date formatting across all functions for clarity and usability.- 66-77: In the
monthly_averages
function, consider adding comments to explain the logic, especially for the grouping and averaging process, to improve maintainability.- 80-91: The
yearly_averages
function is concise and follows similar patterns as other functions. Verify that the date range handling meets the application's requirements.- 94-110: The
return_periods
function introduces a new response format. Ensure that the response structure is documented and consistent with other API endpoints.app/templates/publications.html (2)
- 2-2: The updated title accurately reflects the content of the page and aligns with the project's naming conventions.
- 13-83: The addition of publications is a valuable update for users interested in the research behind the GEOGLOWS ECMWF Streamflow Model. Ensure that all publication links are valid and accessible.
app/v1/v1_controllers_historical.py (3)
- 9-9: The use of
jsonify
andmake_response
from Flask is appropriate for generating responses. Ensure that all responses are consistent in format across the API.- 11-12: The relative imports for constants and functions are correctly updated to maintain modularity and ease of maintenance.
- 6-15: > 📝 NOTE
This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [1-228]
Overall, the changes in
app/v1/v1_controllers_historical.py
improve the organization and readability of the code. Ensure that error handling and input validation are consistently applied across all functions to enhance robustness and security.+ # Add input validation and error handling where necessary
app/v2/blueprint.py (3)
- 25-25: The creation of the Flask blueprint for version 2 endpoints is correctly implemented. Ensure that the blueprint name is unique and descriptive.
- 83-173: The
handle_request
function effectively parses and validates request parameters. Consider adding more detailed error messages to help users correct their requests.- 176-185: Error handling for
ValueError
and general exceptions is a good practice. Ensure that logging is appropriately configured to capture sufficient details for debugging.app/v2/controllers_forecasts.py (7)
- 10-17: The updated import statements and the use of relative imports improve modularity and maintainability. Ensure that all necessary modules are imported and unused imports are removed.
- 23-39: The
hydroviewer
function integrates multiple data sources to provide a comprehensive response. Ensure that the data integration logic is accurate and that the response format meets the API's standards.- 58-140: > 📝 NOTE
This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [51-82]
The
forecast
function demonstrates efficient data manipulation using numpy and pandas. Consider adding error handling for potential issues with data access or transformation.
- 87-118: The
forecast_stats
function correctly calculates various statistical measures. Verify that the percentile calculations are appropriate for the application's requirements.- 58-140: > 📝 NOTE
This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [123-166]
In the
forecast_ensembles
function, the handling of ensemble filtering is well-implemented. Ensure that the ensemble parameter is validated to prevent errors.+ # Validate ensemble parameter
- 188-228: > 📝 NOTE
This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [172-206]
The
forecast_records
function retrieves historical forecast records. Ensure that the date range validation is robust and that error messages are clear for users.
- 212-227: The
forecast_dates
function provides a list of available forecast dates. Consider adding caching to improve performance if the available dates do not change frequently.app/v1/v1_controllers_forecasts.py (6)
- 9-10: The update to relative imports for
constants
andv1_functions
is a good practice for module organization and helps avoid import errors in a package structure.- 5-13: > 📝 NOTE
This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [12-93]
The
forecast_stats
function integrates well with the changes to relative imports and adheres to best practices in handling parameters, units, and file paths.
- 5-13: > 📝 NOTE
This review was outside the diff hunks, and no overlapping diff hunk was found. Original lines [95-169]
The
forecast_ensembles
function correctly uses the updated relative imports and follows best practices in its implementation.
- 5-13: > 📝 NOTE
This review was outside the diff hunks, and no overlapping diff hunk was found. Original lines [171-234]
The
forecast_warnings
function correctly uses the updated relative imports and adheres to best practices in handling different scenarios for regions and forecast dates.
- 5-13: > 📝 NOTE
This review was outside the diff hunks, and no overlapping diff hunk was found. Original lines [236-287]
The
forecast_records
function integrates well with the changes to relative imports and adheres to best practices in handling parameters, units, and file paths.
- 5-13: > 📝 NOTE
This review was outside the diff hunks, and no overlapping diff hunk was found. Original lines [289-307]
The
available_dates
function correctly uses the updated relative imports and follows best practices in its implementation.app/templates/documentation.html (2)
- 2-2: The update to the title casing to "GEOGLOWS" aligns with the PR's objective to standardize the project name's casing.
- 11-11: The update of the version number in the Swagger specification to "1.5.0" likely reflects the introduction of new features or significant updates in the API.
docs/index.html (1)
- 11-11: The JavaScript code for removing the Swagger UI top bar is effective but consider the maintainability of this approach. Future updates to Swagger UI might change class names or the structure, requiring updates to this script. Documenting this customization or exploring alternative, more maintainable approaches could be beneficial.
docs/index.html
Outdated
@@ -8,7 +8,7 @@ | |||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script> | |||
<script> | |||
window.onload = function() { | |||
const spec = {"swagger": "2.0", "info": {"title": "GEOGloWS ECMWF Streamflow Data Service", "description": "A REST Data Service to access high resolution streamflow forecasts from around the world", "version": "2.0.0"}, "host": "geoglows.ecmwf.int", "basePath": "/api", "schemes": ["https", "http"], "paths": {"/Hydroviewer/{reach_id}/{return_format}": {"get": {"description": "A shorthand for retrieving the forecast records and stats, and return periods, usually all plotted together.", "summary": "Returns forecast records, forecast stats, and return periods.", "parameters": [{"name": "reach_id", "in": "path", "description": "The stream reach's unique ID also refered to as common identifier (COMID). If the ID is not known, use the getReachID method.", "type": "number", "format": "integer", "required": true}, {"name": "return_format", "in": "path", "required": true, "description": "The format of the response", "type": "string", "default": "csv", "enum": ["csv", "json"]}, {"name": "date", "in": "query", "description": "The given date for the forecast of interest given as YYYYMMDD (e.g. 20201020). If left blank it defaults to the most recent date. This API provides access to data within the last 30 days.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])(.(00|12)|)$"}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/Forecast/{reach_id}/{return_format}": {"get": {"description": "This operation returns the average of the ensemble forecast.", "summary": "Returns average forecasted flow", "parameters": [{"name": "reach_id", "in": "path", "description": "The stream reach's unique ID also refered to as common identifier (COMID). If the ID is not known, use the getReachID method.", "type": "number", "format": "integer", "required": true}, {"name": "return_format", "in": "path", "required": true, "description": "The format of the response", "type": "string", "default": "csv", "enum": ["csv", "json"]}, {"name": "date", "in": "query", "description": "The given date for the forecast of interest given as YYYYMMDD (e.g. 20201020). If left blank it defaults to the most recent date. This API provides access to data within the last 30 days.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])(.(00|12)|)$"}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/ForecastStats/{reach_id}/{return_format}": {"get": {"description": "This operation returns statistics calculated from 51 forecast ensemble members. A successful response will return a time series with date-value pairs.", "summary": "Return basic forecast statistics", "parameters": [{"name": "reach_id", "in": "path", "description": "The stream reach's unique ID also refered to as common identifier (COMID). If the ID is not known, use the getReachID method.", "type": "number", "format": "integer", "required": true}, {"name": "return_format", "in": "path", "required": true, "description": "The format of the response", "type": "string", "default": "csv", "enum": ["csv", "json"]}, {"name": "date", "in": "query", "description": "The given date for the forecast of interest given as YYYYMMDD (e.g. 20201020). If left blank it defaults to the most recent date. This API provides access to data within the last 30 days.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])(.(00|12)|)$"}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/ForecastEnsembles/{reach_id}/{return_format}": {"get": {"description": "This operation returns a timeseries for each of the 51 normal forecast ensemble members and the 52nd higher resolution forecast. A successful response will return a time series with date-value pairs.", "summary": "Return forecast ensembles", "parameters": [{"name": "reach_id", "in": "path", "description": "The stream reach's unique ID also refered to as common identifier (COMID). If the ID is not known, use the getReachID method.", "type": "number", "format": "integer", "required": true}, {"name": "date", "in": "query", "description": "The given date for the forecast of interest given as YYYYMMDD (e.g. 20201020). If left blank it defaults to the most recent date. This API provides access to data within the last 30 days.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])(.(00|12)|)$"}, {"name": "ensemble", "in": "query", "description": "The desired forecast ensemble(s). Input can be:\n - An individual ensemble (i.e. 5)\n - A group of ensembles separated by commas (i.e. 1,5,9)\n - A range of ensembles separated by a dash (i.e. 3-15)\n - A combination of individual numbers and ranges (i.e. 1,5,7-16,24-35)", "type": "string", "default": "all"}, {"name": "return_format", "in": "path", "required": true, "description": "The format of the response", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series for each ensemble along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/ForecastRecords/{reach_id}/{return_format}": {"get": {"description": "This retrieves the rolling record of the mean of the forecasted streamflow during the first 24 hours of each day's forecast. That is, each day day after the\nstreamflow forecasts are computed, the average of first 8 of the 3-hour timesteps are recorded to a csv. This retrives that rolling record", "summary": "Return rolling record of average flows", "parameters": [{"name": "reach_id", "in": "path", "description": "The stream reach's unique ID also refered to as common identifier (COMID). If the ID is not known, use the getReachID method.", "type": "number", "format": "integer", "required": true}, {"name": "start_date", "in": "query", "description": "A date in YYYYMMDD format when you would like to start retrieving data (if available). Defaults to Jan 1 of the current year.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$"}, {"name": "end_date", "in": "query", "description": "A date in YYYYMMDD format when you would like to stop retrieving data (if available). Defaults to Dec 31 of the current year.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$"}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series for the specified stream reach"}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/ForecastAnomalies/{reach_id}/{return_format}": {"get": {"description": "Computes the deviations from the daily averages", "summary": "Calculates the differences between the daily average and the forecasted flow for each day", "parameters": [{"name": "reach_id", "in": "path", "description": "The stream reach's unique ID also refered to as common identifier (COMID). If the ID is not known, use the getReachID method.", "type": "number", "format": "integer", "required": true}, {"name": "start_date", "in": "query", "description": "A date in YYYYMMDD format when you would like to start retrieving data (if available). Defaults to Jan 1 of the current year.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$"}, {"name": "end_date", "in": "query", "description": "A date in YYYYMMDD format when you would like to stop retrieving data (if available). Defaults to Dec 31 of the current year.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$"}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series for the specified stream reach"}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/ForecastWarnings/{return_format}": {"get": {"description": "This method returns a csv created to summarize the potential return period level flow events coming to the reaches in a specified region. The CSV contains a column for the reach_id, lat of the reach, lon of the reach, maximum forecasted flow in the next 15 day forecast, and a column for each of the return periods (2, 10, 20, 25, 50, 100) which will contain the date when the forecast is first expected to pass that threshold.", "summary": "Returns potential warnings for the forecast", "parameters": [{"name": "region", "in": "path", "description": "the name of one of the regions that the streamflow forecasts are generated for. You can find this with the AvailableRegions method.", "type": "string", "default": "all", "required": true}, {"name": "forecast_date", "in": "query", "description": "If multiple forecast dates are available, provide the date in the format YYYYMMDD.HH of the forecast you would like to query. Use the AvailableDates method if you need to find out which dates are available. Defaults to the most recent available data.", "type": "string", "format": "string"}, {"name": "return_format", "in": "path", "required": true, "description": "The format of the response", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a csv table with the information previous mentioned."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region or both lat and lon are required as input"}}}}}, "/ForecastDates": {"get": {"description": "This operation returns the available forecast dates in JSON format.", "summary": "Available dates", "produces": ["application/json"], "responses": {"200": {"description": "The response body will contain a list of available dates."}, "204": {"description": "Succesful request but no regions found.", "examples": {"message": "No dates available."}}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/Hindcast/{reach_id}/{return_format}": {"get": {"description": "This operation returns simulated streamflow data based on the ERA-5 dataset. A successful response will return a time series with date-value pairs.", "summary": "Return historic simulation", "parameters": [{"name": "reach_id", "in": "path", "description": "The stream reach's unique ID also refered to as common identifier (COMID). If the ID is not known, use the getReachID method.", "type": "number", "format": "integer", "required": true}, {"name": "return_format", "in": "path", "required": true, "description": "The format of the response", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/DailyAverages/{reach_id}/{return_format}": {"get": {"description": "This operation returns the average flow for each day of the year for the Historic Simulation", "summary": "Return historic simulation's daily averages", "parameters": [{"name": "reach_id", "in": "path", "description": "The stream reach's unique ID also refered to as common identifier (COMID). If the ID is not known, use the getReachID method.", "type": "number", "format": "integer", "required": true}, {"name": "return_format", "in": "path", "required": true, "description": "The format of the response", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/MonthlyAverages/{reach_id}/{return_format}": {"get": {"description": "This operation returns the average flow for each month of the year for the Historic Simulation", "summary": "Return historic simulation's monthly averages", "parameters": [{"name": "reach_id", "in": "path", "description": "The stream reach's unique ID also refered to as common identifier (COMID). If the ID is not known, use the getReachID method.", "type": "number", "format": "integer", "required": true}, {"name": "return_format", "in": "path", "required": true, "description": "The format of the response", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/ReturnPeriods/{reach_id}/{return_format}": {"get": {"description": "This operation returns the 2, 5, 10, 25, 50, and 100 year return period based on the 40-years simulated streamflow data and using the Gumbel Method. A successful response will return key-value pairs for earch return period along with metadata.", "summary": "Return historic simulation", "parameters": [{"name": "reach_id", "in": "path", "description": "The stream reach's unique ID also refered to as common identifier (COMID). If the ID is not known, use the getReachID method.", "type": "number", "format": "integer", "required": true}, {"name": "return_format", "in": "path", "required": true, "description": "The format of the response", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a key-value pairs for each return period along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/getReachID": {"get": {"description": "Find the Reach ID nearest a point using latitude and longitude coordinates", "summary": "Find the Reach ID nearest a point using latitude and longitude coordinates", "parameters": [{"name": "lat", "in": "query", "required": true, "description": "The latitude of a point to search", "type": "number", "format": "float"}, {"name": "lon", "in": "query", "required": true, "description": "The longitude of a point to search", "type": "number", "format": "float"}], "produces": ["application/json"], "responses": {"200": {"description": null}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/ForecastStats": {"get": {"description": "This operation returns statistics calculated from 51 forecast ensemble members. A successful response will return a time series with date-value pairs.", "summary": "Return basic forecast statistics (if unable to provide reach_id, lat and lon can be provided as query arguments)", "parameters": [{"name": "lat", "in": "query", "description": "A given latitude used to find the closest stream reach. Must be used together with `lon`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "lon", "in": "query", "description": "A given longitude used to find the closest stream reach. Must be used together with `lat`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "date", "in": "query", "description": "The given date for the forecast of interest given as YYYYMMDD (e.g. 20201020). If left blank it defaults to the most recent date. This API provides access to data within the last 30 days.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])(.(00|12)|)$"}, {"name": "return_format", "in": "query", "description": "The format of the time series response.", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/ForecastEnsembles": {"get": {"description": "This operation returns a timeseries for each of the 51 normal forecast ensemble members and the 52nd higher resolution forecast. A successful response will return a time series with date-value pairs.", "summary": "Return forecast ensembles", "parameters": [{"name": "lat", "in": "query", "description": "A given latitude used to find the closest stream reach. Must be used together with `lon`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "lon", "in": "query", "description": "A given longitude used to find the closest stream reach. Must be used together with `lat`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "date", "in": "query", "description": "The given date for the forecast of interest given as YYYYMMDD (e.g. 20201020). If left blank it defaults to the most recent date. This API provides access to data within the last 30 days.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])(.(00|12)|)$"}, {"name": "ensemble", "in": "query", "description": "The desired forecast ensemble(s). Input can be:\n - An individual ensemble (i.e. 5)\n - A group of ensembles separated by commas (i.e. 1,5,9)\n - A range of ensembles separated by a dash (i.e. 3-15)\n - A combination of individual numbers and ranges (i.e. 1,5,7-16,24-35)", "type": "string", "default": "all"}, {"name": "return_format", "in": "query", "description": "The format of the time series response.", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series for each ensemble along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/ForecastRecords": {"get": {"description": "This retrieves the rolling record of the mean of the forecasted streamflow during the first 24 hours of each day's forecast. That is, each day day after the\nstreamflow forecasts are computed, the average of first 8 of the 3-hour timesteps are recorded to a csv. This retrieves that rolling record", "summary": "Return rolling record of average flows", "parameters": [{"name": "lat", "in": "query", "description": "A given latitude used to find the closest stream reach. Must be used together with `lon`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "lon", "in": "query", "description": "A given longitude used to find the closest stream reach. Must be used together with `lat`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "start_date", "in": "query", "description": "A date in YYYYMMDD format when you would like to start retrieving data (if available). Defaults to Jan 1 of the current year.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$"}, {"name": "end_date", "in": "query", "description": "A date in YYYYMMDD format when you would like to stop retrieving data (if available). Defaults to Dec 31 of the current year.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$"}], "produces": ["text/csv"], "responses": {"200": {"description": "The response body will contain a time series for the specified stream reach"}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/Hindcast": {"get": {"description": "This operation returns simulated streamflow data based on the ERA-5 dataset. A successful response will return a time series with date-value pairs.", "summary": "Return historic simulation", "parameters": [{"name": "lat", "in": "query", "description": "A given latitude used to find the closest stream reach. Must be used together with `lon`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "lon", "in": "query", "description": "A given longitude used to find the closest stream reach. Must be used together with `lat`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "return_format", "in": "query", "description": "The format of the time series response.", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/DailyAverages": {"get": {"description": "This operation returns the average flow for each day of the year for the Historic Simulation", "summary": "Return historic simulation's daily averages", "parameters": [{"name": "lat", "in": "query", "description": "A given latitude used to find the closest stream reach. Must be used together with `lon`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "lon", "in": "query", "description": "A given longitude used to find the closest stream reach. Must be used together with `lat`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "return_format", "in": "query", "description": "The format of the time series response.", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/MonthlyAverages": {"get": {"description": "This operation returns the average flow for each month of the year for the Historic Simulation", "summary": "Return historic simulation's monthly averages", "parameters": [{"name": "lat", "in": "query", "description": "A given latitude used to find the closest stream reach. Must be used together with `lon`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "lon", "in": "query", "description": "A given longitude used to find the closest stream reach. Must be used together with `lat`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "return_format", "in": "query", "description": "The format of the time series response.", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/ReturnPeriods": {"get": {"description": "This operation returns the 2, 5, 10, 25, 50, and 100 year return period based on the 40-years simulated streamflow data and using the Gumbel Method. A successful response will return key-value pairs for earch return period along with metadata.", "summary": "Return historic simulation", "parameters": [{"name": "lat", "in": "query", "description": "A given latitude used to find the closest stream reach. Must be used together with `lon`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "lon", "in": "query", "description": "A given longitude used to find the closest stream reach. Must be used together with `lat`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "return_format", "in": "query", "description": "The format of the time series response.", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a key-value pairs for each return period along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}}}; | |||
const spec = {"swagger": "2.0", "info": {"title": "GEOGLOWS ECMWF Streamflow Data Service", "description": "A REST Data Service to access high resolution streamflow forecasts from around the world", "version": "2.0.0"}, "host": "geoglows.ecmwf.int", "basePath": "/api", "schemes": ["https", "http"], "paths": {"/Hydroviewer/{reach_id}/{return_format}": {"get": {"description": "A shorthand for retrieving the forecast records and stats, and return periods, usually all plotted together.", "summary": "Returns forecast records, forecast stats, and return periods.", "parameters": [{"name": "reach_id", "in": "path", "description": "The stream reach's unique ID also refered to as common identifier (COMID). If the ID is not known, use the getReachID method.", "type": "number", "format": "integer", "required": true}, {"name": "return_format", "in": "path", "required": true, "description": "The format of the response", "type": "string", "default": "csv", "enum": ["csv", "json"]}, {"name": "date", "in": "query", "description": "The given date for the forecast of interest given as YYYYMMDD (e.g. 20201020). If left blank it defaults to the most recent date. This API provides access to data within the last 30 days.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])(.(00|12)|)$"}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/Forecast/{reach_id}/{return_format}": {"get": {"description": "This operation returns the average of the ensemble forecast.", "summary": "Returns average forecasted flow", "parameters": [{"name": "reach_id", "in": "path", "description": "The stream reach's unique ID also refered to as common identifier (COMID). If the ID is not known, use the getReachID method.", "type": "number", "format": "integer", "required": true}, {"name": "return_format", "in": "path", "required": true, "description": "The format of the response", "type": "string", "default": "csv", "enum": ["csv", "json"]}, {"name": "date", "in": "query", "description": "The given date for the forecast of interest given as YYYYMMDD (e.g. 20201020). If left blank it defaults to the most recent date. This API provides access to data within the last 30 days.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])(.(00|12)|)$"}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/ForecastStats/{reach_id}/{return_format}": {"get": {"description": "This operation returns statistics calculated from 51 forecast ensemble members. A successful response will return a time series with date-value pairs.", "summary": "Return basic forecast statistics", "parameters": [{"name": "reach_id", "in": "path", "description": "The stream reach's unique ID also refered to as common identifier (COMID). If the ID is not known, use the getReachID method.", "type": "number", "format": "integer", "required": true}, {"name": "return_format", "in": "path", "required": true, "description": "The format of the response", "type": "string", "default": "csv", "enum": ["csv", "json"]}, {"name": "date", "in": "query", "description": "The given date for the forecast of interest given as YYYYMMDD (e.g. 20201020). If left blank it defaults to the most recent date. This API provides access to data within the last 30 days.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])(.(00|12)|)$"}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/ForecastEnsembles/{reach_id}/{return_format}": {"get": {"description": "This operation returns a timeseries for each of the 51 normal forecast ensemble members and the 52nd higher resolution forecast. A successful response will return a time series with date-value pairs.", "summary": "Return forecast ensembles", "parameters": [{"name": "reach_id", "in": "path", "description": "The stream reach's unique ID also refered to as common identifier (COMID). If the ID is not known, use the getReachID method.", "type": "number", "format": "integer", "required": true}, {"name": "date", "in": "query", "description": "The given date for the forecast of interest given as YYYYMMDD (e.g. 20201020). If left blank it defaults to the most recent date. This API provides access to data within the last 30 days.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])(.(00|12)|)$"}, {"name": "ensemble", "in": "query", "description": "The desired forecast ensemble(s). Input can be:\n - An individual ensemble (i.e. 5)\n - A group of ensembles separated by commas (i.e. 1,5,9)\n - A range of ensembles separated by a dash (i.e. 3-15)\n - A combination of individual numbers and ranges (i.e. 1,5,7-16,24-35)", "type": "string", "default": "all"}, {"name": "return_format", "in": "path", "required": true, "description": "The format of the response", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series for each ensemble along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/ForecastRecords/{reach_id}/{return_format}": {"get": {"description": "This retrieves the rolling record of the mean of the forecasted streamflow during the first 24 hours of each day's forecast. That is, each day day after the\nstreamflow forecasts are computed, the average of first 8 of the 3-hour timesteps are recorded to a csv. This retrives that rolling record", "summary": "Return rolling record of average flows", "parameters": [{"name": "reach_id", "in": "path", "description": "The stream reach's unique ID also refered to as common identifier (COMID). If the ID is not known, use the getReachID method.", "type": "number", "format": "integer", "required": true}, {"name": "start_date", "in": "query", "description": "A date in YYYYMMDD format when you would like to start retrieving data (if available). Defaults to Jan 1 of the current year.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$"}, {"name": "end_date", "in": "query", "description": "A date in YYYYMMDD format when you would like to stop retrieving data (if available). Defaults to Dec 31 of the current year.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$"}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series for the specified stream reach"}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/ForecastAnomalies/{reach_id}/{return_format}": {"get": {"description": "Computes the deviations from the daily averages", "summary": "Calculates the differences between the daily average and the forecasted flow for each day", "parameters": [{"name": "reach_id", "in": "path", "description": "The stream reach's unique ID also refered to as common identifier (COMID). If the ID is not known, use the getReachID method.", "type": "number", "format": "integer", "required": true}, {"name": "start_date", "in": "query", "description": "A date in YYYYMMDD format when you would like to start retrieving data (if available). Defaults to Jan 1 of the current year.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$"}, {"name": "end_date", "in": "query", "description": "A date in YYYYMMDD format when you would like to stop retrieving data (if available). Defaults to Dec 31 of the current year.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$"}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series for the specified stream reach"}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/ForecastWarnings/{return_format}": {"get": {"description": "This method returns a csv created to summarize the potential return period level flow events coming to the reaches in a specified region. The CSV contains a column for the reach_id, lat of the reach, lon of the reach, maximum forecasted flow in the next 15 day forecast, and a column for each of the return periods (2, 10, 20, 25, 50, 100) which will contain the date when the forecast is first expected to pass that threshold.", "summary": "Returns potential warnings for the forecast", "parameters": [{"name": "region", "in": "path", "description": "the name of one of the regions that the streamflow forecasts are generated for. You can find this with the AvailableRegions method.", "type": "string", "default": "all", "required": true}, {"name": "forecast_date", "in": "query", "description": "If multiple forecast dates are available, provide the date in the format YYYYMMDD.HH of the forecast you would like to query. Use the AvailableDates method if you need to find out which dates are available. Defaults to the most recent available data.", "type": "string", "format": "string"}, {"name": "return_format", "in": "path", "required": true, "description": "The format of the response", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a csv table with the information previous mentioned."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region or both lat and lon are required as input"}}}}}, "/ForecastDates": {"get": {"description": "This operation returns the available forecast dates in JSON format.", "summary": "Available dates", "produces": ["application/json"], "responses": {"200": {"description": "The response body will contain a list of available dates."}, "204": {"description": "Succesful request but no regions found.", "examples": {"message": "No dates available."}}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/Hindcast/{reach_id}/{return_format}": {"get": {"description": "This operation returns simulated streamflow data based on the ERA-5 dataset. A successful response will return a time series with date-value pairs.", "summary": "Return historic simulation", "parameters": [{"name": "reach_id", "in": "path", "description": "The stream reach's unique ID also refered to as common identifier (COMID). If the ID is not known, use the getReachID method.", "type": "number", "format": "integer", "required": true}, {"name": "return_format", "in": "path", "required": true, "description": "The format of the response", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/DailyAverages/{reach_id}/{return_format}": {"get": {"description": "This operation returns the average flow for each day of the year for the Historic Simulation", "summary": "Return historic simulation's daily averages", "parameters": [{"name": "reach_id", "in": "path", "description": "The stream reach's unique ID also refered to as common identifier (COMID). If the ID is not known, use the getReachID method.", "type": "number", "format": "integer", "required": true}, {"name": "return_format", "in": "path", "required": true, "description": "The format of the response", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/MonthlyAverages/{reach_id}/{return_format}": {"get": {"description": "This operation returns the average flow for each month of the year for the Historic Simulation", "summary": "Return historic simulation's monthly averages", "parameters": [{"name": "reach_id", "in": "path", "description": "The stream reach's unique ID also refered to as common identifier (COMID). If the ID is not known, use the getReachID method.", "type": "number", "format": "integer", "required": true}, {"name": "return_format", "in": "path", "required": true, "description": "The format of the response", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/ReturnPeriods/{reach_id}/{return_format}": {"get": {"description": "This operation returns the 2, 5, 10, 25, 50, and 100 year return period based on the 40-years simulated streamflow data and using the Gumbel Method. A successful response will return key-value pairs for earch return period along with metadata.", "summary": "Return historic simulation", "parameters": [{"name": "reach_id", "in": "path", "description": "The stream reach's unique ID also refered to as common identifier (COMID). If the ID is not known, use the getReachID method.", "type": "number", "format": "integer", "required": true}, {"name": "return_format", "in": "path", "required": true, "description": "The format of the response", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a key-value pairs for each return period along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/getReachID": {"get": {"description": "Find the Reach ID nearest a point using latitude and longitude coordinates", "summary": "Find the Reach ID nearest a point using latitude and longitude coordinates", "parameters": [{"name": "lat", "in": "query", "required": true, "description": "The latitude of a point to search", "type": "number", "format": "float"}, {"name": "lon", "in": "query", "required": true, "description": "The longitude of a point to search", "type": "number", "format": "float"}], "produces": ["application/json"], "responses": {"200": {"description": null}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/ForecastStats": {"get": {"description": "This operation returns statistics calculated from 51 forecast ensemble members. A successful response will return a time series with date-value pairs.", "summary": "Return basic forecast statistics (if unable to provide reach_id, lat and lon can be provided as query arguments)", "parameters": [{"name": "lat", "in": "query", "description": "A given latitude used to find the closest stream reach. Must be used together with `lon`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "lon", "in": "query", "description": "A given longitude used to find the closest stream reach. Must be used together with `lat`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "date", "in": "query", "description": "The given date for the forecast of interest given as YYYYMMDD (e.g. 20201020). If left blank it defaults to the most recent date. This API provides access to data within the last 30 days.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])(.(00|12)|)$"}, {"name": "return_format", "in": "query", "description": "The format of the time series response.", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/ForecastEnsembles": {"get": {"description": "This operation returns a timeseries for each of the 51 normal forecast ensemble members and the 52nd higher resolution forecast. A successful response will return a time series with date-value pairs.", "summary": "Return forecast ensembles", "parameters": [{"name": "lat", "in": "query", "description": "A given latitude used to find the closest stream reach. Must be used together with `lon`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "lon", "in": "query", "description": "A given longitude used to find the closest stream reach. Must be used together with `lat`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "date", "in": "query", "description": "The given date for the forecast of interest given as YYYYMMDD (e.g. 20201020). If left blank it defaults to the most recent date. This API provides access to data within the last 30 days.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])(.(00|12)|)$"}, {"name": "ensemble", "in": "query", "description": "The desired forecast ensemble(s). Input can be:\n - An individual ensemble (i.e. 5)\n - A group of ensembles separated by commas (i.e. 1,5,9)\n - A range of ensembles separated by a dash (i.e. 3-15)\n - A combination of individual numbers and ranges (i.e. 1,5,7-16,24-35)", "type": "string", "default": "all"}, {"name": "return_format", "in": "query", "description": "The format of the time series response.", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series for each ensemble along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/ForecastRecords": {"get": {"description": "This retrieves the rolling record of the mean of the forecasted streamflow during the first 24 hours of each day's forecast. That is, each day day after the\nstreamflow forecasts are computed, the average of first 8 of the 3-hour timesteps are recorded to a csv. This retrieves that rolling record", "summary": "Return rolling record of average flows", "parameters": [{"name": "lat", "in": "query", "description": "A given latitude used to find the closest stream reach. Must be used together with `lon`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "lon", "in": "query", "description": "A given longitude used to find the closest stream reach. Must be used together with `lat`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "start_date", "in": "query", "description": "A date in YYYYMMDD format when you would like to start retrieving data (if available). Defaults to Jan 1 of the current year.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$"}, {"name": "end_date", "in": "query", "description": "A date in YYYYMMDD format when you would like to stop retrieving data (if available). Defaults to Dec 31 of the current year.", "type": "string", "pattern": "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$"}], "produces": ["text/csv"], "responses": {"200": {"description": "The response body will contain a time series for the specified stream reach"}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/Hindcast": {"get": {"description": "This operation returns simulated streamflow data based on the ERA-5 dataset. A successful response will return a time series with date-value pairs.", "summary": "Return historic simulation", "parameters": [{"name": "lat", "in": "query", "description": "A given latitude used to find the closest stream reach. Must be used together with `lon`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "lon", "in": "query", "description": "A given longitude used to find the closest stream reach. Must be used together with `lat`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "return_format", "in": "query", "description": "The format of the time series response.", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/DailyAverages": {"get": {"description": "This operation returns the average flow for each day of the year for the Historic Simulation", "summary": "Return historic simulation's daily averages", "parameters": [{"name": "lat", "in": "query", "description": "A given latitude used to find the closest stream reach. Must be used together with `lon`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "lon", "in": "query", "description": "A given longitude used to find the closest stream reach. Must be used together with `lat`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "return_format", "in": "query", "description": "The format of the time series response.", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/MonthlyAverages": {"get": {"description": "This operation returns the average flow for each month of the year for the Historic Simulation", "summary": "Return historic simulation's monthly averages", "parameters": [{"name": "lat", "in": "query", "description": "A given latitude used to find the closest stream reach. Must be used together with `lon`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "lon", "in": "query", "description": "A given longitude used to find the closest stream reach. Must be used together with `lat`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "return_format", "in": "query", "description": "The format of the time series response.", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a time series along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}, "/ReturnPeriods": {"get": {"description": "This operation returns the 2, 5, 10, 25, 50, and 100 year return period based on the 40-years simulated streamflow data and using the Gumbel Method. A successful response will return key-value pairs for earch return period along with metadata.", "summary": "Return historic simulation", "parameters": [{"name": "lat", "in": "query", "description": "A given latitude used to find the closest stream reach. Must be used together with `lon`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "lon", "in": "query", "description": "A given longitude used to find the closest stream reach. Must be used together with `lat`. The spatial query uses the center point of the stream reach to determine proximity. This parameter can be given instead of providing `reach_id` in the path. A lat/lon spatial query will take longer than providing the reach_id. It is recommended that the reach_id be used instead once it is known.", "type": "number", "format": "float"}, {"name": "return_format", "in": "query", "description": "The format of the time series response.", "type": "string", "default": "csv", "enum": ["csv", "json"]}], "produces": ["text/csv", "application/json"], "responses": {"200": {"description": "The response body will contain a key-value pairs for each return period along with metadata about the stream reach of interest."}, "400": {"description": "Bad request. Check request and paramaters.", "examples": {"error": "An unexpected error occured."}}, "422": {"description": "Missing a required parameter.", "examples": {"error": "region is required as input."}}}}}}}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Swagger specification is using version 2.0. Consider upgrading to OpenAPI 3.0 for enhanced features and improved support for API documentation. Additionally, ensure that the inclusion of both HTTP and HTTPS schemes is intentional and that appropriate security measures are in place for HTTP connections.
app/v2/constants.py
Outdated
PATH_TO_FORECASTS = '/mnt/output/forecasts' | ||
PATH_TO_FORECAST_RECORDS = '/mnt/output/forecast-records' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hardcoded paths to forecasts and forecast records may limit flexibility in different deployment environments. Consider making these paths configurable through environment variables.
app/v2/constants.py
Outdated
ODP_S3_BUCKET_URI = 's3://geoglows-v2' | ||
ODP_S3_BUCKET_REGION = 'us-west-2' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hardcoded S3 bucket URI and region may expose sensitive information and limit flexibility. Consider making these details configurable through environment variables.
def get_reach_id(lat: float, lon: float, *, format: str = 'csv'): | ||
""" | ||
Finds the reach ID nearest to a given lat/lon | ||
Uses the ModelMasterTable to find the locations | ||
""" | ||
reach_id, dist_error = latlon_to_reach(lat, lon) | ||
if format == 'csv': | ||
return df_to_csv_flask_response(pd.DataFrame(dict(reach_id=[reach_id, ], dist_error=[dist_error, ])), | ||
csv_name='reach_id', index=False) | ||
elif format == 'json': | ||
return jsonify(dict(reach_id=reach_id, dist_error=dist_error)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The get_reach_id
function lacks input validation for lat
and lon
parameters. Consider adding checks to ensure they are within valid ranges for latitude (-90 to 90) and longitude (-180 to 180).
def log_request(version: str, product: str, reach_id: int, return_format: str, source: str): | ||
log_message = { | ||
'version': version, | ||
'product': product.lower().replace(" ", ""), | ||
'reach_id': reach_id, | ||
'return_format': return_format, | ||
'source': source, | ||
} | ||
|
||
# Send the log message to CloudWatch | ||
response = client.put_log_events( | ||
logGroupName=LOG_GROUP_NAME, | ||
logStreamName=LOG_STREAM_NAME, | ||
logEvents=[ | ||
{ | ||
'timestamp': int(round(time.time() * 1000)), | ||
'message': json.dumps(log_message) | ||
} | ||
] | ||
) | ||
return response |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The log_request
function lacks error handling for potential failures in logging to CloudWatch Logs. Consider adding try-except blocks to gracefully handle exceptions and ensure the application's stability.
@app.route(f'/api/<product>', methods=['GET']) | ||
@app.route(f'/api/v1/<product>', methods=['GET']) | ||
@cross_origin() | ||
def rest_endpoints_v1(product: str): | ||
log_request(version="v1", | ||
product=product, | ||
reach_id=request.args.get('reach_id', 0), | ||
return_format=request.args.get('return_format', 'csv'), | ||
source=request.args.get('source', 'other'), ) | ||
|
||
# forecast data products | ||
if product == 'ForecastStats': | ||
return forecast_stats(request) | ||
elif product == 'ForecastEnsembles': | ||
return forecast_ensembles(request) | ||
elif product == 'ForecastWarnings': | ||
return forecast_warnings(request) | ||
elif product == 'ForecastRecords': | ||
return forecast_records(request) | ||
|
||
# historical data products | ||
elif product == 'HistoricSimulation': | ||
return historical(request) | ||
elif product == 'ReturnPeriods': | ||
return return_periods(request) | ||
elif product == 'DailyAverages': | ||
return historical_averages(request, 'daily') | ||
elif product == 'MonthlyAverages': | ||
return historical_averages(request, 'monthly') | ||
|
||
elif product == 'AvailableData': | ||
return get_available_data_handler() | ||
elif product == 'AvailableRegions': | ||
return get_region_handler() | ||
elif product == 'AvailableDates': | ||
return available_dates(request) | ||
elif product == 'GetReachID': | ||
return get_reach_id_from_latlon_handler(request) | ||
|
||
else: | ||
return jsonify({'status': f'data product "{product}" not available'}), 201 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Flask Blueprint and routes for version 1 REST endpoints are correctly defined. Consider enhancing the error handling for unsupported products by providing more detailed information or suggestions for valid products. This can improve the API's usability and help consumers in diagnosing issues.
app/v2/data.py
Outdated
def get_forecast_dataset(reach_id: int, date: str) -> xr.Dataset: | ||
""" | ||
Opens the forecast dataset for a given date, selects the reach_id and Qout variable | ||
""" | ||
if date == "latest": | ||
date = find_available_dates()[-1] | ||
|
||
if len(date) == 8: | ||
date = f"{date}00" | ||
|
||
forecast_file = os.path.join(PATH_TO_FORECASTS, f'{date}.zarr') | ||
|
||
if not os.path.exists(forecast_file): | ||
raise ValueError(f'Data not found for date {date}. Use YYYYMMDD format and the AvailableDates endpoint.') | ||
|
||
try: | ||
forecast_dataset = xr.open_zarr(forecast_file) | ||
except Exception as e: | ||
print(e) | ||
raise ValueError('Error while reading data from the zarr files') | ||
try: | ||
return forecast_dataset.sel(rivid=reach_id).Qout | ||
except Exception as e: | ||
print(e) | ||
raise ValueError(f'Unable to get data for reach_id {reach_id} in the forecast dataset') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The get_forecast_dataset
function correctly retrieves forecast data. Consider adding more detailed error messages for cases where the data is not found or there's an error reading the zarr files. This can help in diagnosing issues more effectively.
def latlon_to_reach(lat: float, lon: float) -> list: | ||
""" | ||
Finds the reach ID nearest to a given lat/lon | ||
Uses the ModelMasterTable to find the locations | ||
""" | ||
df = pd.read_parquet('/mnt/configs/geoglows-v2-geographic-properties-table.parquet', | ||
columns=['LINKNO', 'lat', 'lon']) | ||
df['distance'] = ((df['lat'] - lat) ** 2 + (df['lon'] - lon) ** 2) ** 0.5 | ||
return df.sort_values('distance').reset_index(drop=True).iloc[0][['TDXHydroLinkNo', 'distance']].values.flatten() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tip
Codebase Verification
The geographic properties table is not accessible at the specified path (/mnt/configs/geoglows-v2-geographic-properties-table.parquet
). This could potentially affect the functionality of the latlon_to_reach
function, which relies on this table. It's important to ensure that the path is correct and accessible in the deployment environment.
Analysis chain
The latlon_to_reach
function correctly finds the nearest reach ID to a given latitude and longitude. Verify that the path to the geographic properties table (/mnt/configs/geoglows-v2-geographic-properties-table.parquet
) is accessible and correct in the deployment environment.
Scripts Executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Verify the accessibility of the geographic properties table
if [ -f "/mnt/configs/geoglows-v2-geographic-properties-table.parquet" ]; then
echo "Geographic properties table is accessible."
else
echo "Geographic properties table is not accessible. Check the path."
fi
Length of output: 208
app/v2/controllers_historical.py
Outdated
def retrospective(reach_id: int, units: str, return_format: str, start_date: str = None, | ||
end_date: str = None) -> pd.DataFrame: | ||
""" | ||
Controller for retrieving simulated historic data | ||
""" | ||
df = _get_retrospective_df(reach_id) | ||
|
||
if units == 'cfs': | ||
df *= M3_TO_FT3 | ||
if start_date is not None: | ||
df = df.loc[df.index >= datetime.datetime.strptime(start_date, '%Y%m%d')] | ||
if end_date is not None: | ||
df = df.loc[df.index <= datetime.datetime.strptime(end_date, '%Y%m%d')] | ||
|
||
if return_format == 'csv': | ||
return df_to_csv_flask_response(df, f'retrospective_{reach_id}_{units}') | ||
if return_format == 'json': | ||
return df_to_jsonify_response(df=df, reach_id=reach_id, units=units) | ||
return df |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The retrospective
function correctly handles unit conversion and date filtering. Consider adding input validation for units
and return_format
to ensure they match expected values.
+ # Validate units and return_format
+ if units not in ['cfs', 'cms']:
+ raise ValueError("Invalid units. Expected 'cfs' or 'cms'.")
+ if return_format not in ['csv', 'json']:
+ raise ValueError("Invalid return_format. Expected 'csv' or 'json'.")
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.
def retrospective(reach_id: int, units: str, return_format: str, start_date: str = None, | |
end_date: str = None) -> pd.DataFrame: | |
""" | |
Controller for retrieving simulated historic data | |
""" | |
df = _get_retrospective_df(reach_id) | |
if units == 'cfs': | |
df *= M3_TO_FT3 | |
if start_date is not None: | |
df = df.loc[df.index >= datetime.datetime.strptime(start_date, '%Y%m%d')] | |
if end_date is not None: | |
df = df.loc[df.index <= datetime.datetime.strptime(end_date, '%Y%m%d')] | |
if return_format == 'csv': | |
return df_to_csv_flask_response(df, f'retrospective_{reach_id}_{units}') | |
if return_format == 'json': | |
return df_to_jsonify_response(df=df, reach_id=reach_id, units=units) | |
return df | |
def retrospective(reach_id: int, units: str, return_format: str, start_date: str = None, | |
end_date: str = None) -> pd.DataFrame: | |
""" | |
Controller for retrieving simulated historic data | |
""" | |
# Validate units and return_format | |
if units not in ['cfs', 'cms']: | |
raise ValueError("Invalid units. Expected 'cfs' or 'cms'.") | |
if return_format not in ['csv', 'json']: | |
raise ValueError("Invalid return_format. Expected 'csv' or 'json'.") | |
df = _get_retrospective_df(reach_id) | |
if units == 'cfs': | |
df *= M3_TO_FT3 | |
if start_date is not None: | |
df = df.loc[df.index >= datetime.datetime.strptime(start_date, '%Y%m%d')] | |
if end_date is not None: | |
df = df.loc[df.index <= datetime.datetime.strptime(end_date, '%Y%m%d')] | |
if return_format == 'csv': | |
return df_to_csv_flask_response(df, f'retrospective_{reach_id}_{units}') | |
if return_format == 'json': | |
return df_to_jsonify_response(df=df, reach_id=reach_id, units=units) | |
return df |
app/v2/blueprint.py
Outdated
@app.route(f'/api/latest/<product>/', methods=['GET']) | ||
@app.route(f'/api/latest/<product>/<reach_id>', methods=['GET']) | ||
@app.route(f'/api/v2/<product>/', methods=['GET']) | ||
@app.route(f'/api/v2/<product>/<reach_id>', methods=['GET']) | ||
@cross_origin() | ||
def rest_endpoints_v2(product: str, reach_id: int = None): | ||
product, reach_id, format, units, date, ensemble, start_date, end_date = handle_request( | ||
request, | ||
product, | ||
reach_id, | ||
) | ||
|
||
log_request(version="v2", | ||
product=product, | ||
reach_id=request.args.get('reach_id', 0), | ||
return_format=format, | ||
source=request.args.get('source', 'other'), ) | ||
|
||
# forecast data products | ||
if product == 'forecast': | ||
return forecast(reach_id, date, units, format) | ||
elif product in 'forecaststats': | ||
return forecast_stats(reach_id, date, units, format) | ||
elif product == 'forecastensembles': | ||
return forecast_ensembles(reach_id, date, units, format, ensemble) | ||
elif product == 'forecastrecords': | ||
return forecast_records(reach_id, start_date, end_date, units, format) | ||
elif product == 'forecastwarnings': | ||
return forecast_warnings(date, format) | ||
elif product == 'dates': | ||
return forecast_dates(return_format=format) | ||
|
||
# hindcast data products | ||
elif product == 'retrospective': | ||
return retrospective(reach_id, units, format) | ||
elif product == 'returnperiods': | ||
return return_periods(reach_id, units, format) | ||
elif product == 'dailyaverages': | ||
return daily_averages(reach_id, units, format) | ||
elif product == 'monthlyaverages': | ||
return monthly_averages(reach_id, units, format) | ||
elif product == 'annualaverages': | ||
return yearly_averages(reach_id, units, format) | ||
|
||
# data availability | ||
elif product == 'getreachid': | ||
return get_reach_id(request, format=format) | ||
|
||
elif product == "hydroviewer": | ||
return hydroviewer(reach_id, start_date, date, units, format) | ||
|
||
else: | ||
return jsonify({'error': f'data product "{product}" not available'}), 201 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The route definitions are comprehensive and cover a wide range of data products. Verify that all routes are documented and that their parameters are validated to prevent injection attacks or unexpected errors.
+ # Add parameter validation for all routes
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.
@app.route(f'/api/latest/<product>/', methods=['GET']) | |
@app.route(f'/api/latest/<product>/<reach_id>', methods=['GET']) | |
@app.route(f'/api/v2/<product>/', methods=['GET']) | |
@app.route(f'/api/v2/<product>/<reach_id>', methods=['GET']) | |
@cross_origin() | |
def rest_endpoints_v2(product: str, reach_id: int = None): | |
product, reach_id, format, units, date, ensemble, start_date, end_date = handle_request( | |
request, | |
product, | |
reach_id, | |
) | |
log_request(version="v2", | |
product=product, | |
reach_id=request.args.get('reach_id', 0), | |
return_format=format, | |
source=request.args.get('source', 'other'), ) | |
# forecast data products | |
if product == 'forecast': | |
return forecast(reach_id, date, units, format) | |
elif product in 'forecaststats': | |
return forecast_stats(reach_id, date, units, format) | |
elif product == 'forecastensembles': | |
return forecast_ensembles(reach_id, date, units, format, ensemble) | |
elif product == 'forecastrecords': | |
return forecast_records(reach_id, start_date, end_date, units, format) | |
elif product == 'forecastwarnings': | |
return forecast_warnings(date, format) | |
elif product == 'dates': | |
return forecast_dates(return_format=format) | |
# hindcast data products | |
elif product == 'retrospective': | |
return retrospective(reach_id, units, format) | |
elif product == 'returnperiods': | |
return return_periods(reach_id, units, format) | |
elif product == 'dailyaverages': | |
return daily_averages(reach_id, units, format) | |
elif product == 'monthlyaverages': | |
return monthly_averages(reach_id, units, format) | |
elif product == 'annualaverages': | |
return yearly_averages(reach_id, units, format) | |
# data availability | |
elif product == 'getreachid': | |
return get_reach_id(request, format=format) | |
elif product == "hydroviewer": | |
return hydroviewer(reach_id, start_date, date, units, format) | |
else: | |
return jsonify({'error': f'data product "{product}" not available'}), 201 | |
@app.route(f'/api/latest/<product>/', methods=['GET']) | |
@app.route(f'/api/latest/<product>/<reach_id>', methods=['GET']) | |
@app.route(f'/api/v2/<product>/', methods=['GET']) | |
@app.route(f'/api/v2/<product>/<reach_id>', methods=['GET']) | |
@cross_origin() | |
def rest_endpoints_v2(product: str, reach_id: int = None): | |
# Add parameter validation for all routes | |
product, reach_id, format, units, date, ensemble, start_date, end_date = handle_request( | |
request, | |
product, | |
reach_id, | |
) | |
log_request(version="v2", | |
product=product, | |
reach_id=request.args.get('reach_id', 0), | |
return_format=format, | |
source=request.args.get('source', 'other'), ) | |
# forecast data products | |
if product == 'forecast': | |
return forecast(reach_id, date, units, format) | |
elif product in 'forecaststats': | |
return forecast_stats(reach_id, date, units, format) | |
elif product == 'forecastensembles': | |
return forecast_ensembles(reach_id, date, units, format, ensemble) | |
elif product == 'forecastrecords': | |
return forecast_records(reach_id, start_date, end_date, units, format) | |
elif product == 'forecastwarnings': | |
return forecast_warnings(date, format) | |
elif product == 'dates': | |
return forecast_dates(return_format=format) | |
# hindcast data products | |
elif product == 'retrospective': | |
return retrospective(reach_id, units, format) | |
elif product == 'returnperiods': | |
return return_periods(reach_id, units, format) | |
elif product == 'dailyaverages': | |
return daily_averages(reach_id, units, format) | |
elif product == 'monthlyaverages': | |
return monthly_averages(reach_id, units, format) | |
elif product == 'annualaverages': | |
return yearly_averages(reach_id, units, format) | |
# data availability | |
elif product == 'getreachid': | |
return get_reach_id(request, format=format) | |
elif product == "hydroviewer": | |
return hydroviewer(reach_id, start_date, date, units, format) | |
else: | |
return jsonify({'error': f'data product "{product}" not available'}), 201 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review Status
Actionable comments generated: 0
Configuration used: CodeRabbit UI
Files selected for processing (3)
- app/v2/constants.py (1 hunks)
- app/v2/controllers_historical.py (1 hunks)
- app/v2/data.py (1 hunks)
Files skipped from review as they are similar to previous changes (3)
- app/v2/constants.py
- app/v2/controllers_historical.py
- app/v2/data.py
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review Status
Actionable comments generated: 0
Configuration used: CodeRabbit UI
Files selected for processing (2)
- app/v2/controllers_historical.py (1 hunks)
- app/v2/response_formatters.py (1 hunks)
Files skipped from review as they are similar to previous changes (2)
- app/v2/controllers_historical.py
- app/v2/response_formatters.py
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review Status
Actionable comments generated: 0
Configuration used: CodeRabbit UI
Files ignored due to path filters (1)
docs/swagger_doc.yaml
is excluded by:!**/*.yaml
Files selected for processing (1)
- README.md (1 hunks)
Additional comments: 2
README.md (2)
- 1-1: The project name casing correction from "GEOGloWS" to "GEOGLOWS" is accurate and aligns with the PR objectives for standardization.
- 3-3: While the static analysis tool flagged potential spelling mistakes and a missing article, these are largely false positives due to the technical nature of the content. However, it's always beneficial to have another set of eyes review technical documentation for clarity and correctness.
Summary by CodeRabbit
.gitignore
to exclude specific directories and files.