I'd like to DI for repository interface and service interface like Spring using typedi.
Below code (example code of DI for repository) is working correctly when calling api.
Repository
import { Service } from "typedi";
import { EntityRepository, Repository } from "typeorm";
import { User } from "../entity/User";
export interface IUserRepository {
findAllUsers();
findUserByUserId(id: number);
addUser(user: any);
removeUserByUserId(user: any);
}
@Service()
@EntityRepository(User)
export class UserRepository
extends Repository<User>
implements IUserRepository {
findAllUsers() {
return this.find();
}
findUserByUserId(id: number) {
return this.findOne({ id });
}
addUser(user: any) {
return this.save(user);
}
removeUserByUserId(user: any) {
return this.remove(user);
}
}
Service
import { Service } from "typedi";
import { InjectRepository } from "typeorm-typedi-extensions";
import { User } from "../entity/User";
import { UserRepository } from "../repository/userRepository";
export interface IUserService {
all();
one(id: any);
save(user: any);
remove(id: any);
}
@Service()
export class UserService implements IUserService {
@InjectRepository(User)
private userRepository: UserRepository;
async all() {
return this.userRepository.findAllUsers();
}
async one(id: any) {
let user = await this.userRepository.findUserByUserId(id);
if (typeof user === "undefined") {
throw new Error(`userId ${id} is not found.`);
}
return user;
}
async save(user: any) {
return this.userRepository.addUser(user);
}
async remove(id: any) {
let userToRemove = await this.userRepository.findUserByUserId(id);
if (typeof userToRemove === "undefined") {
throw new Error(`userId ${id} is not found.`);
}
return this.userRepository.removeUserByUserId(userToRemove);
}
}
However, when I'd like to inject repository using interface, it does not work correctly and occur the error message.
The build is succes. The error message is occur when calling api
In addition, error message are different for the first time and the second time later when call api.
like this
Repository
import { Service } from "typedi";
import { InjectRepository } from "typeorm-typedi-extensions";
import { User } from "../entity/User";
import { UserRepository } from "../repository/userRepository";
...
@Service()
export class UserService implements IUserService {
@InjectRepository(User)
private userRepository: UserRepository;
async all() {
return this.userRepository.findAllUsers();
}
...
}
Error message of first time.
{
"name": "CustomRepositoryNotFoundError",
"message": "Custom repository Object was not found. Did you forgot to put @EntityRepository decorator on it?",
"stack": "CustomRepositoryNotFoundError: Custom repository Object was not found. Did you forgot to put @EntityRepository decorator on it? (The following is omitted)"
}
Error message of second time later.
{
"name": "TypeError",
"message": "Cannot read property 'all' of undefined",
"stack": "TypeError: Cannot read property 'all' of undefined(The following is omitted)"
}
Service does not work well either.
Below code is success code.
Controller
import {
Get,
JsonController,
OnUndefined,
Param,
Post,
Body,
Delete,
} from "routing-controllers";
import { Inject, Service } from "typedi";
import { UserService } from "../service/userService";
@Service()
@JsonController("/users")
export class UserRestController {
@Inject()
private userService: UserService;
@Get("/")
getAll() {
return this.userService.all();
}
@Get("/:id")
@OnUndefined(404)
getOne(@Param("id") id: number) {
return this.userService.one(id);
}
@Post("/")
add(@Body() user: any) {
return this.userService.save(user);
}
@Delete("/:id")
delete(@Param("id") id: number) {
return this.userService.remove(id);
}
}
But the below is not work well. In this case, even the build does not work.
Controller
import {
Get,
JsonController,
OnUndefined,
Param,
Post,
Body,
Delete,
} from "routing-controllers";
import { Inject, Service } from "typedi";
import { IUserService } from "../service/userService";
@Service()
@JsonController("/users")
export class UserRestController {
@Inject()
private userService: IUserService;
@Get("/")
getAll() {
return this.userService.all();
}
@Get("/:id")
@OnUndefined(404)
getOne(@Param("id") id: number) {
return this.userService.one(id);
}
@Post("/")
add(@Body() user: any) {
return this.userService.save(user);
}
@Delete("/:id")
delete(@Param("id") id: number) {
return this.userService.remove(id);
}
}
Error Message
CannotInjectValueError: Cannot inject value into "UserRestController.userService". Please make sure you setup reflect-metadata properly and you don't use interfaces without service tokens as injection value.
As described at the beginning, I'd like to DI for repository interface and service interface like Spring using typedi.
TypeDI cannnot using like this?
or my code is wrong?
Please help me.
Thank you.
Interfaces are ephemeral, they don't actually exist when your code is running doing its job, they exist only when you write the code. Classes, on the other hand, are pretty much tangible, they always exist. That's why when you use
UserService
class, it works, but when you useIUserService
interface, it doesn't work.The error you are getting tells you something useful: