Currently, I am faced with a common challenge. I have a database object that is a standard JS object originating from a document database, and my goal is to transmit this object to the client. However, certain fields contain sensitive information that should not be exposed to the client.
In the realm of C#, I would typically utilize Declarative Reflective programming by attaching attributes to my C# object, specifying which fields are safe for client use as demonstrated below:
[SafeForClient]
string MyProperty { get; set; } // send to client.
string SecretData { get; set; } // Do NOT send to client.
I would then employ reflection to collect all properties marked with [SafeForClient]
, compile my JSON, and transfer it over to the client. Unfortunately, JavaScript lacks such declarative metaprogramming capabilities at this level.
In TypeScript, I define my types as follows:
export type RoomForClient = {
id: number;
name: string;
description: string;
exits: {[index in Direction]?: Exit }
}
export type Room = RoomForClient & {
hiddenFlags: ScriptData;
}
The room data sent to the client represents only a subset of the complete room data. Currently, if there is one property that should not be included, I can simply remove that attribute from the object. However, as more properties are introduced in the future, I will need to specify those property names in two locations - once in the Room
definition and again in the method responsible for trimming down the object.
How can I generate a "RoomForClient" object from a "Room" object without manually listing all the fields that should or shouldn't be copied? Since all type information is removed at runtime, I am struggling to devise a solution that doesn't violate the DRY principle, which I consider a code smell.
Any suggestions?