11"""Renku apps blueprints."""
22
33from dataclasses import dataclass
4+ from typing import Any
45
56from sanic import HTTPResponse , Request
6- from sanic .response import JSONResponse , json
7+ from sanic .response import JSONResponse
78from sanic_ext import validate
89from ulid import ULID
910
1011from renku_data_services import base_models
1112from renku_data_services .base_api .auth import authenticate , only_authenticated
1213from renku_data_services .base_api .blueprint import BlueprintFactoryResponse , CustomBlueprint
14+ from renku_data_services .base_models .validation import validated_json
1315from renku_data_services .renku_apps import apispec
16+ from renku_data_services .renku_apps .models import App
1417from renku_data_services .renku_apps .repository import RenkuAppsRepository
1518
1619
@@ -21,6 +24,19 @@ class RenkuAppBP(CustomBlueprint):
2124 apps_repo : RenkuAppsRepository
2225 authenticator : base_models .Authenticator
2326
27+ @staticmethod
28+ def _dump_app (app : App ) -> dict [str , Any ]:
29+ """Dump an app for API responses."""
30+ return dict (
31+ name = app .name ,
32+ launcher_id = str (app .launcher_id ),
33+ project_id = str (app .project_id ),
34+ status = app .status .value ,
35+ url = app .url ,
36+ started = app .started .isoformat () if app .started is not None else None ,
37+ image = app .image ,
38+ )
39+
2440 def post (self ) -> BlueprintFactoryResponse :
2541 """Launch a new app from a session launcher."""
2642
@@ -29,7 +45,7 @@ def post(self) -> BlueprintFactoryResponse:
2945 @validate (json = apispec .AppPostRequest )
3046 async def _post (_ : Request , user : base_models .APIUser , body : apispec .AppPostRequest ) -> JSONResponse :
3147 app = await self .apps_repo .create_app (user = user , launcher_id = ULID .from_str (body .launcher_id ))
32- return json ( app . as_apispec (). model_dump ( exclude_none = True , mode = "json" ), status = 201 )
48+ return validated_json ( apispec . AppResponse , self . _dump_app ( app ), status = 201 )
3349
3450 return "/apps" , ["POST" ], _post
3551
@@ -39,7 +55,7 @@ def get_one(self) -> BlueprintFactoryResponse:
3955 @authenticate (self .authenticator )
4056 async def _get_one (_ : Request , user : base_models .APIUser , app_name : str ) -> JSONResponse :
4157 app = await self .apps_repo .get_app (user = user , app_name = app_name )
42- return json ( app . as_apispec (). model_dump ( exclude_none = True , mode = "json" ))
58+ return validated_json ( apispec . AppResponse , self . _dump_app ( app ))
4359
4460 return "/apps/<app_name>" , ["GET" ], _get_one
4561
@@ -69,7 +85,7 @@ async def _patch_one(
6985 state = body .state ,
7086 resource_class_id = body .resource_class_id ,
7187 )
72- return json ( app . as_apispec (). model_dump ( exclude_none = True , mode = "json" ))
88+ return validated_json ( apispec . AppResponse , self . _dump_app ( app ))
7389
7490 return "/apps/<app_name>" , ["PATCH" ], _patch_one
7591
@@ -83,6 +99,6 @@ async def _get_all(
8399 ) -> JSONResponse :
84100 project_id = ULID .from_str (query .project_id ) if query .project_id is not None else None
85101 apps = await self .apps_repo .list_apps (user = user , project_id = project_id )
86- return json ([ app . as_apispec (). model_dump ( exclude_none = True , mode = "json" ) for app in apps ])
102+ return validated_json ( apispec . AppListResponse , [ self . _dump_app ( app ) for app in apps ])
87103
88104 return "/apps" , ["GET" ], _get_all
0 commit comments