79-Nodejs Course 2023: Resources: Recursive Resources
Tags: node, typescript, mongodb, fastify
Published: 2022-12-03 04:00:11

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

In this article, we'll see how to use resource as an output type and how to implement it.

## Purpose

Why would we need to assign to an output key a `resource` type? well, because we're using MongoDB, which means a document(s) can be stored in a single key in another document, for example we can store `createdBy` object in literally any document (which we'll do later), and so on.

So we need to map that `createdBy` object to use its proper resource to make a proper response output.

We are going to learn how to use two things, checking wether if a variable is a typeof class, and also a partial recursion, which means a class/function that can call itself (in somehow).

## Before implementing

We're going to add a new feature in our `Resource` class, which is allowing outputs to be resources, this requires us to add a check for the `valueType` to check if it is a `Resource` type, so i want to show you how to check if a variable is a type of class, (The class itself not the object is instance of it).

```ts
// some-file.ts
class MyClass {

}

const A = MyClass;

// check if A is a `MyClass` type

if (A.prototype instanceof MyClass) {
  // A is a MyClass type
}
```

We used here `prototype` to check if the class is an instance of another class, so we can use this to check if the `valueType` is a `Resource` type.

So we can say if we want to check if variable is a `class` type, we use `prototype`, if we want to check if variable is an object/instance of class we use `instanceof` directly.

## Implementation

Now let's see how we can do this.

It's very simple, we just assign to the output key, let's say `createdBy` the value of `UserResource` type and in our `toJSON` we'll add another check if the given value type is typeof a `Resource`, then we'll pass the data to it, otherwise we'll skip the key entirely.

```ts
// src/core/resources/resource.ts
import { get } from "@mongez/reinforcements";

// this will be used to skip the output property if it is missing from the given resource
const missingKey = Symbol("missing");

export default class Resource {
  /**
   * Constructor
   */
  public constructor(protected resource: any = {}) {
    //
  }

  /**
   * Output shape
   */
  protected output: any = {};

  /**
   * {@inheritDoc}
   */
  public toJSON() {
    // final output
    const data: Record<string, any> = {};

    // loop through the output property
    for (const key in this.output) {
      // get the value type
      const valueType = this.output[key];
      // get the value, and also make sure to skip the output property if it is missing from the given resource
      let value = get(this.resource, key, missingKey);

      // skip the output property if it is missing from the given resource
      if (value === missingKey) {
        continue;
      }

      if (typeof valueType === "string") {
        // cast the value
        value = this.cast(value, valueType);
      } else if (valueType.prototype instanceOf Resource) {
        // if the value type is a resource, then pass the value to it
        value = new valueType(value).toJSON();
      } else if (typeof valueType === "function") {
        // call the custom output handler
        value = valueType(value);
      }

      // just for now sett the output value to the data
      data[key] = value;
    }

    return data;
  }
  
  /**
   * Builtin casts
   */
  protected cast(value: any, type: string) {
    switch (type) {
      case "number":
        return Number(value);
      case "float":
      case "double":
        return parseFloat(value);
      case "int":
      case "integer":
        return parseInt(value);
      case "string":
        return String(value);
      case "boolean":
        return Boolean(value);
      default:
        return value;
    }
  }
}
```

Here we just added a little if statement, which is checking if the value type is a `Resource` type, if so, then we'll pass the value to it, otherwise we'll skip the key entirely.

Now we can update our `UserResource` class

```ts
// src/app/users/resources/user-resource.ts
import Resource from 'core/resources/resource';
import { uploadsUrl } from 'core/utils/urls';

export default class UserResource extends Resource {
  /**
   * Output shape
   */
  protected output: any = {
    id: 'number',
    name: 'string',
    email: 'string',
    age: 'number',
    avatar: uploadsUrl,
    createdBy: UserResource,
 };
}
```

This should be working just fine with you, pass to the data a key named `createdBy` and pass to it the object.

The point here is to map that data into a proper output using the `UserResource` class.

This is also called `Recursive Resource` because we're using the same resource to map the data to the output.

## 🎨 Conclusion

We just learnt how to implement a recursive call for resources inside each other, also how to check if a variable is a type of class.

## ☕♨️ 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)