87-Nodejs Course 2023: Resource: Resources In Models
Tags: node, typescript, mongodb, fastify
Published: 2022-12-04 16:21:24

---
title: 87-Nodejs Course 2023: Resource: Resources In Models
published: true
description: 
series: Nodejs Course 2023
tags: nodejs, typescript, mongodb, fastify
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p06vruji1a033g6aq5l2.png
# Use a ratio of 100:42 for best results.
---

Let's update our codebase and go to the next level, let's embed our resources in our models!

## The idea

Let's take a look at the following code:

```ts
// src/users/controllers/users-list.ts

import User from "../models/user";

export default async function usersList() {
  const users = await User.list();

  return {
    users,
  };
}
```

This will basically return an array of models and will return the entire properties listed in each model, that's ugly too way ugly, in that sense, we need to link our model with our resource, if the model does not have a resource, then we'll just return only the `data` not the entire model.

## toJSON method

Let's implement the easy part first, let's create a `toJSON` method in our `base-model` file, remember it? that model that we buried in our models folder, let's add a new method to it:

```ts
// src/core/database/model/base-model.ts

// ...

export default abstract class BaseModel {

  /**
   * Prepare model for response
   */
  public async toJSON() {
    return (this as any).data;
  }
}
```

Why we added `any` because `CrudModel` does not anything about it, we added that property in our `Model` class so we need to tell typescript that it's okay to use it.

And also we made it `async` because of the next step, adding the resource.

## Adding Resource

The resource will be added as a `static` property, why? well because we may access the Models' resource without the need to create an instance of the model, for example:

```ts
const UserResource = User.resource;

return {
    user: new UserResource({
        id: 1,
        name: 'Hasan',
    })
};
```

I know that's sounds weird, why not just call the `UserResource` class directly, well you're right, but let's stick with that idea, i like it more.

Returning back to our code, let's add the `resource` property to our `BaseModel` class:

```ts
// src/core/database/model/base-model.ts
import Resource from 'core/resources/resource';
// ...

export default abstract class BaseModel {

  /**
   * Resource class
   */
  public static resource: typeof Resource;

  // ...
}
```

Now Let's update the `toJSON` method to use the resource:

```ts
// src/core/database/model/base-model.ts
import Resource from 'core/resources/resource';
// ...

export default abstract class BaseModel {

  /**
   * Resource class
   */
  public static resource: typeof Resource;

  /**
   * Prepare model for response
   */
  public async toJSON() {
    // get static resource class
    const resource = this.getStaticProperty("resource");

    // if the model has a resource class
    if (resource) {
      // then return the resource instance and call `toJSON` method
      return await new resource(this).toJSON();
    }

    // otherwise return the data object
    return (this as any).data;
  }
}
```

And that's it! now we can try this with our User model

```ts
// src/app/users/models/user.ts

import Auth from "core/auth/models/auth";
import castPassword from "core/database/casts/cast-password";
import { Casts, Document } from "core/database/model/types";
import UserResource from "../resources/user-resource";

export default class User extends Auth {
  /**
   * Collection name
   */
  public static collectionName = "users";

  /**
   * Resource
   */
  public static resource = UserResource;

  /**
   * Get user type
   */
  public get userType(): string {
    return "user";
  }

  /**
   * {@inheritDoc}
   */
  public defaultValue: Document = {
    isActive: true,
    isEmailVerified: false,
    isPhoneVerified: false,
  };

  protected casts: Casts = {
    isActive: "boolean",
    isPhoneVerified: "boolean",
    joinDate: "date",
    password: castPassword,
  };
}
```

Now our user model is linked automatically with the `UserResource` class.

## Usage

Now let's see the magic happens, let's update our `users-list` controller:

```ts
// src/users/controllers/users-list.ts

import User from "../models/user";

export default async function usersList() {
  const users = await User.list();

  return {
    users,
  };
}
```

Same exact code, but this time you'll see in your response that it is returned from the resource not the model directly, and to make sure it works fine, let's add boot method in our user resource and add custom property in the final output.

```ts
// src/app/users/resources/user-resource.ts

import Resource from "core/resources/resource";

export default class UserResource extends Resource {
  /**
   * {@inheritDoc}
   */
  protected async boot() {
    this.set('outputFromUserResource', true);s
  }
}
```

Now you should see something like this:

```json

{
  "users": [
    {
      "outputFromUserResource": true,
      "isActive": true,
      "isPhoneVerified": false,
      "name": "John Doe",
      "email": "hassanzohdy@gmail.com",
      "image": "http://127.0.0.1:3000/uploads/users/my-image.jpg"
    },
    {
      "outputFromUserResource": true,
      "isActive": true,
      "isPhoneVerified": false,
      "name": "John Doe",
      "email": "hassanzohdy@gmail.com",
      "image": "http://127.0.0.1:3000/uploads/users/my-image.jpg"
    },
    {
      "outputFromUserResource": true,
      "isActive": true,
      "isPhoneVerified": false,
      "name": "John Doe",
      "email": "hassanzohdy@gmail.com",
      "image": "http://127.0.0.1:3000/uploads/users/my-image.jpg"
    },
    {
      "outputFromUserResource": true,
      "isActive": true,
      "isPhoneVerified": false,
      "name": "John Doe",
      "email": "hassanzohdy@gmail.com",
      "image": "http://127.0.0.1:3000/uploads/users/my-image.jpg"
    },
    {
      "outputFromUserResource": true,
      "isActive": true,
      "isPhoneVerified": false,
      "name": "John Doe",
      "email": "hassanzohdy@gmail.com",
      "image": "http://127.0.0.1:3000/uploads/users/my-image.jpg"
    },
    {
      "outputFromUserResource": true,
      "isActive": true,
      "isPhoneVerified": false,
      "name": "John Doe",
      "email": "hassanzohdy@gmail.com",
      "image": "http://127.0.0.1:3000/uploads/users/my-image.jpg"
    }
  ]
}
```

And that's it!

## 🎨 Conclusion

We saw in this tutorial how to manipulate the model when is being returned in response and also how to link a resource to model.

## ☕♨️ Buy me a Coffee ♨️☕

If you enjoy my articles and see it useful to you, you may [buy me a coffee](https://www.paypal.com/paypalme/hassanzohdy), it will help me to keep going and keep creating more content.

## 🚀 Project Repository

You can find the latest updates of this project on [Github](https://github.com/hassanzohdy/nodejs-2023)

## 😍 Join our community

Join our community on [Discord](https://discord.gg/pb2vmdfhGf) to get help and support (Node Js 2023 Channel).

## 🎞️ Video Course (Arabic Voice)

If you want to learn this course in video format, you can find it on [Youtube](https://www.youtube.com/playlist?list=PLGO8ntvxgiZMJc7RN2lIq9WmMOlWZGzmz), the course is in Arabic language.

## 📚 Bonus Content 📚

You may have a look at these articles, it will definitely boost your knowledge and productivity.

General Topics

* [Event Driven Architecture: A Practical Guide in Javascript](https://dev.to/hassanzohdy/event-driven-architecture-the-best-paradigm-that-i-love-to-work-with-in-javascript-and-node-js-1gnk)
* [Best Practices For Case Styles: Camel, Pascal, Snake, and Kebab Case In Node And Javascript](https://dev.to/hassanzohdy/best-practices-for-case-styles-camel-pascal-snake-and-kebab-case-in-node-and-javascript-55oi)
* [After 6 years of practicing MongoDB, Here are my thoughts on MongoDB vs MySQL
](https://dev.to/hassanzohdy/after-6-years-of-practicing-mongodb-here-are-my-thoughts-on-mongodb-vs-mysql-574b)

Packages & Libraries

* [Collections: Your ultimate Javascript Arrays Manager](https://dev.to/hassanzohdy/collections-your-ultimate-javascript-array-handler-3o15)
* [Supportive Is: an elegant utility to check types of values in JavaScript](https://dev.to/hassanzohdy/supportive-is-an-elegant-utility-to-check-types-of-values-in-javascript-1b3e)
* [Localization: An agnostic i18n package to manage localization in your project](https://dev.to/hassanzohdy/mongez-localization-the-simplest-way-to-translate-your-website-regardless-your-favorite-framework-4gi3)

 React Js Packages

* [useFetcher: easiest way to fetch data in React Js](https://dev.to/hassanzohdy/usefetcher-the-easiest-way-to-fetch-data-in-react-45o9)

Courses (Articles)

* [OOP In JS And TS From The Very Beginning](https://dev.to/hassanzohdy/jsts-oop-course-1-introduction-2ld)
* [ES6++: The Ultimate Guide to ES6 and Beyond](https://dev.to/hassanzohdy/es6-1-introduction-h3e)
* [React Js: Let"s Create File Manager With React Js and Node Js](https://dev.to/hassanzohdy/lets-create-a-file-manager-from-scratch-with-react-and-typescript-chapter-i-a-good-way-to-expand-your-experience-5g4k)