parent
b535d94910
commit
97dd9aab58
3 changed files with 98 additions and 23 deletions
|
|
@ -62,6 +62,17 @@ To run the API, follow these steps from the root directory of the project:
|
|||
|
||||
The web server will be accessible at [http://localhost:8081/](http://localhost:8081/).
|
||||
|
||||
!!! warning "CORS Configuration"
|
||||
When running a client web application on a different domain than the REST API server,
|
||||
do not forget to set the environment variable `CAIMIRA_ALLOWED_ORIGINS`:
|
||||
|
||||
`export CAIMIRA_ALLOWED_ORIGINS="https://myclientapp.org"`
|
||||
|
||||
If you need to allow multiple domains, input a comma-separated list of domains:
|
||||
|
||||
`export CAIMIRA_ALLOWED_ORIGINS="https://myclientapp.org,https://myclientapp2.org"`
|
||||
|
||||
|
||||
### API Endpoints
|
||||
|
||||
Currently, the REST API contains two routing categories that provide the generation of results for the main CAiMIRA outputs:
|
||||
|
|
|
|||
|
|
@ -1,13 +1,36 @@
|
|||
import os
|
||||
import tornado.web
|
||||
|
||||
|
||||
class BaseRequestHandler(tornado.web.RequestHandler):
|
||||
class CorsHandler(tornado.web.RequestHandler):
|
||||
"""Handler to manage CORS (Cross-Origin Resource Sharing) configuration.
|
||||
|
||||
This handler implements CORS support by setting appropriate headers for cross-origin requests.
|
||||
It checks allowed origins against environment variable CAIMIRA_ALLOWED_ORIGINS and enables
|
||||
CORS for matching origins.
|
||||
"""
|
||||
|
||||
def set_default_headers(self):
|
||||
self.set_header("Access-Control-Allow-Origin", "*")
|
||||
self.set_header("Access-Control-Allow-Headers", "x-requested-with")
|
||||
self.set_header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
|
||||
allowed_origins = os.environ.get("CAIMIRA_ALLOWED_ORIGINS", None)
|
||||
request_origin = self.request.headers.get("Origin", None) # can have value `null`
|
||||
if allowed_origins and request_origin:
|
||||
allowed_origins = [origin.lower().strip() for origin in allowed_origins.split(",")]
|
||||
if request_origin.lower() in allowed_origins:
|
||||
self.set_header("Access-Control-Allow-Origin", request_origin)
|
||||
|
||||
def options(self, *args):
|
||||
self.set_header("Access-Control-Allow-Methods", "POST, OPTIONS")
|
||||
self.set_header("Access-Control-Allow-Headers", "Content-Type")
|
||||
self.set_status(204) # No Content
|
||||
|
||||
|
||||
class BaseRequestHandler(CorsHandler):
|
||||
"""Base handler for HTTP requests extending CorsHandler.
|
||||
|
||||
This class provides base functionality for handling HTTP requests with CORS support.
|
||||
It includes error handling capabilities by overriding the write_error method.
|
||||
"""
|
||||
|
||||
def write_error(self, status_code, **kwargs):
|
||||
self.set_status(status_code)
|
||||
self.write({"message": kwargs.get('exc_info')[1].__str__()})
|
||||
|
||||
41
caimira/tests/apps/test_api_app.py
Normal file
41
caimira/tests/apps/test_api_app.py
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import os
|
||||
from tornado.testing import AsyncHTTPTestCase
|
||||
from caimira.api.app import Application
|
||||
|
||||
class TestAPIApp(AsyncHTTPTestCase):
|
||||
def get_app(self):
|
||||
return Application(debug=True)
|
||||
|
||||
def test_api_app(self):
|
||||
response = self.fetch("/")
|
||||
assert response.code == 200
|
||||
|
||||
def test_cors(self):
|
||||
# test unset env
|
||||
response = self.fetch("/", method="OPTIONS", headers={"Origin": "http://example.com"})
|
||||
assert response.code == 204
|
||||
assert "Access-Control-Allow-Origin" not in response.headers
|
||||
|
||||
# test None and empty value
|
||||
os.environ["CAIMIRA_ALLOWED_ORIGINS"] = ""
|
||||
response = self.fetch("/", method="OPTIONS", headers={"Origin": "http://example.com"})
|
||||
assert response.code == 204
|
||||
assert "Access-Control-Allow-Origin" not in response.headers
|
||||
|
||||
# test allowing single domain
|
||||
os.environ["CAIMIRA_ALLOWED_ORIGINS"] = "http://example.com"
|
||||
response = self.fetch("/", method="OPTIONS", headers={"Origin": "http://example.com"})
|
||||
assert response.code == 204
|
||||
assert response.headers["Access-Control-Allow-Origin"] == "http://example.com"
|
||||
|
||||
# test allowing multiple domains
|
||||
os.environ["CAIMIRA_ALLOWED_ORIGINS"] = "http://example.com, http://example2.com"
|
||||
response = self.fetch("/", method="OPTIONS", headers={"Origin": "http://example2.com"})
|
||||
assert response.code == 204
|
||||
assert response.headers["Access-Control-Allow-Origin"] == "http://example2.com"
|
||||
|
||||
# test `null` value for Origin header
|
||||
os.environ["CAIMIRA_ALLOWED_ORIGINS"] = "http://example.com"
|
||||
response = self.fetch("/", method="OPTIONS", headers={"Origin": "null"})
|
||||
assert response.code == 204
|
||||
assert "Access-Control-Allow-Origin" not in response.headers
|
||||
Loading…
Reference in a new issue