Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,14 @@ for await (const eventType of client.readEventTypes()) {
controller.abort();
```

### Listing a Specific Event Type

To list a specific event type, call the `readEventType` function with the event type as an argument. The function returns the detailed event type, which includes the schema:

```typescript
eventType = await client.readEventType("io.eventsourcingdb.library.book-acquired")
```

### Using Testcontainers

Import the `Container` class, create an instance, call the `start` function to run a test container, get a client, run your test code, and finally call the `stop` function to stop the test container:
Expand Down
31 changes: 31 additions & 0 deletions src/Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,37 @@ class Client {
})();
}

public async readEventType(eventType: string): Promise<EventType> {
const url = this.#getUrl('/api/v1/read-event-type');
const response = await fetch(url, {
method: 'post',
headers: {
authorization: `Bearer ${this.#apiToken}`,
'content-type': 'application/json',
},
body: JSON.stringify({
eventType,
}),
});

if (response.status !== 200) {
throw new Error(
`Failed to read event type, got HTTP status code '${response.status}', expected '200'.`,
);
}
const responseBody = await response.json();
if (
!hasShapeOf(responseBody, {
eventType: 'string',
isPhantom: true,
})
) {
throw new Error('Failed to parse response.');
}

return responseBody;
}

public readEventTypes(signal?: AbortSignal): AsyncGenerator<EventType, void, void> {
const url = this.#getUrl('/api/v1/read-event-types');
const apiToken = this.#apiToken;
Expand Down
76 changes: 76 additions & 0 deletions src/readEventType.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import assert from 'node:assert/strict';
import { afterEach, beforeEach, suite, test } from 'node:test';
import { Container } from './Container.js';
import type { EventCandidate } from './EventCandidate.js';
import { getImageVersionFromDockerfile } from './getImageVersionFromDockerfile.js';

suite('readEventType', { timeout: 20_000 }, () => {
let container: Container;

beforeEach(async () => {
const imageVersion = getImageVersionFromDockerfile();
container = new Container().withImageTag(imageVersion);
await container.start();
});

afterEach(async () => {
await container.stop();
});

test('fails if the event type does not exist.', async (): Promise<void> => {
const client = container.getClient();

await assert.rejects(
async () => {
await client.readEventType('non.existent.eventType');
},
{
name: 'Error',
message: "Failed to read event type, got HTTP status code '404', expected '200'.",
},
);
});

test('fails if the evenet type is malformed.', async (): Promise<void> => {
const client = container.getClient();

await assert.rejects(
async () => {
await client.readEventType('malformed.eventType.');
},
{
name: 'Error',
message: "Failed to read event type, got HTTP status code '400', expected '200'.",
},
);
});

test('read an existing event type.', async (): Promise<void> => {
const client = container.getClient();

const firstEvent: EventCandidate = {
source: 'https://www.eventsourcingdb.io',
subject: '/test',
type: 'io.eventsourcingdb.test.foo',
data: {
value: 23,
},
};

const secondEvent: EventCandidate = {
source: 'https://www.eventsourcingdb.io',
subject: '/test',
type: 'io.eventsourcingdb.test.bar',
data: {
value: 42,
},
};

await client.writeEvents([firstEvent, secondEvent]);

const readEventType = await client.readEventType('io.eventsourcingdb.test.foo');
assert.equal(readEventType.eventType, 'io.eventsourcingdb.test.foo');
assert.equal(readEventType.isPhantom, false);
assert.equal(readEventType.schema, undefined);
});
});