Currently, I am facing a challenge while developing the frontend of a web application using TypeScript. The dilemma revolves around efficiently converting a data object from an API response into a format suitable for the application.
Let's consider retrieving a BlogpostAPI object from the API:
interface BlogpostAPI {
title: string;
content: string;
createdAt: string;
// ...and other properties
}
The objective is to transform it into:
interface BlogpostApp {
title: string;
content: BlogpostBlock[];
createdAt: Date;
// ...along with other properties that might require transformation
}
type BlogpostBlock = {
role: 'body' | 'header';
text: string;
}
I am striving for clean code and wish to encapsulate the transformation logic within a class. However, my current solutions seem complex and cumbersome.
For instance, let's say I intend to create a Blogpost class specifically for handling the transformation logic and potential additional functionalities in the future.
class Blogpost implements BlogpostApp {
title: string;
content: BlogpostBlock[];
createdAt: Date;
constructor(post: BlogpostApp) {
this.title = post.title;
this.content = post.content;
this.createdAt = post.createdAt;
}
static fromBlogpostAPI(post: BlogpostAPI): Blogpost {
const content: BlogpostBlock[] = post.content.split('\n').map((s, idx) => {
if (idx === 0) return { text: s, role: 'header' };
return { text: s, role: 'body' };
};
const createdAt: Date = new Date(post.createdAt);
return new Blogpost({ title: post.title, content, createdAt });
}
}
However, there are some concerns raised by this approach.
- The
BlogpostApp
interface serves solely to enhance the readability of the arguments in theBlogpost
constructor. - If the class primarily focuses on transforming the BlogpostAPI interface, having two identical entities (
BlogpostApp
andBlogpost
) with matching properties may lead to confusion.
An alternative could involve creating a separate transformer class without implementing interfaces:
class BlogpostTransformer {
constructor() {}
static transform(post: BlogpostAPI): BlogpostApp {
const content: BlogpostBlock[] = post.content.split('\n').map((s, idx) => {
if (idx === 0) return { text: s, role: 'header' };
return { text: s, role: 'body' };
});
const createdAt: Date = new Date(post.createdAt);
return { title: post.title, content, createdAt } as BlogpostApp;
}
}
Although this method isolates the transformation process, having multiple classes for various data objects obtained from APIs raises concerns about architectural robustness.
It appears that I am missing a conventional approach for performing these transformations. Any assistance would be greatly appreciated!