Creating Custom Data Classes
You can use FP’s Literal
class for successful data,
but has many limitations.
To go beyond the default Literal
class, you can define a custom class that extends
DataFP
(an abstract class from FP).
Example class created by extending
DataFP
import { ApiProperty } from "@nestjs/swagger";
import { Expose } from "class-transformer";
import { Equals, IsIn, IsJWT, IsString } from "class-validator";
import { DataFP } from "./DataFP";
export class LoginResponse extends DataFP<"LoginResponse", 200 | 201> {
public static readonly kind = "LoginResponse"; (1)
@ApiProperty() (2)
@Equals("LoginResponse")
@Expose()
public override readonly kind: "LoginResponse"; (3)
@ApiProperty()
@IsIn([200, 201])
@Expose()
public override readonly status: 200 | 201; (3)
@ApiProperty()
@IsString()
@Expose()
public readonly id: string; (4)
@ApiProperty()
@IsJWT()
@Expose()
public readonly jwt: string; (4)
public constructor(
id: string,
jwt: string,
newRegistration: boolean = false,
) {
super();
this.kind = "LoginResponse";
this.status = newRegistration ? 201 : 200;
this.id = id;
this.jwt = jwt;
}
}
1 | Defining a static kind property is used in some utilities, but is not required. |
2 | DataFP does not attach ApiProperty , Expose , or any validation decorators (unlike other FP classes) - if using OpenAPI or fp-interceptor you should declare ApiProperty and Expose . |
3 | You must define kind and status fields. |
4 | You may define any additional fields to represent your data, such as id and jwt . |
Now the properties are exposed directly in the returned object,
no need to go through data
:
Example usage of custom class extending
DataFP
const response = new LoginResponse("admin", "[jwt contents]");
expect(response.id).toBe("admin");
If an error might be returned, you can check that the value is a LoginResponse
before
accessing fields, or use a transformation like map
or chain
.
async function performLogin(
username: string,
password: string,
): Promise<LoginResponse | UnexpectedError<LoginResponse>> {
return response;
}
const login = await performLogin("admin", "top-secret-password");
if(login.hasData) {
console.log(`Success! JWT: ${login.jwt}`);
} else {
console.log("Failed login.");
}