I'm trying to implement a web application with a framework which lets you implement both API and user interface (NextJS). And I'm not sure what the best practices for modeling and Json responses are.
Considerations
- In the database the models are stored using foreign keys to reference other objects. There are
many-to-many
,one-to-many
andon-to-one
relationships. - Currently using a programming language that allows interface declaration (TypeScript).
- The interface declarations can be accessed from both front and back ends.
- When parsing a model, which has a foreign key, from the database in the backend (API) I use an instance of an interface which has the foreign key declared as a
string
. - To the front-end I want to return JSON with nested objects. This is, instead of giving a reference to the object in the foreign key, I want to embed an already retrieved object from the database.
The problem
If I want to archive this pattern, I'm forced to declare two interfaces: one with a simple shallow reference (foreign key) and another that allows an ambed object.
Example:
Say I have a Blog Post model: Post
:
interface Post {
id: string;
creatorId: string;
}
And another User model: User
:
interface User {
id: string;
name: string;
}
So for parsing from the database I'm using the Post
interface which represents exactly how it's stored in the database.
But if I want to return to the frontend the nested object I should rely on a model similar to:
interface PostWithNested {
id: string;
creator : User;
}
where the JSON
of this interface will be something like:
{
"id": "X",
"creator": {
"id" : "Y",
"name": "Z";
},
}
Example of the API where the parsing from the database must be done using an interface:
...
const postsRepository = getRepository(Post); // has shallow reference
const singlePost : Post = await postsRepository.findById(X);
// Adding nested object
const postWithNested : PostWithNested = {
id : singlePost.id,
user : userInstance,
}
res.status(200).json({post : postWithNested }
So is there a workaround for not declaring two interfaces that are essentially equal but differ on the reference to its related object?
CodePudding user response:
You can create an interface Post
with an optional creator
. For example
interface User {
id: string;
name: string;
}
interface Post {
id: string;
creatorId: string;
creator?: User; //it will be not populated, if it has no data
}
Whenever you receive creator
data from API, it will be populated automatically. Otherwise, it will be unset always in your Post
data. You can verify logs here.
Here is how we integrate it into your code
const postsRepository = getRepository(Post);
const singlePost : Post = await postsRepository.findById(X);
res.status(200).json({post : singlePost })
Similarly, if you have one-many
relationship. For example, 1 user has many posts, you will have this interface structure
interface User {
id: string;
name: string;
posts?: Post[]; //can keep many posts belong to this user
}
interface Post {
id: string;
creatorId: string;
creator?: User;
}