Skip to content

Commit

Permalink
refactor(connect): use fetch shim so as to not pass a Request object …
Browse files Browse the repository at this point in the history
…to fetch #566
  • Loading branch information
TillaTheHun0 committed Mar 18, 2023
1 parent 398f260 commit ffcfd89
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 37 deletions.
6 changes: 5 additions & 1 deletion packages/connect/deno/dev_deps.ts
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
export { assert, assertEquals } from 'https://deno.land/[email protected]/testing/asserts.ts'
export {
assert,
assertEquals,
assertObjectMatch,
} from 'https://deno.land/[email protected]/testing/asserts.ts'
77 changes: 43 additions & 34 deletions packages/connect/deno/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import * as search from './services/search.ts'
import * as info from './services/info.ts'
import * as storage from './services/storage.ts'
import * as queue from './services/queue.ts'
import { hyper } from './utils/hyper-request.ts'
import { fetchWithShim, hyper } from './utils/hyper-request.ts'

import type {
HyperCache,
Expand Down Expand Up @@ -60,174 +60,183 @@ export function connect(CONNECTION_STRING: string, domain = 'default'): Hyper {
.then((r) => (response.ok ? r : assoc('status', response.status, r)))
.then((r) => (response.status >= 500 ? Promise.reject(r) : r))

/**
* This is a shim to support https://github.com/hyper63/hyper/issues/566
*/
const $fetch = fetchWithShim(fetch)

return {
data: {
add: (body) =>
Promise.resolve(h)
.then(data.add(body))
.then(fetch)
.then($fetch)
.then(handleResponse),
get: (id) => Promise.resolve(h).then(data.get(id)).then(fetch).then(handleResponse),
get: (id) => Promise.resolve(h).then(data.get(id)).then($fetch).then(handleResponse),
list: (options) =>
Promise.resolve(h)
.then(data.list(options))
.then(fetch)
.then($fetch)
.then(handleResponse),
update: (id, doc) =>
Promise.resolve(h)
.then(data.update(id, doc))
.then(fetch)
.then($fetch)
.then(handleResponse),
remove: (id) =>
Promise.resolve(h)
.then(data.remove(id))
.then(fetch)
.then($fetch)
.then(handleResponse),
query: (selector, options) =>
Promise.resolve(h)
.then(data.query(selector, options))
.then(fetch)
.then($fetch)
.then(handleResponse),
bulk: (docs) =>
Promise.resolve(h)
.then(data.bulk(docs))
.then(fetch)
.then($fetch)
.then(handleResponse),
index: (indexName, fields) =>
Promise.resolve(h)
.then(data.index(indexName, fields))
.then(fetch)
.then($fetch)
.then(handleResponse),
create: () =>
Promise.resolve(h)
.then(data.create())
.then($fetch)
.then(handleResponse),
create: () => Promise.resolve(h).then(data.create()).then(fetch).then(handleResponse),
destroy: (confirm) =>
Promise.resolve(h)
.then(data.destroy(confirm))
.then(fetch)
.then($fetch)
.then(handleResponse),
},
cache: {
add: (key, value, ttl) =>
Promise.resolve(h)
.then(cache.add(key, value, ttl))
.then(fetch)
.then($fetch)
.then(handleResponse),
get: (key) =>
Promise.resolve(h)
.then(cache.get(key))
.then(fetch)
.then($fetch)
.then(handleResponse),
remove: (key) =>
Promise.resolve(h)
.then(cache.remove(key))
.then(fetch)
.then($fetch)
.then(handleResponse),
set: (key, value, ttl) =>
Promise.resolve(h)
.then(cache.set(key, value, ttl))
.then(fetch)
.then($fetch)
.then(handleResponse),
query: (pattern) =>
Promise.resolve(h)
.then(cache.query(pattern))
.then(fetch)
.then($fetch)
.then(handleResponse),
create: () =>
Promise.resolve(h)
.then(cache.create())
.then(fetch)
.then($fetch)
.then(handleResponse),
destroy: (confirm) =>
Promise.resolve(h)
.then(cache.destroy(confirm))
.then(fetch)
.then($fetch)
.then(handleResponse),
},
search: {
add: (key, doc) =>
Promise.resolve(h)
.then(search.add(key, doc))
.then(fetch)
.then($fetch)
.then(handleResponse),
remove: (key) =>
Promise.resolve(h)
.then(search.remove(key))
.then(fetch)
.then($fetch)
.then(handleResponse),
get: (key) =>
Promise.resolve(h)
.then(search.get(key))
.then(fetch)
.then($fetch)
.then(handleResponse),
update: (key, doc) =>
Promise.resolve(h)
.then(search.update(key, doc))
.then(fetch)
.then($fetch)
.then(handleResponse),
query: (query, options) =>
Promise.resolve(h)
.then(search.query(query, options))
.then(fetch)
.then($fetch)
.then(handleResponse),
load: (docs) =>
Promise.resolve(h)
.then(search.load(docs))
.then(fetch)
.then($fetch)
.then(handleResponse),
create: (fields, storeFields) =>
Promise.resolve(h)
.then(search.create(fields, storeFields))
.then(fetch)
.then($fetch)
.then(handleResponse),
destroy: (confirm) =>
Promise.resolve(h)
.then(search.destroy(confirm))
.then(fetch)
.then($fetch)
.then(handleResponse),
},
storage: {
upload: (name, data) =>
Promise.resolve(h)
.then(storage.upload(name, data))
.then(fetch)
.then($fetch)
.then(handleResponse),
download: (name) =>
Promise.resolve(h)
.then(storage.download(name))
.then(fetch)
.then($fetch)
.then((res) => res.body as ReadableStream),
signedUrl: (name, options) =>
Promise.resolve(h)
.then(storage.signedUrl(name, options))
.then(fetch)
.then($fetch)
.then(handleResponse),
remove: (name) =>
Promise.resolve(h)
.then(storage.remove(name))
.then(fetch)
.then($fetch)
.then(handleResponse),
},
queue: {
enqueue: (job) =>
Promise.resolve(h)
.then(queue.enqueue(job))
.then(fetch)
.then($fetch)
.then(handleResponse),
errors: () =>
Promise.resolve(h)
.then(queue.errors())
.then(fetch)
.then($fetch)
.then(handleResponse),
queued: () =>
Promise.resolve(h)
.then(queue.queued())
.then(fetch)
.then($fetch)
.then(handleResponse),
},
info: {
services: () =>
Promise.resolve(h)
.then(info.services())
.then(fetch)
.then($fetch)
.then(handleResponse),
},
}
Expand Down
63 changes: 61 additions & 2 deletions packages/connect/deno/tests/hyper-request.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { assert, assertEquals } from '../dev_deps.ts'
import { assert, assertEquals, assertObjectMatch } from '../dev_deps.ts'

import { generateToken } from '../deps.deno.ts'
import { hyper, HYPER_LEGACY_GET_HEADER } from '../utils/hyper-request.ts'
import { fetchWithShim, hyper, HYPER_LEGACY_GET_HEADER } from '../utils/hyper-request.ts'
import { HyperRequest } from '../types.ts'

Deno.test('hyper-request', async (t) => {
Expand All @@ -18,6 +18,65 @@ Deno.test('hyper-request', async (t) => {
})
})

await t.step('fetchWithShim', async (t) => {
const $fetch = fetchWithShim(
// deno-lint-ignore require-await
async (url, init) => {
return new Response(init?.body, {
headers: {
...Object.fromEntries(init?.headers as Headers),
url: url as string,
method: init?.method as string,
},
})
},
)

await t.step(
'should make the fetch call with the parts of the providedRequest object',
async () => {
await $fetch(
new Request('https://foo.bar', {
headers: {
Authorization: 'Bearer foo',
'Content-Type': 'application/json',
},
method: 'PUT',
body: JSON.stringify({ foo: 'bar' }),
}),
)
.then((res) => {
const headers = res.headers
assertEquals(headers.get('content-type'), 'application/json')
assertEquals(headers.get('url'), 'https://foo.bar/')
assertEquals(headers.get('method'), 'PUT')
return res.json()
})
.then((body) => {
assertObjectMatch(body, { foo: 'bar' })
})
},
)

await t.step('should work with an empty body', async () => {
await $fetch(
new Request('https://foo.bar?fizz=buzz', {
headers: {
Authorization: 'Bearer foo',
'Content-Type': 'application/json',
},
method: 'PUT',
}),
).then((res) => {
const headers = res.headers
assertEquals(headers.get('content-type'), 'application/json')
assertEquals(headers.get('url'), 'https://foo.bar/?fizz=buzz')
assertEquals(headers.get('method'), 'PUT')
assertEquals(res.body, null)
})
})
})

await t.step('hyper', async (t) => {
const req: HyperRequest = {
service: 'data',
Expand Down
17 changes: 17 additions & 0 deletions packages/connect/deno/utils/hyper-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,23 @@ interface HyperRequestParams {

export const HYPER_LEGACY_GET_HEADER = 'X-HYPER-LEGACY-GET'

/**
* This is a shim to support https://github.com/hyper63/hyper/issues/566
*
* We take fetch, and a Request object and split the Request object into
* it url and RequestInit pieces to pass to Request
*/
export const fetchWithShim = (f: typeof fetch) =>
/**
* Technically we should be able to pass the Request
* as the RequestInit https://github.com/whatwg/fetch/issues/1486
*
* But I am honestly worried that wouldn't work when transpiled to Node,
* so just manually build out the RequestInit for now.
*/
(req: Request): Promise<Response> =>
f(req.url, { headers: req.headers, method: req.method, body: req.body })

export const hyper = (conn: URL, domain: string) =>
async ({
service,
Expand Down

0 comments on commit ffcfd89

Please sign in to comment.