From e09e80fa4f7f7f91a29ee33856ca2bfd725e183d Mon Sep 17 00:00:00 2001 From: Ben Allfree Date: Tue, 14 Nov 2023 16:57:35 -0800 Subject: [PATCH] chore: REST refactor --- .../src/pocketbase-client/PocketbaseClient.ts | 4 +- .../[instanceId]/Danger/Maintenance.svelte | 2 +- .../[instanceId]/Danger/RenameInstance.svelte | 2 +- .../[instanceId]/Danger/VersionChange.svelte | 2 +- .../[instanceId]/Secrets/Form.svelte | 2 +- .../pb_hooks/src/instances-update.pb.js | 29 ++++++++------ .../pocketbase-client-helpers/RestHelper.ts | 39 ++++++++++++++++--- src/shared/schema/Rest/UpdateInstance.ts | 24 ++++++------ src/shared/schema/Rest/index.ts | 6 +-- 9 files changed, 73 insertions(+), 37 deletions(-) diff --git a/frontends/dashboard/src/pocketbase-client/PocketbaseClient.ts b/frontends/dashboard/src/pocketbase-client/PocketbaseClient.ts index c7316a8c..e5ec19c2 100644 --- a/frontends/dashboard/src/pocketbase-client/PocketbaseClient.ts +++ b/frontends/dashboard/src/pocketbase-client/PocketbaseClient.ts @@ -100,13 +100,13 @@ export const createPocketbaseClient = (config: PocketbaseClientConfig) => { const createInstance = mkRest( RestCommands.Instance, - RestMethods.Create, + RestMethods.Post, CreateInstancePayloadSchema, ) const updateInstance = mkRest( RestCommands.Instance, - RestMethods.Update, + RestMethods.Put, UpdateInstancePayloadSchema, ) diff --git a/frontends/dashboard/src/routes/app/instances/[instanceId]/Danger/Maintenance.svelte b/frontends/dashboard/src/routes/app/instances/[instanceId]/Danger/Maintenance.svelte index 2a1104b3..a3be5441 100644 --- a/frontends/dashboard/src/routes/app/instances/[instanceId]/Danger/Maintenance.svelte +++ b/frontends/dashboard/src/routes/app/instances/[instanceId]/Danger/Maintenance.svelte @@ -14,7 +14,7 @@ const isChecked = target.checked // Update the database with the new value - updateInstance({ instanceId: id, fields: { maintenance: isChecked } }).then( + updateInstance({ id, fields: { maintenance: isChecked } }).then( () => 'saved', ) } diff --git a/frontends/dashboard/src/routes/app/instances/[instanceId]/Danger/RenameInstance.svelte b/frontends/dashboard/src/routes/app/instances/[instanceId]/Danger/RenameInstance.svelte index b096a57f..4aaa7c8b 100644 --- a/frontends/dashboard/src/routes/app/instances/[instanceId]/Danger/RenameInstance.svelte +++ b/frontends/dashboard/src/routes/app/instances/[instanceId]/Danger/RenameInstance.svelte @@ -40,7 +40,7 @@ // If they select yes, then update the version in pocketbase if (confirmVersionChange) { updateInstance({ - instanceId: id, + id, fields: { subdomain: instanceNameValidation, }, diff --git a/frontends/dashboard/src/routes/app/instances/[instanceId]/Danger/VersionChange.svelte b/frontends/dashboard/src/routes/app/instances/[instanceId]/Danger/VersionChange.svelte index e71ab08a..146c1604 100644 --- a/frontends/dashboard/src/routes/app/instances/[instanceId]/Danger/VersionChange.svelte +++ b/frontends/dashboard/src/routes/app/instances/[instanceId]/Danger/VersionChange.svelte @@ -39,7 +39,7 @@ errorMessage = '' client() .updateInstance({ - instanceId: id, + id, fields: { version: selectedVersion }, }) .then(() => { diff --git a/frontends/dashboard/src/routes/app/instances/[instanceId]/Secrets/Form.svelte b/frontends/dashboard/src/routes/app/instances/[instanceId]/Secrets/Form.svelte index 451f28c4..48ba734f 100644 --- a/frontends/dashboard/src/routes/app/instances/[instanceId]/Secrets/Form.svelte +++ b/frontends/dashboard/src/routes/app/instances/[instanceId]/Secrets/Form.svelte @@ -44,7 +44,7 @@ // Save to the database items.upsert({ name: secretKey, value: secretValue }) await client().updateInstance({ - instanceId: $instance.id, + id: $instance.id, fields: { secrets: reduce( $items, diff --git a/src/mothership-app/pb_hooks/src/instances-update.pb.js b/src/mothership-app/pb_hooks/src/instances-update.pb.js index d67be63e..7f9d4e77 100644 --- a/src/mothership-app/pb_hooks/src/instances-update.pb.js +++ b/src/mothership-app/pb_hooks/src/instances-update.pb.js @@ -2,7 +2,7 @@ /* { - "instanceId": "kz4ngg77eaw1ho0", + "id": "kz4ngg77eaw1ho0", "fields": { "maintenance": true "name": '', @@ -12,12 +12,11 @@ */ routerAdd( 'PUT', - '/api/instance', + '/api/instance/:id', (c) => { - console.log(`***TOP OF PUt`) + console.log(`***TOP OF PUT`) let data = new DynamicModel({ - // describe the shape of the fields to read (used also as initial values) - instanceId: '', + id: '', fields: { maintenance: null, name: null, @@ -27,21 +26,28 @@ routerAdd( }) c.bind(data) + console.log(`***After bind`) // This is necessary for destructuring to work correctly data = JSON.parse(JSON.stringify(data)) + const id = c.pathParam('id') const { - instanceId, fields: { maintenance, name, version, secrets }, } = data console.log( `***vars`, - JSON.stringify({ instanceId, maintenance, name, version, secrets }), + JSON.stringify({ + id, + maintenance, + name, + version, + secrets, + }), ) - const record = $app.dao().findRecordById('instances', instanceId) + const record = $app.dao().findRecordById('instances', id) const authRecord = c.get('authRecord') // empty if not authenticated as regular auth record console.log(`***authRecord`, JSON.stringify(authRecord)) @@ -53,22 +59,23 @@ routerAdd( } function cleanObject(obj) { - return Object.entries(obj).reduce((acc, [key, value]) => { + console.log(`***original`, JSON.stringify(obj)) + const sanitized = Object.entries(obj).reduce((acc, [key, value]) => { if (value !== null && value !== undefined) { acc[key] = value } return acc }, {}) + console.log(`***sanitized`, JSON.stringify(sanitized)) + return sanitized } - console.log(`***original`, JSON.stringify(data)) const sanitized = cleanObject({ subdomain: name, version, maintenance, secrets, }) - console.log(`***sanitized`, JSON.stringify(sanitized)) const form = new RecordUpsertForm($app, record) form.loadData(sanitized) diff --git a/src/shared/pocketbase-client-helpers/RestHelper.ts b/src/shared/pocketbase-client-helpers/RestHelper.ts index 5593e390..ef993234 100644 --- a/src/shared/pocketbase-client-helpers/RestHelper.ts +++ b/src/shared/pocketbase-client-helpers/RestHelper.ts @@ -1,5 +1,6 @@ import Ajv, { JSONSchemaType } from 'ajv' import type pocketbaseEs from 'pocketbase' +import { ClientResponseError } from 'pocketbase' import type { JsonObject } from 'type-fest' import { LoggerService } from '../Logger' import { RestCommands, RestMethods } from '../schema' @@ -28,13 +29,41 @@ export const createRestHelper = (config: RestHelperConfig) => { if (!validator(payload)) { throw new Error(`Invalid REST payload: ${validator.errors}`) } + const _payload = { ...payload } - const res = await client.send(`/api/${cmd}`, { - method: method, - body: payload, + const url = `/api/${cmd}${ + method === RestMethods.Post ? '' : '/:id' + }`.replace(/:([a-zA-Z]+)/g, (_, key) => { + if (!(key in _payload)) { + throw new Error(`Payload must include '${key}`) + } + const value = _payload[key]! + delete _payload[key] + return encodeURIComponent(value.toString()) }) - dbg(res) - return res + + const options: any = { + method: method, + } + + if (method !== RestMethods.Get) { + options.body = _payload + } + + dbg({ url, options }) + + try { + const res = await client.send(url, options) + dbg(res) + return res + } catch (e) { + if (e instanceof ClientResponseError) { + error(`REST error: ${e.originalError}`) + throw e.originalError + } + error(`REST error: ${e}`) + throw e + } } } diff --git a/src/shared/schema/Rest/UpdateInstance.ts b/src/shared/schema/Rest/UpdateInstance.ts index 3e697f5a..7c6fa0ce 100644 --- a/src/shared/schema/Rest/UpdateInstance.ts +++ b/src/shared/schema/Rest/UpdateInstance.ts @@ -1,16 +1,15 @@ import { JSONSchemaType } from 'ajv' -import { InstanceId, Semver } from '../types' +import { InstanceFields } from '../Instance' +import { InstanceId } from '../types' export type UpdateInstancePayload = { - instanceId: InstanceId - fields: { - subdomain?: string - maintenance?: boolean - version?: Semver - secrets?: { - [_: string]: string - } - } + id: InstanceId + fields: Partial< + Pick< + InstanceFields, + 'maintenance' | 'secrets' | 'subdomain' | 'syncAdmin' | 'version' + > + > } export const SECRET_KEY_REGEX = /^[A-Z][A-Z0-9_]*$/ @@ -24,10 +23,11 @@ export const UpdateInstancePayloadSchema: JSONSchemaType { type: 'object', properties: { - instanceId: { type: 'string' }, + id: { type: 'string' }, fields: { type: 'object', properties: { + syncAdmin: { type: 'boolean', nullable: true }, subdomain: { type: 'string', nullable: true }, maintenance: { type: 'boolean', nullable: true }, version: { @@ -47,6 +47,6 @@ export const UpdateInstancePayloadSchema: JSONSchemaType }, }, }, - required: ['instanceId', 'fields'], + required: ['id', 'fields'], additionalProperties: false, } diff --git a/src/shared/schema/Rest/index.ts b/src/shared/schema/Rest/index.ts index 3bac05be..fc43f6ea 100644 --- a/src/shared/schema/Rest/index.ts +++ b/src/shared/schema/Rest/index.ts @@ -2,8 +2,9 @@ import Ajv from 'ajv' import { JsonObject } from 'type-fest' export enum RestMethods { - Create = 'POST', - Update = 'PUT', + Get = 'GET', + Post = 'POST', + Put = 'PUT', } export enum RestCommands { @@ -16,4 +17,3 @@ export const ajv = new Ajv() export * from './CreateInstance' export * from './UpdateInstance' -// gen:export