From 7c7c09aa3d0f996e91525a35ae66e9e0818e4c91 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Sat, 10 Jan 2026 22:29:11 +0100 Subject: [PATCH 1/3] fix(api): create service validation and docs - if service type and docker_compose_raw is filled show an error - if service type is not valid show an error with all valid service types - remove enum from service type docs as it always gets outdated --- .../Controllers/Api/ServicesController.php | 107 +++--------------- 1 file changed, 13 insertions(+), 94 deletions(-) diff --git a/app/Http/Controllers/Api/ServicesController.php b/app/Http/Controllers/Api/ServicesController.php index 6a00818aa..ec3d036bc 100644 --- a/app/Http/Controllers/Api/ServicesController.php +++ b/app/Http/Controllers/Api/ServicesController.php @@ -105,98 +105,7 @@ public function services(Request $request) type: 'object', required: ['server_uuid', 'project_uuid', 'environment_name', 'environment_uuid'], properties: [ - 'type' => [ - 'description' => 'The one-click service type', - 'type' => 'string', - 'enum' => [ - 'activepieces', - 'appsmith', - 'appwrite', - 'authentik', - 'babybuddy', - 'budge', - 'changedetection', - 'chatwoot', - 'classicpress-with-mariadb', - 'classicpress-with-mysql', - 'classicpress-without-database', - 'cloudflared', - 'code-server', - 'dashboard', - 'directus', - 'directus-with-postgresql', - 'docker-registry', - 'docuseal', - 'docuseal-with-postgres', - 'dokuwiki', - 'duplicati', - 'emby', - 'embystat', - 'fider', - 'filebrowser', - 'firefly', - 'formbricks', - 'ghost', - 'gitea', - 'gitea-with-mariadb', - 'gitea-with-mysql', - 'gitea-with-postgresql', - 'glance', - 'glances', - 'glitchtip', - 'grafana', - 'grafana-with-postgresql', - 'grocy', - 'heimdall', - 'homepage', - 'jellyfin', - 'kuzzle', - 'listmonk', - 'logto', - 'mediawiki', - 'meilisearch', - 'metabase', - 'metube', - 'minio', - 'moodle', - 'n8n', - 'n8n-with-postgresql', - 'next-image-transformation', - 'nextcloud', - 'nocodb', - 'odoo', - 'openblocks', - 'pairdrop', - 'penpot', - 'phpmyadmin', - 'pocketbase', - 'posthog', - 'reactive-resume', - 'rocketchat', - 'shlink', - 'slash', - 'snapdrop', - 'statusnook', - 'stirling-pdf', - 'supabase', - 'syncthing', - 'tolgee', - 'trigger', - 'trigger-with-external-database', - 'twenty', - 'umami', - 'unleash-with-postgresql', - 'unleash-without-database', - 'uptime-kuma', - 'vaultwarden', - 'vikunja', - 'weblate', - 'whoogle', - 'wordpress-with-mariadb', - 'wordpress-with-mysql', - 'wordpress-without-database', - ], - ], + 'type' => ['description' => 'The one-click service type (e.g. "actualbudget", "calibre-web", "gitea-with-mysql" ...)', 'type' => 'string'], 'name' => ['type' => 'string', 'maxLength' => 255, 'description' => 'Name of the service.'], 'description' => ['type' => 'string', 'nullable' => true, 'description' => 'Description of the service.'], 'project_uuid' => ['type' => 'string', 'description' => 'Project UUID.'], @@ -283,6 +192,13 @@ public function create_service(Request $request) 'errors' => $errors, ], 422); } + + if (filled($request->type) && filled($request->docker_compose_raw)) { + return response()->json([ + 'message' => 'You cannot provide both service type and docker_compose_raw. Use one or the other.', + ], 422); + } + $environmentUuid = $request->environment_uuid; $environmentName = $request->environment_name; if (blank($environmentUuid) && blank($environmentName)) { @@ -524,8 +440,11 @@ public function create_service(Request $request) 'uuid' => $service->uuid, 'domains' => $domains, ])->setStatusCode(201); - } else { - return response()->json(['message' => 'No service type or docker_compose_raw provided.'], 400); + } elseif (filled($request->type)) { + return response()->json([ + 'message' => 'Invalid service type.', + 'valid_service_types' => $serviceKeys, + ], 404); } } From 9c0e308dd35aae4ff06d4c7e3552f281e894c24e Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Sun, 11 Jan 2026 18:26:11 +0100 Subject: [PATCH 2/3] refactor(api): make docker_compose_raw description more clear --- app/Http/Controllers/Api/ServicesController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Api/ServicesController.php b/app/Http/Controllers/Api/ServicesController.php index ec3d036bc..4025898b9 100644 --- a/app/Http/Controllers/Api/ServicesController.php +++ b/app/Http/Controllers/Api/ServicesController.php @@ -114,7 +114,7 @@ public function services(Request $request) 'server_uuid' => ['type' => 'string', 'description' => 'Server UUID.'], 'destination_uuid' => ['type' => 'string', 'description' => 'Destination UUID. Required if server has multiple destinations.'], 'instant_deploy' => ['type' => 'boolean', 'default' => false, 'description' => 'Start the service immediately after creation.'], - 'docker_compose_raw' => ['type' => 'string', 'description' => 'The Docker Compose raw content.'], + 'docker_compose_raw' => ['type' => 'string', 'description' => 'The base64 encoded Docker Compose content.'], ], ), ), @@ -621,7 +621,7 @@ public function delete_by_uuid(Request $request) 'destination_uuid' => ['type' => 'string', 'description' => 'The destination UUID.'], 'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the service should be deployed instantly.'], 'connect_to_docker_network' => ['type' => 'boolean', 'default' => false, 'description' => 'Connect the service to the predefined docker network.'], - 'docker_compose_raw' => ['type' => 'string', 'description' => 'The Docker Compose raw content.'], + 'docker_compose_raw' => ['type' => 'string', 'description' => 'The base64 encoded Docker Compose content.'], ], ) ), From ca2d02d8a344a039a8fc8863a78831bd6aa4ac52 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Sat, 10 Jan 2026 22:31:06 +0100 Subject: [PATCH 3/3] chore(api): update openapi json and yaml --- openapi.json | 96 +++------------------------------------------------- openapi.yaml | 7 ++-- 2 files changed, 7 insertions(+), 96 deletions(-) diff --git a/openapi.json b/openapi.json index 5a2465a10..9c31f7628 100644 --- a/openapi.json +++ b/openapi.json @@ -8809,96 +8809,8 @@ ], "properties": { "type": { - "description": "The one-click service type", - "type": "string", - "enum": [ - "activepieces", - "appsmith", - "appwrite", - "authentik", - "babybuddy", - "budge", - "changedetection", - "chatwoot", - "classicpress-with-mariadb", - "classicpress-with-mysql", - "classicpress-without-database", - "cloudflared", - "code-server", - "dashboard", - "directus", - "directus-with-postgresql", - "docker-registry", - "docuseal", - "docuseal-with-postgres", - "dokuwiki", - "duplicati", - "emby", - "embystat", - "fider", - "filebrowser", - "firefly", - "formbricks", - "ghost", - "gitea", - "gitea-with-mariadb", - "gitea-with-mysql", - "gitea-with-postgresql", - "glance", - "glances", - "glitchtip", - "grafana", - "grafana-with-postgresql", - "grocy", - "heimdall", - "homepage", - "jellyfin", - "kuzzle", - "listmonk", - "logto", - "mediawiki", - "meilisearch", - "metabase", - "metube", - "minio", - "moodle", - "n8n", - "n8n-with-postgresql", - "next-image-transformation", - "nextcloud", - "nocodb", - "odoo", - "openblocks", - "pairdrop", - "penpot", - "phpmyadmin", - "pocketbase", - "posthog", - "reactive-resume", - "rocketchat", - "shlink", - "slash", - "snapdrop", - "statusnook", - "stirling-pdf", - "supabase", - "syncthing", - "tolgee", - "trigger", - "trigger-with-external-database", - "twenty", - "umami", - "unleash-with-postgresql", - "unleash-without-database", - "uptime-kuma", - "vaultwarden", - "vikunja", - "weblate", - "whoogle", - "wordpress-with-mariadb", - "wordpress-with-mysql", - "wordpress-without-database" - ] + "description": "The one-click service type (e.g. \"actualbudget\", \"calibre-web\", \"gitea-with-mysql\" ...)", + "type": "string" }, "name": { "type": "string", @@ -8937,7 +8849,7 @@ }, "docker_compose_raw": { "type": "string", - "description": "The Docker Compose raw content." + "description": "The base64 encoded Docker Compose content." } }, "type": "object" @@ -9187,7 +9099,7 @@ }, "docker_compose_raw": { "type": "string", - "description": "The Docker Compose raw content." + "description": "The base64 encoded Docker Compose content." } }, "type": "object" diff --git a/openapi.yaml b/openapi.yaml index 28aba508f..198322328 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -5581,9 +5581,8 @@ paths: - environment_uuid properties: type: - description: 'The one-click service type' + description: 'The one-click service type (e.g. "actualbudget", "calibre-web", "gitea-with-mysql" ...)' type: string - enum: [activepieces, appsmith, appwrite, authentik, babybuddy, budge, changedetection, chatwoot, classicpress-with-mariadb, classicpress-with-mysql, classicpress-without-database, cloudflared, code-server, dashboard, directus, directus-with-postgresql, docker-registry, docuseal, docuseal-with-postgres, dokuwiki, duplicati, emby, embystat, fider, filebrowser, firefly, formbricks, ghost, gitea, gitea-with-mariadb, gitea-with-mysql, gitea-with-postgresql, glance, glances, glitchtip, grafana, grafana-with-postgresql, grocy, heimdall, homepage, jellyfin, kuzzle, listmonk, logto, mediawiki, meilisearch, metabase, metube, minio, moodle, n8n, n8n-with-postgresql, next-image-transformation, nextcloud, nocodb, odoo, openblocks, pairdrop, penpot, phpmyadmin, pocketbase, posthog, reactive-resume, rocketchat, shlink, slash, snapdrop, statusnook, stirling-pdf, supabase, syncthing, tolgee, trigger, trigger-with-external-database, twenty, umami, unleash-with-postgresql, unleash-without-database, uptime-kuma, vaultwarden, vikunja, weblate, whoogle, wordpress-with-mariadb, wordpress-with-mysql, wordpress-without-database] name: type: string maxLength: 255 @@ -5613,7 +5612,7 @@ paths: description: 'Start the service immediately after creation.' docker_compose_raw: type: string - description: 'The Docker Compose raw content.' + description: 'The base64 encoded Docker Compose content.' type: object responses: '201': @@ -5780,7 +5779,7 @@ paths: description: 'Connect the service to the predefined docker network.' docker_compose_raw: type: string - description: 'The Docker Compose raw content.' + description: 'The base64 encoded Docker Compose content.' type: object responses: '200':