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()