Setting up a Database Module in Nest.js
I've been looking at nestjs as a framework to use and started running through their documentation. One of the things that I was a bit confused by was the database documentation. I ran into an issue that I couldn't figure out until now and I'm going to run through how it was fixed.
Let's start with some context on what I was trying to do. I wanted to create a DatabaseModule
that would hold the connections to all of my databases and would search through specific paths for entities. I then wanted to use that module where necessary to connect to the database. My first test was with the UserService
. So I had created a database-connections.ts
file which had the connection to the main database set up,
At the moment it's just one entry but this could be as many entries as you want. In the entites
array, I specify the path to the entities that would be applicable to the database.
Cool so the connection is set up! The next step is to create the DatabaseModule
that I can use in other places,
Basically, all I'm doing here is importing the database connections and exporting them. THIS IS WRONG!! You need to keep reading on if you did the same because it's what caused the error that I couldn't explain. We're not looking to export each TypeOrmModule
like I've done above. I'm going to keep going to show what happens if you do this.
Okay sweet so we have the database module (it doesn't work but we don't know that yet). The next step is to create a SharedModule
that has a couple of services and other things that we want all modules to use. In this case, the UserService
is what I'd like to create and share with all of my modules. So let's first make the user.service.ts
file,
And the user.entity.ts
file looks like this,
Okay great, we've set up the entity and service, let's create the shared.module.ts
,
So you can see here that I'm sharing the DatabaseModule
and I'm also providing the UserService
here. This is where it gets interesting. If you build and run this you'll get the following error,
[Nest] 647 - 2018-8-18 17:21:48 [ExceptionHandler] Nest can't resolve dependencies of the UserService (?). Please make sure that the argument at index [0] is available in the current context.
Error: Nest can't resolve dependencies of the UserService (?). Please make sure that the argument at index [0] is available in the current context.
at Injector.lookupComponentInExports (/app/node_modules/@nestjs/core/injector/injector.js:129:19)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:118:7)
at Function.Module.runMain (module.js:692:11)
at Object.<anonymous> (/app/node_modules/ts-node/src/_bin.ts:177:12)
at Module._compile (module.js:649:30)
at Object.Module._extensions..js (module.js:660:10)
at Module.load (module.js:561:32)
at tryModuleLoad (module.js:501:12)
at Function.Module._load (module.js:493:3)
1: node::Abort() [/usr/local/bin/node]
2: 0x8cea99 [/usr/local/bin/node]
3: v8::internal::FunctionCallbackArguments::Call(void (*)(v8::FunctionCallbackInfo<v8::Value> const&)) [/usr/local/bin/node]
4: 0xb1444c [/usr/local/bin/node]
5: v8::internal::Builtin_HandleApiCall(int, v8::internal::Object**, v8::internal::Isolate*) [/usr/local/bin/node]
6: 0x165e75e042fd
Aborted (core dumped)
Flip... I can see that the issue is with the first entry in the constructor of the UserService
but apart from that, it's pretty hard to see whats wrong. One great clue is that if you remove all of your database imports and run the code, you get the same error. This implies that those database imports and exports aren't working as expected. So what did I do wrong? I exported the TypeOrmModule.forRoot
calls from the DatabaseModule
when I should have just exported TypeOrmModule
. I also didn't import the TypeOrmModule.forFeature
in the SharedModule
. So to fix this issue, we need to do two things, first we need to change the DatabaseModule
,
The second thing we need to do is import the TypeOrmModule
using the forFeature
call in the SharedModule
,
And that's it, everything runs smoothly and we're able to run our nestjs application :) In any modules, make sure to call TypeOrmModule.forFeature([... the applicable entities go here])
and you should be good to go!
Edit 23/01/2019
If you're looking to extend your entities with BaseEntity
so that you don't need to inject a repository, then you'll need to name your database default
in the database-connections.ts
file. So in my case Config.get.databases.main.name
would return the string default
and, because of that, I can use the Active Record pattern.