Home > database >  Object modeling and JSON responses
Object modeling and JSON responses

Time:04-03

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 and on-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; 
}
  • Related