How can I set an entity type within a dto [NestJS]? - node.js

I don't even think I've got a proper question so I apologize greatly.
I am consuming a 3rd party API and to update or create records, one of the fields is the entity type.
For example, here is my CreateOrganizationDTO:
export class CreateOrganizationDto {
#ApiProperty({
description: "The entity type. Only 'organization' is allowed.",
example: "organization",
})
#IsNotEmpty()
readonly #type: string; <-- this
...
I'm not sure how to properly handle the # character. I've tried different versions of '#type' or ['#type']. Clearly, neither are correct. I'm also not sure how to send that data through my service. For example:
// MyService.ts
const {name, #type, active} = updateOrganizationDto;
organization.name = name;
organization.#type = #type; <-- not going to work :(
organization.active = active;
...
What is the proper way to "escape" this # throughout my application? Thank you for any suggestions!

Related

DDD : Business Logic which need infra layer access should be in application service layer, domain service or domain objects?

For an attribute which need to be validated, lets say for an entity we have country field as VO
This country field needs to be validated to be alpha-3 code as per some business logic required by domain expert.
NOTE:
*We need to persist this country data as it can have other values also and possible in future there can be addition, updating and deleting of the country persisted data.
This is just one example using country code which may rarely change, there can be other fields which needs to be validated from persistence like validating some quantity with wrt data in persistence and it won't be efficient to store them in memory or prefetching them all.
Another valid example can be user creation with unique and valid domain email check, which will need uniqueness check from persistence
*
Case 1.
Doing validation in application layer:
If we call repository countryRepo.getCountryByCountryAlpha3Code() in application layer and then if the value is correct and valid part of system we can then pass the createValidEntity() and if not then can throw the error directly in application layer use-case.
Issue:
This validation will be repeated in multiple use-case if same validation need to be checked in other use-cases if its application layer concern
Here the business logic is now a part of application service layer
Case 2
Validating the country code in its value object class or domain service in Domain Layer
Doing this will keep business logic inside domain layer and also won't violate DRY principle.
import { ValueObject } from '#shared/core/domain/ValueObject';
import { Result } from '#shared/core/Result';
import { Utils } from '#shared/utils/Utils';
interface CountryAlpha3CodeProps {
value: string;
}
export class CountryAlpha3Code extends ValueObject<CountryAlpha3CodeProps> {
// Case Insensitive String. Only printable ASCII allowed. (Non-printable characters like: Carriage returns, Tabs, Line breaks, etc are not allowed)
get value(): string {
return this.props.value;
}
private constructor(props: CountryAlpha3CodeProps) {
super(props);
}
public static create(value: string): Result<CountryAlpha3Code> {
return Result.ok<CountryAlpha3Code>(new CountryAlpha3Code({ value: value }));
}
}
Is it good to call the repository from inside domain layer (Service
or VO (not recommended) ) then dependency flow will change?
If we trigger event how to make it synchronous?
What are some better ways to solve this?
export default class UseCaseClass implements IUseCaseInterface {
constructor(private readonly _repo: IRepo, private readonly countryCodeRepo: ICountryCodeRepo) {}
async execute(request: dto): Promise<dtoResponse> {
const someOtherKeyorError = KeyEntity.create(request.someOtherDtoKey);
const countryOrError = CountryAlpha3Code.create(request.country);
const dtoResult = Result.combine([
someOtherKeyorError, countryOrError
]);
if (dtoResult.isFailure) {
return left(Result.fail<void>(dtoResult.error)) as dtoResponse;
}
try {
// -> Here we are just calling the repo
const isValidCountryCode = await this.countryCodeRepo.getCountryCodeByAlpha2Code(countryOrError.getValue()); // return boolean value
if (!isValidCountryCode) {
return left(new ValidCountryCodeError.CountryCodeNotValid(countryOrError.getValue())) as dtoResponse;
}
const dataOrError = MyEntity.create({...request,
key: someOtherKeyorError.city.getValue(),
country: countryOrError.getValue(),
});
const commandResult = await this._repo.save(dataOrError.getValue());
return right(Result.ok<any>(commandResult));
} catch (err: any) {
return left(new AppError.UnexpectedError(err)) as dtoResponse;
}
}
}
In above application layer,
this part of code :
const isValidCountryCode = await this.countryCodeRepo.getCountryCodeByAlpha2Code(countryOrError.getValue()); // return boolean value
if (!isValidCountryCode) {
return left(new ValidCountryCodeError.CountryCodeNotValid(countryOrError.getValue())) as dtoResponse;
}
it it right to call the countryCodeRepo and fetch result or this part should be moved to domain service and then check the validity of the countryCode VO?
UPDATE:
After exploring I found this article by Vladimir Khorikov which seems close to what I was looking, he is following
As per his thoughts some domain logic leakage is fine, but I feel it will still keep the value object validation in invalid state if some other use case call without knowing that persistence check is necessary for that particular VO/entity creation.
I am still confused for the right approach
In my opinion, the conversion from String to ValueObject does not belong to the Business Logic at all. The Business Logic has a public contract that is invoked from the outside (API layer or presentation layer maybe). The contract should already expect Value Objects, not raw strings. Therefore, whoever is calling the business logic has to figure out how to obtain those Value Objects.
Regarding the implementation of the Country Code value object, I would question if it is really necessary to load the country codes from the database. The list of country codes very rarely changes. The way I've solved this in the past is simply hardcoding the list of country codes inside the value object itself.
Sample code in pseudo-C#, but you should get the point:
public class CountryCode : ValueObject
{
// Static definitions to be used in code like:
// var myCountry = CountryCode.France;
public static readonly CountryCode France = new CountryCode("FRA");
public static readonly CountryCode China = new CountryCode("CHN");
[...]
public static AllCountries = new [] {
France, China, ...
}
public string ThreeLetterCode { get; }
private CountryCode(string threeLetterCountryCode)
{
ThreeLetterCode = threeLetterCountryCode;
}
public static CountryCode Parse(string code)
{
[...] handle nulls, empties, etc
var exists = AllCountries.FirstOrDefault(c=>c.ThreeLetterCode==code);
if(exists == null)
// throw error
return exists;
}
}
Following this approach, you can make a very useful and developer-friendly CountryCode value object. In my actual solution, I had both the 2 and 3-letter codes and display names in English only for logging purposes (for presentation purposes, the presentation layer can look up the translation based on the code).
If loading the country codes from the DB is valuable for your scenario, it's still very likely that the list changes very rarely, so you could for example load a static list in the value object itself at application start up and then refresh it periodically if the application runs for very long.

NestJS class-validators on incoming requests using interface

I need to use an interface through class-validator to validate the incoming form for a specific field in the incoming request body.
The interface:
export enum Fields {
Full_Stack_Dev = 'full stack dev',
Frontend_Dev = 'frontend dev',
Backend_Dev = 'backend dev',
}
export interface Experience {
field: Fields;
years: number;
}
And here is the DTO Class:
#IsEnum(Languages)
languages: Languages[];
experience: Experience[]; // 👈 Not sure which decorator to use for interfaces
Okay after doing a lot of research, I found a workaound for this:
First of all, Interfaces CANNOT be used directly. Officially declared by class-validators issue here
This is what I did:
Changed the interface into a separate class and added validation on its properties
class ExperienceDto {
#IsEnum(Fields)
field: Fields;
#IsNumber()
years: number;
}
Then used this class as type to validate Array of Objects in the ACTUAL DTO CLASS (not the above one)
#ArrayNotEmpty()
#ArrayMinSize(1)
#ArrayMaxSize(3)
#ValidateNested({ each: true })
#Type(() => ExperienceDto) // imported from class-transformer package
experience: ExperienceDto[];

TSNode + Mocha: Ignore TypeScript errors (make compiler emit on errors and make TSNode execute emitted code)

In the below code, although function test2 in invalid, it should not affect to testing of function test1:
export function test1(): boolean {
return true;
}
export function test2(): number {
return "1";
}
Test:
import { assert as Assert } from "chai";
import { test1 } from "./example";
describe("Example", (): void => {
it("Example", (): void => {
Assert.isTrue(test1());
});
});
However Mocha, executed by TSNode will fail:
TSError: ⨯ Unable to compile TypeScript:
Source/ProjectBuilder/example.ts(6,3): error TS2322: Type '"1"' is not assignable to type 'number'.
Possible to force TSNode to complete above test? TypeScript has option noEmitOnError...
My mocharc.yaml:
extension:
- ts
spec: "**/*.test.ts"
require:
- ts-node/register
- tsconfig-paths/register
Why I need it
According the Clean Architecture, "Business rules must not depends on anything, and it must be testable". But even if business rules does not depend on views, controllers, etc., we can not test it if some errors in views, controllers, etc. exists.
When I modify business logic in my application, all that depend on it becomes invalid. Assume that in my entity in business logic type User { name: string; age: number } has been changed to type User { fullName: string; age: string; }. All that depend on business logic (view, controllers, presenters, etc.) becomes invalid - I need to correct it too according updated to business logic.
// In business rules:
type User = {
ID: number;
fullName: string;
age: string; // in past - number
}
// In controller:
class UserProfileController {
// ...
// All what comes from input field is string ↓
private onClickChangeUserAge(inputtedUserAge: string) {
// This expression obeys to previous version of business rules!
this.targetUser.age = Number(inputtedUserAge);
// TypeScript will emit type error, when I try to test business rules,
// however business rules does not depend on controller.
}
}
However, in big application, this corrections could takes days, weeks and months. How we can get the feedback proves that at least business logic works properly and we are in right way?
It would not make sense for you to ask Typescript to disregard types. What you are describing is akin to asking for a calculator that confirms that 2 + 2 = 5, only temporarily, because eventually you will ask for 2 + 3 = 5 but that might take a very long time.
The assumption in your question is that number and string are sufficiently compatible that your business logic will be sound regardless of whether test2 returns 1 or "1". This is not true: By way of example, 1 + 1 == 2, "1" + 1 == "11", and "1" - 1 == 0. Depending on which of those applies to your case, disregarding types may allow you to test your business logic, or may give you false confidence in a broken system. I would venture that in general the data types count as part of the business logic you're trying to verify--what would the data model count as, if not business logic?
Instead, what you are describing is a gradual migration during which the business rules ensure that test2 returns string | number. By describing the migration accurately in the type system, you may be able to confirm that the business logic applies correctly--if that is true across your migration--and also provide a type that you can apply only from certain modules and call sites that can be tightened up as you finish the migration.
type User = {
ID: number;
fullName: string;
age: string | number
}
You can specify both types to make migration easier and not use //#ts-ignore everywhere.
This will add proper suggestions everywhere like:

NestJS - Validating body conditionally, based on one property

I'm trying to find a nice way to validate a body using DTO (using the brilliant class-validator and class-transformer libraries). It works really well, even for nested structures but in my case I'd like to have the body property based on some conditions.
Example that will probably help to understand:
Let's imagine my body should always have selectedCategory.
Based on that field, the content could either be from category 1, which contains prop1 OR from category 2, which contains prop2.
I do not want to allow a null for both of them, I really want to have to either have prop1 defined or prop2 based on the selectedCategory.
I think that I could use a pipe, but then how can I specify the correct DTO to use?
I've built a "base" class with all the common properties and few other classes that inherit from it.
I could instantiate the pipe manually based on the property selectedCategory, that'd be ideal but I have no clue what to pass as a second argument of the pipe (metadata).
Thanks for your help.
Have you tried using groups?
Instead of having multiple DTOs, you just create one DTO. Every property is assigned to one or multiple groups:
#Min(12, {groups: ['registration', 'update']})
age: number;
#Length(2, 20, {groups: ['registration']})
name: string;
You can then conditionally pass the groups to class transformer / validator:
#Injectable()
export class ConditionalValidationPipe implements PipeTransform {
async transform(entity: any, metadata: ArgumentMetadata) {
// Dynamically determine the groups
const groups = [];
if (entity.selectedCategory === 1) {
groups.push('registration');
}
// Transform to class with groups
const entityClass = plainToClass(EntityDto, entity, { groups })
// Validate with groups
const errors = await validate(entityClass, { groups });
if (errors.length > 0) {
throw this.createError(errors);
}
return entityClass;
}
}
Have you tried the ValidateIf statement?
You can have multiple validations for props1 or props2 and apply them if selectedCategory is "category 1" or "category 2" accordingly.

Why does JHipster generate Interfaces for Angular model objects?

Why does JHipster generate interfaces for each Angular model object?
e.g.
export interface IStudent {
id?: number;
studentIdentifier?: string;
firstName?: string;
lastName?: string;
}
export class Student implements IStudent {
constructor(
public id?: number,
public studentIdentifier?: string,
public firstName?: string,
public lastName?: string,
) {}
}
I cannot find the original discussion but in my understanding, this is because of the way how interfaces work in TypeScript, which is a little different than in Java. They not just describe how a class should look like by defining its method, but also which fields should be present. So you can define, how a JSON from somewhere should look like. Like a POJO. Or a POTO (plain old TypeScript object) :)
By example, you could do that:
let student: IStudent = { id: 123, studentIdentifier: '...',...}
and TS would check if your provided object satisfies the defined structure of student. When you get an object out from the API, you just map a JSON directly this way, so there is no class in between. From the other side, it's more handy to work with classes rather than interfaces, when building objects of IStudent directly. As it also satisfies IStudent, you can make just
let student: IStudent = new Student(123, '...', ..)
which is shorter.
You could rely also on my first snippet (this is how ionic does it, btw. Using interfaces as POJOs/POTOs). Using classes only in TS leads to a bad developer experience IMHO.
Hope that helps a little bit out

Resources