diff --git a/src/http-api.ts b/src/http-api.ts index dbe1038..8ea0d19 100644 --- a/src/http-api.ts +++ b/src/http-api.ts @@ -1,6 +1,8 @@ import { type Dwn, RecordsRead, + type RecordsQueryReply, + RecordsQuery, type RecordsReadReply, } from '@tbd54566975/dwn-sdk-js'; @@ -78,34 +80,6 @@ export class HttpApi { } }); - this.#api.get('/:did/records/:id', async (req, res) => { - const record = await RecordsRead.create({ - filter: { recordId: req.params.id }, - }); - const reply = (await this.dwn.processMessage( - req.params.did, - record.toJSON(), - )) as RecordsReadReply; - - if (reply.status.code === 200) { - if (reply?.record?.data) { - const stream = reply.record.data; - delete reply.record.data; - - res.setHeader('content-type', reply.record.descriptor.dataFormat); - res.setHeader('dwn-response', JSON.stringify(reply)); - - return stream.pipe(res); - } else { - return res.sendStatus(400); - } - } else if (reply.status.code === 401) { - return res.sendStatus(404); - } else { - return res.status(reply.status.code).send(reply); - } - }); - this.#api.get('/', (_req, res) => { // return a plain text string res.setHeader('content-type', 'text/plain'); @@ -179,6 +153,49 @@ export class HttpApi { return res.json(jsonRpcResponse); } }); + + this.#api.get('/dwn/:did/records/:id', async (req, res) => { + const record = await RecordsRead.create({ + filter: { recordId: req.params.id }, + }); + const reply = (await this.dwn.processMessage( + req.params.did, + record.toJSON(), + )) as RecordsReadReply; + + if (reply.status.code === 200) { + if (reply?.record?.data) { + const stream = reply.record.data; + delete reply.record.data; + + res.setHeader('content-type', reply.record.descriptor.dataFormat); + res.setHeader('dwn-response', JSON.stringify(reply)); + + return stream.pipe(res); + } else { + return res.sendStatus(400); + } + } else if (reply.status.code === 401) { + return res.sendStatus(404); + } else { + return res.status(reply.status.code).send(reply); + } + }); + + this.#api.get('/dwn/:did/records', async (req: Request, res: Response) => { + const record = await RecordsQuery.create({ + filter: { + protocol: req.query.protocol as string, + protocolPath: req.query.protocolPath as string, + }, + }); + const dwnReply = (await this.dwn.processMessage( + req.params.did, + record.toJSON(), + )) as RecordsQueryReply; + + res.json(dwnReply.entries); + }); } #listen(port: number, callback?: () => void): void { diff --git a/tests/http-api.spec.ts b/tests/http-api.spec.ts index 7188586..b938139 100644 --- a/tests/http-api.spec.ts +++ b/tests/http-api.spec.ts @@ -500,4 +500,103 @@ describe('http api', function () { expect(response.status).to.equal(404); }); }); + + describe('/:did/records', function () { + it('returns a list of records that match a given query', async function () { + const filePath = './fixtures/test.jpeg'; + const { + cid: expectedCid, + size, + stream, + } = await getFileAsReadStream(filePath); + const alice = await createProfile(); + const { recordsWrite } = await createRecordsWriteMessage(alice, { + dataCid: expectedCid, + dataSize: size, + published: true, + }); + const requestId = uuidv4(); + const dwnRequest = createJsonRpcRequest(requestId, 'dwn.processMessage', { + message: recordsWrite.toJSON(), + target: alice.did, + }); + let response = await fetch('http://localhost:3000', { + method: 'POST', + headers: { + 'dwn-request': JSON.stringify(dwnRequest), + }, + body: stream, + }); + expect(response.status).to.equal(200); + const body = (await response.json()) as JsonRpcResponse; + expect(body.id).to.equal(requestId); + expect(body.error).to.not.exist; + const { reply } = body.result; + expect(reply.status.code).to.equal(202); + response = await fetch( + `http://localhost:3000/dwn/${alice.did}/records?protocolPath=photo`, + ); + console.log(await response.json()); + const blob = await response.blob(); + expect(blob.size).to.equal(size); + }); + // it('returns a 404 if an unpublished record is requested', async function () { + // const filePath = './fixtures/test.jpeg'; + // const { + // cid: expectedCid, + // size, + // stream, + // } = await getFileAsReadStream(filePath); + // const alice = await createProfile(); + // const { recordsWrite } = await createRecordsWriteMessage(alice, { + // dataCid: expectedCid, + // dataSize: size, + // }); + // const requestId = uuidv4(); + // const dwnRequest = createJsonRpcRequest(requestId, 'dwn.processMessage', { + // message: recordsWrite.toJSON(), + // target: alice.did, + // }); + // let response = await fetch('http://localhost:3000', { + // method: 'POST', + // headers: { + // 'dwn-request': JSON.stringify(dwnRequest), + // }, + // body: stream, + // }); + // expect(response.status).to.equal(200); + // const body = (await response.json()) as JsonRpcResponse; + // expect(body.id).to.equal(requestId); + // expect(body.error).to.not.exist; + // const { reply } = body.result; + // expect(reply.status.code).to.equal(202); + // response = await fetch( + // `http://localhost:3000/${alice.did}/records/${recordsWrite.message.recordId}`, + // ); + // expect(response.status).to.equal(404); + // }); + // it('returns a 404 if record doesnt exist', async function () { + // const alice = await createProfile(); + // const { recordsWrite } = await createRecordsWriteMessage(alice); + // const response = await fetch( + // `http://localhost:3000/${alice.did}/records/${recordsWrite.message.recordId}`, + // ); + // expect(response.status).to.equal(404); + // }); + // it('returns a 404 for invalid did', async function () { + // const alice = await createProfile(); + // const { recordsWrite } = await createRecordsWriteMessage(alice); + // const response = await fetch( + // `http://localhost:3000/1234567892345678/records/${recordsWrite.message.recordId}`, + // ); + // expect(response.status).to.equal(404); + // }); + // it('returns a 404 for invalid record id', async function () { + // const alice = await createProfile(); + // const response = await fetch( + // `http://localhost:3000/${alice.did}/records/kaka`, + // ); + // expect(response.status).to.equal(404); + // }); + }); });