@sentzunhat/zacatl 0.0.6 โ†’ 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,42 +1,128 @@
1
1
  # Zacatl Microservice Framework
2
2
 
3
- A blazing fast, modular TypeScript microservice framework for Node.js, designed for rapid development of high-performance APIs and distributed systems. Zacatl enforces a clean, layered architecture, robust typing, and seamless collaboration between human and AI contributors.
3
+ [![npm version](https://img.shields.io/npm/v/@sentzunhat/zacatl.svg)](https://www.npmjs.com/package/@sentzunhat/zacatl)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](https://www.typescriptlang.org/)
4
6
 
5
- ---
7
+ A modular, high-performance TypeScript microservice framework for Node.js, featuring layered architecture, dependency injection, and robust validation for building scalable APIs and distributed systems.
6
8
 
7
- ## 1. How Humans and AI Agents Can Contribute
9
+ ## Table of Contents
8
10
 
9
- - **Read the docs:** Always review `guidelines.yaml`, `context.yaml`, and `patterns.yaml` before making changes.
10
- - **Follow conventions:** Use dependency injection (`tsyringe`), maintain modularity, and respect the layered architecture.
11
- - **Testing:** All logic must be unit tested (`vitest`). Place tests in `test/unit/`, mirroring the `src/` structure.
12
- - **Documentation:** Update YAML docs with new patterns, features, or conventions. AI agents should parse YAML for context.
13
- - **Register everything:** All services, repositories, and handlers must be registered in the DI container.
11
+ - [Overview](#overview)
12
+ - [Key Features](#key-features)
13
+ - [Installation](#installation)
14
+ - [Quick Start](#quick-start)
15
+ - [Project Structure](#project-structure)
16
+ - [Core Concepts](#core-concepts)
17
+ - [Configuration](#configuration)
18
+ - [Testing](#testing)
19
+ - [Contributing](#contributing)
20
+ - [Documentation](#documentation)
21
+ - [License](#license)
14
22
 
15
- ---
23
+ ## Overview
24
+
25
+ Zacatl is a TypeScript-first microservice framework that enforces clean, layered (hexagonal) architecture with strict separation of concerns. It's designed for rapid development of robust APIs and distributed systems, with built-in support for dependency injection, validation, and seamless collaboration between human and AI contributors.
26
+
27
+ ## Key Features
28
+
29
+ - **๐Ÿ—๏ธ Layered Architecture**: Clean separation with Application, Domain, Infrastructure, and Platform layers
30
+ - **๐Ÿ’‰ Dependency Injection**: Built-in DI container using `tsyringe` for better modularity
31
+ - **โšก High Performance**: Built on Fastify for maximum speed and efficiency
32
+ - **๐Ÿ” Type Safety**: Full TypeScript support with strict typing and generics
33
+ - **โœ… Validation**: Request/response validation using Zod schemas
34
+ - **๐Ÿงช Testing**: Comprehensive testing with Vitest and clear test structure
35
+ - **๐Ÿ“Š MongoDB Support**: Built-in repository pattern with Mongoose integration
36
+ - **๐ŸŒ Internationalization**: Multi-language support with i18n
37
+ - **๐Ÿš€ Production Ready**: Error handling, logging, and monitoring built-in
38
+
39
+ ## Installation
40
+
41
+ Install Zacatl using npm:
42
+
43
+ ```bash
44
+ npm install @sentzunhat/zacatl
45
+ ```
46
+
47
+ Or with yarn:
48
+
49
+ ```bash
50
+ yarn add @sentzunhat/zacatl
51
+ ```
52
+
53
+ ## Quick Start
54
+
55
+ Here's a minimal example to get you started:
56
+
57
+ ```typescript
58
+ import Fastify from "fastify";
59
+ import { MicroService } from "@sentzunhat/zacatl";
60
+
61
+ const fastifyApp = Fastify();
62
+
63
+ const microservice = new MicroService({
64
+ architecture: {
65
+ application: {
66
+ entryPoints: {
67
+ rest: {
68
+ hookHandlers: [], // Add hook handler classes
69
+ routeHandlers: [], // Add route handler classes
70
+ },
71
+ },
72
+ },
73
+ domain: { providers: [] }, // Add domain provider classes
74
+ infrastructure: { repositories: [] }, // Add repository classes
75
+ service: {
76
+ name: "my-service",
77
+ server: {
78
+ type: "SERVER",
79
+ vendor: "FASTIFY",
80
+ instance: fastifyApp,
81
+ },
82
+ databases: [
83
+ // Example for MongoDB:
84
+ // {
85
+ // vendor: "MONGOOSE",
86
+ // instance: new Mongoose(),
87
+ // connectionString: "mongodb://localhost/mydb",
88
+ // }
89
+ ],
90
+ },
91
+ },
92
+ });
16
93
 
17
- ## 2. Project Structure & Layer Overview
94
+ await microservice.start({ port: 9000 });
95
+ ```
96
+
97
+ For a complete example with route handlers, see our [examples](./examples) directory.
98
+
99
+ ## Project Structure
18
100
 
19
101
  ```
20
102
  src/
21
- configuration.ts # App configuration (env, settings)
22
- logs.ts # Logging utilities
23
- optionals.ts # Optional helpers/utilities
24
- error/ # Custom error classes (BadRequest, NotFound, etc.)
25
- locales/ # Localization files (en.json, fr.json, ...)
26
- micro-service/
27
- architecture/
28
- application/ # Entry points, route/hook handlers, validation
29
- domain/ # Business logic, models, providers, services
30
- infrastructure/ # DB repositories, adapters
31
- platform/ # Service orchestration, DI setup
32
- index.ts # Microservice layer entry
33
- utils/ # Utility functions (base64, hmac, etc.)
103
+ โ”œโ”€โ”€ configuration.ts # App configuration and environment settings
104
+ โ”œโ”€โ”€ logs.ts # Structured logging with Pino
105
+ โ”œโ”€โ”€ optionals.ts # Optional utility types and helpers
106
+ โ”œโ”€โ”€ error/ # Custom error classes (BadRequest, NotFound, etc.)
107
+ โ”œโ”€โ”€ locales/ # Internationalization files (en.json, fr.json)
108
+ โ”œโ”€โ”€ micro-service/
109
+ โ”‚ โ””โ”€โ”€ architecture/
110
+ โ”‚ โ”œโ”€โ”€ application/ # HTTP entry points, validation, route handlers
111
+ โ”‚ โ”œโ”€โ”€ domain/ # Business logic, models, services (pure)
112
+ โ”‚ โ”œโ”€โ”€ infrastructure/ # Database repositories, external adapters
113
+ โ”‚ โ””โ”€โ”€ platform/ # Service orchestration, DI setup, startup
114
+ โ””โ”€โ”€ utils/ # Utility functions (base64, hmac, etc.)
115
+
116
+ test/
117
+ โ””โ”€โ”€ unit/ # Unit tests mirroring src/ structure
34
118
  ```
35
119
 
36
- - **Application:** Handles HTTP entry points, validation, and delegates to domain logic.
37
- - **Domain:** Pure business logic, models, and providers. No infrastructure dependencies.
38
- - **Infrastructure:** Persistence (MongoDB repositories), adapters, and external integrations.
39
- - **Platform:** Bootstraps the app, configures DI, and starts the server.
120
+ ### Layer Responsibilities
121
+
122
+ - **Application Layer**: Handles HTTP requests, validation, and delegates to domain logic
123
+ - **Domain Layer**: Contains pure business logic, models, and services (no infrastructure dependencies)
124
+ - **Infrastructure Layer**: Manages persistence (MongoDB repositories) and external integrations
125
+ - **Platform Layer**: Bootstraps the application, configures DI container, and starts the server
40
126
 
41
127
  ---
42
128
 
package/package.json CHANGED
@@ -2,12 +2,43 @@
2
2
  "name": "@sentzunhat/zacatl",
3
3
  "main": "src/index.ts",
4
4
  "module": "src/index.ts",
5
- "version": "0.0.6",
5
+ "version": "0.0.8",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/sentzunhat/zacatl.git"
9
9
  },
10
- "description": "",
10
+ "description": "A modular, high-performance TypeScript microservice framework for Node.js, featuring layered architecture, dependency injection, and robust validation for building scalable APIs and distributed systems.",
11
+ "keywords": [
12
+ "typescript",
13
+ "microservice",
14
+ "microservices",
15
+ "framework",
16
+ "nodejs",
17
+ "dependency-injection",
18
+ "hexagonal-architecture",
19
+ "layered-architecture",
20
+ "clean-architecture",
21
+ "fastify",
22
+ "mongodb",
23
+ "mongoose",
24
+ "zod",
25
+ "validation",
26
+ "vitest",
27
+ "testing",
28
+ "api",
29
+ "rest-api",
30
+ "backend",
31
+ "server",
32
+ "enterprise",
33
+ "scalable",
34
+ "modular",
35
+ "tsyringe",
36
+ "pino",
37
+ "logging",
38
+ "i18n",
39
+ "internationalization",
40
+ "artisan"
41
+ ],
11
42
  "author": "Diego Beltran <beltrd@gmail.com> (https://sentzunhat.com)",
12
43
  "contributors": [
13
44
  {
@@ -14,7 +14,9 @@ export type HttpStatusCode =
14
14
  | 502 // Bad Gateway
15
15
  | 503; // Service Unavailable;
16
16
 
17
- export type ErrorCode = Optional<HttpStatusCode | string>;
17
+ export type StatusCodeString = "invalid";
18
+
19
+ export type ErrorCode = Optional<HttpStatusCode | StatusCodeString>;
18
20
 
19
21
  export interface CustomErrorsArgs {
20
22
  message: string;
@@ -1,11 +1,10 @@
1
- import { z } from "zod";
2
1
  import { FastifyReply } from "fastify";
3
2
 
4
3
  import { Request } from "./request";
5
4
 
6
5
  export type Handler<
7
6
  TBody,
8
- TQuerystring = z.ZodSchema<Record<string, string>>,
7
+ TQuerystring = Record<string, string>,
9
8
  TParams = void
10
9
  > = (
11
10
  request: Request<TBody, TQuerystring, TParams>,
@@ -1,17 +1,16 @@
1
- import { z } from "zod";
2
1
  import { IncomingMessage } from "http";
3
2
  import { FastifySchema, FastifyRequest, RawServerBase } from "fastify";
4
3
 
5
4
  export type Request<
6
5
  TBody,
7
- TQuerystring = z.ZodSchema<Record<string, string>>,
6
+ TQuerystring = Record<string, string>,
8
7
  TParams = void
9
8
  > = FastifyRequest<
10
9
  {
11
10
  Body: TBody;
12
11
  Querystring: TQuerystring;
13
12
  Params: TParams;
14
- Headers: z.ZodSchema<Record<string, string>>;
13
+ Headers: Record<string, string>;
15
14
  },
16
15
  RawServerBase,
17
16
  IncomingMessage,
@@ -5,6 +5,20 @@ import { HTTPMethods, FastifySchema, FastifyReply } from "fastify";
5
5
  import { RouteHandler } from "./route-handler";
6
6
  import { Request } from "../common/request";
7
7
 
8
+ export type RouteSchema<
9
+ TBody = void,
10
+ TQuerystring = Record<string, string>,
11
+ TParams = Record<string, string>,
12
+ THeaders = Record<string, string>,
13
+ TResponse = void
14
+ > = {
15
+ body?: z.ZodSchema<TBody>;
16
+ querystring?: z.ZodSchema<TQuerystring>;
17
+ params?: z.ZodSchema<TParams>;
18
+ headers?: z.ZodSchema<THeaders>;
19
+ response?: z.ZodSchema<TResponse>;
20
+ };
21
+
8
22
  export type AbstractRouteHandlerConstructor = {
9
23
  url: string;
10
24
  method: HTTPMethods;
@@ -15,9 +29,9 @@ export type HandlerOutput<TResponse> = TResponse;
15
29
 
16
30
  export abstract class AbstractRouteHandler<
17
31
  TBody = void,
18
- TQuerystring = z.ZodSchema<Record<string, string>>,
32
+ TQuerystring = Record<string, string>,
19
33
  TResponse = void,
20
- TParams = void
34
+ TParams = Record<string, string>
21
35
  > implements RouteHandler<TBody, TQuerystring, TParams>
22
36
  {
23
37
  public url: string;
@@ -1,6 +1,4 @@
1
- import { z } from "zod";
2
1
  import { FastifySchema } from "fastify";
3
-
4
2
  import { AbstractRouteHandler } from "./abstract";
5
3
 
6
4
  export type GetRouteHandlerConstructor = {
@@ -9,9 +7,9 @@ export type GetRouteHandlerConstructor = {
9
7
  };
10
8
 
11
9
  export abstract class GetRouteHandler<
12
- TBody = never,
13
- TResponse = never,
14
- TQuerystring = z.ZodSchema<Record<string, string>>,
10
+ TBody = void,
11
+ TQuerystring = Record<string, string>,
12
+ TResponse = void,
15
13
  TParams = void
16
14
  > extends AbstractRouteHandler<TBody, TQuerystring, TResponse, TParams> {
17
15
  constructor(args: GetRouteHandlerConstructor) {
@@ -1,6 +1,4 @@
1
- import { z } from "zod";
2
1
  import { FastifySchema } from "fastify";
3
-
4
2
  import { AbstractRouteHandler } from "./abstract";
5
3
 
6
4
  export type PostRouteHandlerConstructor = {
@@ -9,10 +7,10 @@ export type PostRouteHandlerConstructor = {
9
7
  };
10
8
 
11
9
  export abstract class PostRouteHandler<
12
- TBody = never,
13
- TResponse = never,
14
- TQuerystring = z.ZodSchema<Record<string, string>>,
15
- TParams = void
10
+ TBody = unknown,
11
+ TResponse = unknown,
12
+ TQuerystring = Record<string, string>,
13
+ TParams = Record<string, string>
16
14
  > extends AbstractRouteHandler<TBody, TQuerystring, TResponse, TParams> {
17
15
  constructor(args: PostRouteHandlerConstructor) {
18
16
  super({
@@ -1,11 +1,10 @@
1
- import { z } from "zod";
2
1
  import { FastifySchema, HTTPMethods } from "fastify";
3
2
 
4
3
  import { Handler } from "../common/handler";
5
4
 
6
5
  export type RouteHandler<
7
6
  TBody = void,
8
- TQuerystring = z.ZodSchema<Record<string, string>>,
7
+ TQuerystring = Record<string, string>,
9
8
  TParams = void
10
9
  > = {
11
10
  url: string;
@@ -7,6 +7,7 @@ import importedMongoose, {
7
7
  Schema,
8
8
  Default__v,
9
9
  Require_id,
10
+ ObjectId,
10
11
  } from "mongoose";
11
12
  import { v4 as uuidv4 } from "uuid";
12
13
  import { container } from "tsyringe";
@@ -18,6 +19,14 @@ export type BaseRepositoryConfig<D> = {
18
19
 
19
20
  export type WithMongooseMeta<T> = Default__v<Require_id<T>>;
20
21
 
22
+ export type MongooseDocument<Db> = Document<
23
+ ObjectId,
24
+ {},
25
+ Db,
26
+ Record<string, string>
27
+ > &
28
+ WithMongooseMeta<Db>;
29
+
21
30
  export type LeanWithMeta<T> = WithMongooseMeta<T> & {
22
31
  id: string;
23
32
  createdAt: Date;
@@ -31,9 +40,9 @@ export type LeanDocument<T> = T & {
31
40
  };
32
41
 
33
42
  export type MongooseDoc<Db> = IfAny<
34
- Db,
35
- unknown,
36
- Document<unknown, {}, Db, {}> & WithMongooseMeta<Db>
43
+ MongooseDocument<Db>,
44
+ MongooseDocument<Db>,
45
+ MongooseDocument<Db>
37
46
  >;
38
47
 
39
48
  export type ToLeanInput<D, T> =
@@ -47,6 +56,7 @@ export type ToLeanInput<D, T> =
47
56
  export type Repository<D, T> = {
48
57
  model: Model<D>;
49
58
 
59
+ toLean(input: ToLeanInput<D, T>): LeanDocument<T> | null;
50
60
  findById(id: string): Promise<LeanDocument<T> | null>;
51
61
  create(entity: D): Promise<LeanDocument<T>>;
52
62
  update(id: string, update: Partial<D>): Promise<LeanDocument<T> | null>;
@@ -62,12 +72,15 @@ export abstract class BaseRepository<D, T> implements Repository<D, T> {
62
72
  const mongoose = connection.db?.databaseName
63
73
  ? importedMongoose
64
74
  : container.resolve<Mongoose>(Mongoose);
75
+
65
76
  const { name, schema } = this.config;
77
+
66
78
  if (name) {
67
79
  this.model = mongoose.model<D>(name, schema);
68
80
  } else {
69
81
  this.model = mongoose.model<D>(uuidv4(), schema);
70
82
  }
83
+
71
84
  this.model.createCollection();
72
85
  this.model.createIndexes();
73
86
  this.model.init();
@@ -77,20 +90,17 @@ export abstract class BaseRepository<D, T> implements Repository<D, T> {
77
90
  * Ensures the returned document has the correct id, createdAt, and updatedAt fields.
78
91
  * Accepts a Mongoose document, a plain object, or a result from .lean().
79
92
  */
80
- private toLean(input: ToLeanInput<D, T>): LeanDocument<T> | null {
93
+ public toLean(input: ToLeanInput<D, T>): LeanDocument<T> | null {
81
94
  if (!input) {
82
95
  return null;
83
96
  }
84
97
 
85
98
  let base: LeanWithMeta<T>;
86
99
 
87
- if (
88
- Object.prototype.hasOwnProperty.call(input, "toObject") &&
89
- typeof (input as unknown as { toObject: unknown }).toObject === "function"
90
- ) {
91
- base = (
92
- input as Document<unknown, {}, D, {}> & WithMongooseMeta<D>
93
- ).toObject<LeanDocument<T>>({ virtuals: true });
100
+ if (typeof (input as MongooseDoc<D>).toObject === "function") {
101
+ base = (input as MongooseDoc<D>).toObject<LeanDocument<T>>({
102
+ virtuals: true,
103
+ });
94
104
  } else {
95
105
  base = input as LeanWithMeta<T>;
96
106
  }
@@ -132,11 +142,15 @@ export abstract class BaseRepository<D, T> implements Repository<D, T> {
132
142
  }
133
143
 
134
144
  async create(entity: D): Promise<LeanDocument<T>> {
135
- const doc = await this.model.create(entity);
145
+ const document = await this.model.create<D>(entity);
136
146
 
137
- doc.toObject();
147
+ const leanDocument = this.toLean(document as MongooseDoc<D>);
148
+
149
+ if (!leanDocument) {
150
+ throw new Error("failed to create document");
151
+ }
138
152
 
139
- return this.toLean(doc)!;
153
+ return leanDocument;
140
154
  }
141
155
 
142
156
  async update(
@@ -206,6 +206,10 @@ export class Service implements ServicePort {
206
206
  }
207
207
 
208
208
  public async configureDatabases(): Promise<void> {
209
+ if (!this.databases || this.databases.length === 0) {
210
+ return; // No databases to configure
211
+ }
212
+
209
213
  for (const database of this.databases) {
210
214
  const strategy = strategiesForDatabaseVendor[database.vendor];
211
215
 
@@ -16,7 +16,14 @@ class DummyHookHandler implements HookHandler {
16
16
  async execute(_: FastifyRequest): Promise<void> {}
17
17
  }
18
18
 
19
- class DummyRouteHandler extends AbstractRouteHandler {
19
+ import { FastifyReply } from "fastify";
20
+
21
+ class DummyRouteHandler extends AbstractRouteHandler<
22
+ void, // Body
23
+ Record<string, string>, // Querystring
24
+ void, // Params
25
+ void // Response
26
+ > {
20
27
  constructor() {
21
28
  super({
22
29
  url: "/",
@@ -25,7 +32,17 @@ class DummyRouteHandler extends AbstractRouteHandler {
25
32
  });
26
33
  }
27
34
 
28
- handler(_: Request<void, {}>): void | Promise<void> {}
35
+ handler(
36
+ _: Request<
37
+ void, // Body
38
+ Record<string, string>, // Querystring
39
+ void // Params
40
+ >,
41
+ __: FastifyReply
42
+ ): void | Promise<void> {
43
+ // Dummy implementation
44
+ return;
45
+ }
29
46
  }
30
47
 
31
48
  const fakeConfig: ConfigApplication = {
@@ -10,9 +10,29 @@ import {
10
10
  Request,
11
11
  } from "../../../../../../../../src/micro-service/architecture/application";
12
12
 
13
- class TestRouteHandler extends AbstractRouteHandler<unknown, string, unknown> {
14
- async handler(_: unknown, __: unknown): Promise<string> {
15
- return "Test Data";
13
+ class TestRouteHandler extends AbstractRouteHandler<
14
+ void, // Body
15
+ Record<string, string>, // Querystring
16
+ void, // Params
17
+ void // Response
18
+ > {
19
+ constructor() {
20
+ super({
21
+ url: "/",
22
+ schema: {},
23
+ method: "GET",
24
+ });
25
+ }
26
+
27
+ handler(
28
+ _: Request<
29
+ void, // Body
30
+ Record<string, string>, // Querystring
31
+ void // Params
32
+ >
33
+ ): void | Promise<void> {
34
+ // Dummy implementation
35
+ return;
16
36
  }
17
37
  }
18
38
 
@@ -20,15 +40,15 @@ describe("AbstractRouteHandler", () => {
20
40
  it("executes the handler and sends the proper response", async () => {
21
41
  vi.spyOn(i18n, "__").mockReturnValue("Default success");
22
42
 
23
- const fakeRequest = createFakeFastifyRequest() as Request<unknown, string>;
43
+ const fakeRequest = createFakeFastifyRequest() as Request<
44
+ void, // Body
45
+ Record<string, string>, // Querystring
46
+ void // Params
47
+ >;
24
48
 
25
49
  const fakeReply: any = createFakeFastifyReply();
26
50
 
27
- const testHandler = new TestRouteHandler({
28
- url: "/test",
29
- method: "GET",
30
- schema: {},
31
- });
51
+ const testHandler = new TestRouteHandler();
32
52
 
33
53
  await testHandler.execute(fakeRequest, fakeReply);
34
54
 
@@ -36,7 +56,7 @@ describe("AbstractRouteHandler", () => {
36
56
  expect(fakeReply.send).toHaveBeenCalledWith({
37
57
  ok: true,
38
58
  message: "Default success",
39
- data: "Test Data",
59
+ data: undefined,
40
60
  });
41
61
  });
42
62
  });
@@ -10,9 +10,17 @@ import {
10
10
  createFakeFastifyRequest,
11
11
  } from "../../../../../../helpers/common/common";
12
12
 
13
- class TestPostRouteHandler extends PostRouteHandler<unknown, string, unknown> {
14
- async handler(_: unknown, __: unknown): Promise<string> {
15
- return "Test POST response";
13
+ class TestPostRouteHandler extends PostRouteHandler<{}, {}, {}, {}> {
14
+ constructor() {
15
+ super({
16
+ url: "/post-test",
17
+ schema: {}, // Use an empty schema for test purposes.
18
+ });
19
+ }
20
+
21
+ handler(_: Request<{}, {}, {}>): {} | Promise<{}> {
22
+ // Dummy implementation
23
+ return {};
16
24
  }
17
25
  }
18
26
 
@@ -20,12 +28,9 @@ describe("PostRouteHandler", () => {
20
28
  it("executes POST handler and sends proper response", async () => {
21
29
  vi.spyOn(i18n, "__").mockReturnValue("Default success POST");
22
30
 
23
- const testHandler = new TestPostRouteHandler({
24
- url: "/post-test",
25
- schema: {}, // Use an empty schema for test purposes.
26
- });
31
+ const testHandler = new TestPostRouteHandler();
27
32
 
28
- const fakeRequest = createFakeFastifyRequest() as Request<unknown, string>;
33
+ const fakeRequest = createFakeFastifyRequest() as Request<{}, {}, {}>;
29
34
  const fakeReply = createFakeFastifyReply();
30
35
 
31
36
  await testHandler.execute(fakeRequest, fakeReply);
@@ -34,7 +39,7 @@ describe("PostRouteHandler", () => {
34
39
  expect(fakeReply.send).toHaveBeenCalledWith({
35
40
  ok: true,
36
41
  message: "Default success POST",
37
- data: "Test POST response",
42
+ data: {},
38
43
  });
39
44
  });
40
45
  });
@@ -146,6 +146,8 @@ describe("Service", () => {
146
146
  const port = 3000;
147
147
  const service = new Service(config);
148
148
 
149
+ await service.configureDatabases();
150
+
149
151
  await service.start({ port });
150
152
 
151
153
  expect(
@@ -184,15 +186,13 @@ describe("Service", () => {
184
186
  });
185
187
 
186
188
  it("should throw an error if database configuration fails", async () => {
187
- const port = 3000;
188
-
189
189
  strategiesForDatabaseVendor[DatabaseVendor.MONGOOSE] = originalDbStrategy;
190
190
 
191
191
  fakeMongoose.connect.mockRejectedValue(new Error("db connect failed"));
192
192
 
193
193
  const service = new Service(config);
194
194
 
195
- await expect(service.start({ port })).rejects.toThrow(
195
+ await expect(service.configureDatabases()).rejects.toThrow(
196
196
  "failed to configure database for service"
197
197
  );
198
198
  });