Commit Graph

5 Commits

Author SHA1 Message Date
3a6901e718 fix(openapi): /apps 422 body emits JSON
ValidationError -> UnprocessableEntity(exc.json()) so CLI consumers
can parse the error body. The previous str(errors()) produced a
Python repr (single-quoted dicts), not JSON. Also align with
sibling openapi controllers: request.args.to_dict(flat=True)
and 'as exc' naming.

Test cleanup: hoist module-scope imports; add a happy-path
positive case covering every field.
2026-05-05 20:08:43 -07:00
25034612b8 feat(openapi): AppListQuery — Pydantic validation for /apps
Replaces ad-hoc int(request.args.get(...)) parsing in AppListApi.get
with a typed Pydantic query model. Bad inputs (page=abc, limit=-1,
limit=500, mode=invalid, missing workspace_id) raise ValidationError
which the handler converts to 422 with field-level error detail
instead of 500 / silent empty page. Closes the mode whitelist via
AppMode enum.

Verified via direct unit tests on AppListQuery (no HTTP integration
tests required since the model carries the validation contract).
2026-05-05 20:02:47 -07:00
87620050d7 refactor(openapi): tighten _AppReadResource refactor
- Correct docstring: Flask-RESTX iterates method_decorators forward;
  the last entry becomes outermost via composition, not via framework
  reversal.
- Extract shared _APPS_READ_DECORATORS constant; was duplicated
  verbatim between AppReadResource and AppListApi.
- Rename _AppReadResource -> AppReadResource (no longer module-private
  since app_info.py imports it). Drops the pyright ignore.
2026-05-05 19:59:04 -07:00
e006eb7a4b refactor(openapi): _AppReadResource base for per-app reads
Four per-app GETs (/apps/<id>, /info, /parameters, /describe) repeated
the same SSO-guard / app-load / membership-check pattern. Hoist into
_AppReadResource with method_decorators=[require_scope, validate_bearer]
plus _load(app_id) -> (App, AuthContext). Subclasses now 3-line bodies.
Eliminates the per-method # type: ignore[reportUntypedFunctionDecorator]
suppression by relocating the decorator chain to the class attribute.
Endpoints now build typed AppInfoResponse / AppDescribeResponse and
.model_dump() at the boundary.
2026-05-05 19:51:42 -07:00
86ba361ff1 feat(openapi): app reads + canonical pagination envelope
Read-side surface for difyctl describe / get / list:

- GET /openapi/v1/apps              paginated list (workspace_id required)
- GET /openapi/v1/apps/<id>         single app summary
- GET /openapi/v1/apps/<id>/parameters  port of service_api parameters
- GET /openapi/v1/apps/<id>/describe    merged { info, parameters }

All gated by validate_bearer(ACCEPT_USER_ANY) + require_scope(APPS_READ) +
require_workspace_member(ctx, tenant_id). SSO subjects 404 (account-only
helper account_or_404 deduplicates the guard across the four endpoints).

PaginationEnvelope[T] (page, limit, total, has_more, data) is the canonical
shape for every /openapi/v1/* list endpoint. has_more is computed by the
server from page * limit < total. /account/sessions migrates from the
legacy { sessions: [...] } shape to the envelope; integration tests assert
the legacy key is gone.
2026-05-05 18:08:12 -07:00