I found a clever solution to this. In the DI container, we usually register our dependencies during app initialization. However, it is fine to register a dependency in context. Here's a snippet of how I did it.
export function mountPrismaDatabase(app: OpenAPIHono<OpenAPIHonoConfig>) {
app.use(async (c, next) => {
// order is important here.
// we initialize our prisma client connection first
// and bind it to the context
const adapter = new PrismaD1(c.env.DB);
const client = new PrismaClient({ adapter });
c.set('prisma', client);
await next();
});
app.use(async (c, next) => {
// we then register that context to our di container
registerContextModule(applicationContainer, c);
await next();
});
}
I can then consume this dependency in my infrastructure.
type OAHonoContext = Context<OpenAPIHonoConfig>;
export class AuthenticationService implements IAuthenticationService {
constructor(private _context: OAHonoContext) {}
// ...code...
createToken(session: Session): string {
return jwt.sign(session.getData(), this._context.env.JWT_SECRET);
}
// ...code...
}
If you need more details, you may check this basic todo repo that I am currently using to practice clean architecture in my profile. I am linking the exact commit hash so that this link won't be broken when I move files around.