diff --git a/archivebox/api/urls.py b/archivebox/api/urls.py index 5d3877e9..81f8cb43 100644 --- a/archivebox/api/urls.py +++ b/archivebox/api/urls.py @@ -1,111 +1,17 @@ __package__ = 'archivebox.api' -# import orjson - -from io import StringIO -from traceback import format_exception -from contextlib import redirect_stdout, redirect_stderr - from django.urls import path -from django.http import HttpRequest, HttpResponse from django.views.generic.base import RedirectView -from django.core.exceptions import ObjectDoesNotExist, EmptyResultSet, PermissionDenied - -from ninja import NinjaAPI, Swagger - -# TODO: explore adding https://eadwincode.github.io/django-ninja-extra/ - -from api.auth import API_AUTH_METHODS -from ..config import VERSION, COMMIT_HASH - -# from ninja.renderers import BaseRenderer - -# class ORJSONRenderer(BaseRenderer): -# media_type = "application/json" - -# def render(self, request, data, *, response_status): -# return { -# "success": True, -# "errors": [], -# "result": data, -# "stdout": ansi_to_html(stdout.getvalue().strip()), -# "stderr": ansi_to_html(stderr.getvalue().strip()), -# } -# return orjson.dumps(data) - - -class NinjaAPIWithIOCapture(NinjaAPI): - def create_temporal_response(self, request: HttpRequest) -> HttpResponse: - stdout, stderr = StringIO(), StringIO() - - with redirect_stderr(stderr): - with redirect_stdout(stdout): - request.stdout = stdout - request.stderr = stderr - - response = super().create_temporal_response(request) - - print('RESPONDING NOW', response) - - return response - -html_description=f''' -
[v1 ALPHA]
homepage!archivebox/api/
{COMMIT_HASH[:8]}
), API powered by django-ninja
.
-'''
-
-api = NinjaAPIWithIOCapture(
- title='ArchiveBox API',
- description=html_description,
- version='1.0.0',
- csrf=False,
- auth=API_AUTH_METHODS,
- urls_namespace="api",
- docs=Swagger(settings={"persistAuthorization": True}),
- # docs_decorator=login_required,
- # renderer=ORJSONRenderer(),
-)
-api.add_router('/auth/', 'api.routes_auth.router')
-api.add_router('/core/', 'api.routes_core.router')
-api.add_router('/cli/', 'api.routes_cli.router')
-
-
-@api.exception_handler(Exception)
-def generic_exception_handler(request, err):
- status = 503
- if isinstance(err, (ObjectDoesNotExist, EmptyResultSet, PermissionDenied)):
- status = 404
-
- print(''.join(format_exception(err)))
-
- return api.create_response(
- request,
- {
- "succeeded": False,
- "errors": [
- ''.join(format_exception(err)),
- # or send simpler exception-only summary without full traceback:
- # f'{err.__class__.__name__}: {err}',
- # *([str(err.__context__)] if getattr(err, '__context__', None) else []),
- ],
- },
- status=status,
- )
+from .v1_api import urls as v1_api_urls
urlpatterns = [
- path("v1/", api.urls),
+ path("", RedirectView.as_view(url='/api/v1')),
+ path("v1/", v1_api_urls),
path("v1", RedirectView.as_view(url='/api/v1/docs')),
- path("", RedirectView.as_view(url='/api/v1/docs')),
+
+ # ... v2 can be added here ...
+ # path("v2/", v2_api_urls),
+ # path("v2", RedirectView.as_view(url='/api/v2/docs')),
]
diff --git a/archivebox/api/v1_api.py b/archivebox/api/v1_api.py
new file mode 100644
index 00000000..6b2c8c63
--- /dev/null
+++ b/archivebox/api/v1_api.py
@@ -0,0 +1,109 @@
+__package__ = 'archivebox.api'
+
+
+from io import StringIO
+from traceback import format_exception
+from contextlib import redirect_stdout, redirect_stderr
+
+from django.http import HttpRequest, HttpResponse
+from django.core.exceptions import ObjectDoesNotExist, EmptyResultSet, PermissionDenied
+
+from ninja import NinjaAPI, Swagger
+
+# TODO: explore adding https://eadwincode.github.io/django-ninja-extra/
+
+from api.auth import API_AUTH_METHODS
+from ..config import VERSION, COMMIT_HASH
+
+
+html_description=f'''
+[v1 ALPHA]
homepage!archivebox/api/
{COMMIT_HASH[:8]}
), API powered by django-ninja
.
+'''
+
+
+def register_urls(api: NinjaAPI) -> NinjaAPI:
+ api.add_router('/auth/', 'api.v1_auth.router')
+ api.add_router('/core/', 'api.v1_core.router')
+ api.add_router('/cli/', 'api.v1_cli.router')
+ return api
+
+
+class NinjaAPIWithIOCapture(NinjaAPI):
+ def create_temporal_response(self, request: HttpRequest) -> HttpResponse:
+ stdout, stderr = StringIO(), StringIO()
+
+ with redirect_stderr(stderr):
+ with redirect_stdout(stdout):
+ request.stdout = stdout
+ request.stderr = stderr
+
+ response = super().create_temporal_response(request)
+
+ print('RESPONDING NOW', response)
+
+ return response
+
+
+api = NinjaAPIWithIOCapture(
+ title='ArchiveBox API',
+ description=html_description,
+ version='1.0.0',
+ csrf=False,
+ auth=API_AUTH_METHODS,
+ urls_namespace="api",
+ docs=Swagger(settings={"persistAuthorization": True}),
+ # docs_decorator=login_required,
+ # renderer=ORJSONRenderer(),
+)
+api = register_urls(api)
+urls = api.urls
+
+
+@api.exception_handler(Exception)
+def generic_exception_handler(request, err):
+ status = 503
+ if isinstance(err, (ObjectDoesNotExist, EmptyResultSet, PermissionDenied)):
+ status = 404
+
+ print(''.join(format_exception(err)))
+
+ return api.create_response(
+ request,
+ {
+ "succeeded": False,
+ "message": f'{err.__class__.__name__}: {err}',
+ "errors": [
+ ''.join(format_exception(err)),
+ # or send simpler parent-only traceback:
+ # *([str(err.__context__)] if getattr(err, '__context__', None) else []),
+ ],
+ },
+ status=status,
+ )
+
+
+
+# import orjson
+# from ninja.renderers import BaseRenderer
+# class ORJSONRenderer(BaseRenderer):
+# media_type = "application/json"
+# def render(self, request, data, *, response_status):
+# return {
+# "success": True,
+# "errors": [],
+# "result": data,
+# "stdout": ansi_to_html(stdout.getvalue().strip()),
+# "stderr": ansi_to_html(stderr.getvalue().strip()),
+# }
+# return orjson.dumps(data)
diff --git a/archivebox/api/routes_auth.py b/archivebox/api/v1_auth.py
similarity index 100%
rename from archivebox/api/routes_auth.py
rename to archivebox/api/v1_auth.py
diff --git a/archivebox/api/routes_cli.py b/archivebox/api/v1_cli.py
similarity index 98%
rename from archivebox/api/routes_cli.py
rename to archivebox/api/v1_cli.py
index 4bef5088..6e737464 100644
--- a/archivebox/api/routes_cli.py
+++ b/archivebox/api/v1_cli.py
@@ -3,8 +3,6 @@ __package__ = 'archivebox.api'
from typing import List, Dict, Any, Optional
from enum import Enum
-# from pydantic import BaseModel
-from archivebox.api.routes_core import paginate
from ninja import Router, Schema
from ..main import (
diff --git a/archivebox/api/routes_core.py b/archivebox/api/v1_core.py
similarity index 100%
rename from archivebox/api/routes_core.py
rename to archivebox/api/v1_core.py