From dbeed52875af7b1dfcca129033c76cfa2e718e0d Mon Sep 17 00:00:00 2001 From: starptech Date: Sat, 24 Apr 2021 01:48:16 +0200 Subject: [PATCH] add endpoint to delete PQ entry --- README.md | 15 ++++++++ src/index.ts | 7 ++++ src/repositories/PersistedQueries.ts | 5 +++ src/routes/delete-persisted-query.test.ts | 46 +++++++++++++++++++++++ src/routes/delete-persisted-query.ts | 42 +++++++++++++++++++++ src/test-utils.ts | 4 ++ 6 files changed, 119 insertions(+) create mode 100644 src/routes/delete-persisted-query.test.ts create mode 100644 src/routes/delete-persisted-query.ts diff --git a/README.md b/README.md index 45f8376..1929bf6 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,21 @@ POST - `/persisted_query` Adds persisted query to the KV Storage.

+DELETE - `/persisted_query` Deletes persisted query from KV Storage. + +
+Example Request +

+ +```json +{ + "key": "apq:foo" +} +``` + +

+
+ ### Authentication Clients authenticate via [`Basic-Auth`](https://en.wikipedia.org/wiki/Basic_access_authentication). You have to set the cloudflare secret `ALLOWED_CLIENT_SECRETS=secret1,secret2`. The secret is used as user and pass combination. diff --git a/src/index.ts b/src/index.ts index 0f37086..d9c4f57 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,9 +8,11 @@ import { getPersistedQuery } from './routes/get-persisted-query' import { getSchemaDiff } from './routes/get-schema-diff' import { getSchemaValidation } from './routes/get-schema-validation' import { registerSchema } from './routes/register-schema' +import { deletePersistedQuery } from './routes/delete-persisted-query' const API = new Router() +// Federation API.add('POST', '/schema/push', compose(basicAuth, registerSchema)) API.add('GET', '/schema/latest', compose(basicAuth, getComposedSchema)) API.add( @@ -18,9 +20,14 @@ API.add( '/schema/compose', compose(basicAuth, getComposedSchemaByVersions), ) + +// Tooling API.add('POST', '/schema/validate', compose(basicAuth, getSchemaValidation)) API.add('POST', '/schema/diff', compose(basicAuth, getSchemaDiff)) + +// Persisted queries API.add('POST', '/persisted_query', compose(basicAuth, addPersistedQuery)) API.add('GET', '/persisted_query', compose(basicAuth, getPersistedQuery)) +API.add('DELETE', '/persisted_query', compose(basicAuth, deletePersistedQuery)) listen(API.run) diff --git a/src/repositories/PersistedQueries.ts b/src/repositories/PersistedQueries.ts index 5c9dc17..9c0d853 100644 --- a/src/repositories/PersistedQueries.ts +++ b/src/repositories/PersistedQueries.ts @@ -15,6 +15,11 @@ export function find(uid: string) { return DB.read(PERSISTED_QUERIES, key, 'text') } +export function remove(pqKey: string) { + const key = key_item(pqKey) + return DB.remove(PERSISTED_QUERIES, key) +} + export function save(pqKey: string, query: string) { const key = key_item(pqKey) return DB.write(PERSISTED_QUERIES, key, query, false) diff --git a/src/routes/delete-persisted-query.test.ts b/src/routes/delete-persisted-query.test.ts new file mode 100644 index 0000000..99956c1 --- /dev/null +++ b/src/routes/delete-persisted-query.test.ts @@ -0,0 +1,46 @@ +import test from 'ava' +import { NewNamespace, Request, Response } from '../test-utils' +import { addPersistedQuery } from './add-persisted-query' +import { getPersistedQuery } from './get-persisted-query' +import { deletePersistedQuery } from './delete-persisted-query' + +test.serial('Should delete PQ from KV', async (t) => { + NewNamespace({ + name: 'PERSISTED_QUERIES', + }) + + let req = Request('POST', '', { key: '123', query: 'query' }) + let res = Response() + await addPersistedQuery(req, res) + t.is(res.statusCode, 200) + + req = Request('GET', 'key=123') + res = Response() + await getPersistedQuery(req, res) + t.is(res.statusCode, 200) + t.deepEqual(res.body as any, { + success: true, + data: 'query', + }) + + req = Request('DELETE', '', { key: '123' }) + res = Response() + await deletePersistedQuery(req, res) + t.is(res.statusCode, 200) + + req = Request('GET', 'key=123') + res = Response() + await getPersistedQuery(req, res) + t.is(res.statusCode, 404) +}) + +test.serial('Should return 400 when key was not provided', async (t) => { + NewNamespace({ + name: 'PERSISTED_QUERIES', + }) + + const req = Request('DELETE', '', {}) + const res = Response() + await deletePersistedQuery(req, res) + t.is(res.statusCode, 400) +}) diff --git a/src/routes/delete-persisted-query.ts b/src/routes/delete-persisted-query.ts new file mode 100644 index 0000000..4603d83 --- /dev/null +++ b/src/routes/delete-persisted-query.ts @@ -0,0 +1,42 @@ +import type { Handler } from 'worktop' +import { object, size, string, validate } from 'superstruct' +import { remove as removePQ } from '../repositories/PersistedQueries' + +interface DeletePQRequest { + key: string + query: string +} + +const deleteRequest = object({ + key: size(string(), 1, 100), +}) + +/** + * Deletes persisted query from KV Storage + * + * @param req + * @param res + */ +export const deletePersistedQuery: Handler = async function (req, res) { + const requestBody = await req.body() + const [error, input] = validate(requestBody, deleteRequest) + if (!input || error) { + return res.send(400, { + success: false, + error: error?.message, + }) + } + + const result = await removePQ(input.key) + + if (!result) { + return res.send(404, { + success: false, + error: 'Could not delete persisted query', + }) + } + + res.send(200, { + success: true, + }) +} diff --git a/src/test-utils.ts b/src/test-utils.ts index 0284ff5..354e910 100644 --- a/src/test-utils.ts +++ b/src/test-utils.ts @@ -96,6 +96,10 @@ export const NewNamespace = ( } return Promise.resolve(null) } + binding.delete = (key: string) => { + store.delete(key) + return Promise.resolve() + } binding.put = (key: string, value: any) => { store.set(key, value) return Promise.resolve()