83-Nodejs Course 2023: Resources: Allowed And Disabled Outputs

hassanzohdy

Hasan Zohdy

Posted on December 3, 2022

83-Nodejs Course 2023: Resources: Allowed And Disabled Outputs

Sometimes, we can use the resource in multiple apis, for example we may use the resource for admin api and for the front office (Website or mobile app) api, therefore some keys can be displayed in the admin but not in the front office.

For example, the published key probably won't be needed in the front office, but it will be needed in the admin thus we need to disable it if it was sent to the resource so it doesn't get displayed in the front office.

Allowed And Disabled Outputs

To achieve this, we need to define two static properties, disabledKeys and allowedKeys, these properties will be used to filter the data before sending it to the response.

Defining Disabled Keys

Now let's update our base resource class and add a new static method disable this method receives multiple keys that are going to be used to filter the data before sending it to the response.

// src/core/resources/resource.ts
// ...
export default class Resource {
  // ...
  /**
   * Disabled keys from being returned in the final output
   */
  protected static disabledKeys: string[] = [];

  /**
   * Disable the given keys
   */
  public static disable(...keys: string[]) {
    this.disabledKeys.push(...keys);

    return this;
  }
  // ...
}
Enter fullscreen mode Exit fullscreen mode

We defined here out disable method that allows us to add multiple keys to the disabledKeys array.

Defining Allowed Keys

Now let's do the same with the other case, we'll define a new static method allow this method receives multiple keys that are going to be used to filter the data before sending it to the response.

// src/core/resources/resource.ts
// ...

export default class Resource {
  // ...
  /**
   * Allowed keys to be returned in the final output
   */
  protected static allowedKeys: string[] = [];

  /**
   * Allow the given keys
   */
  public static allow(...keys: string[]) {
    this.allowedKeys.push(...keys);

    return this;
  }
  // ...
}
Enter fullscreen mode Exit fullscreen mode

Of course as usual, these methods have no effect until we use them in our toJSON method, so let's update it.

Updating toJSON

To do so, we need to define also two internal methods one to check for the given key that will be in the output object if it is disabled, if so then skip the transformation step and go to the next key.

And also we need to check if the given key is not in the allowed list, if so then skip the transformation step and go to the next key.

But note that the allowed list must have at least one key, otherwise, it will be ignored and all keys will be allowed.

// src/core/resources/resource.ts
// ...
export default class Resource {
  // ...

  /**
   * Check if the given key is disabled
   */
  protected isDisabledKey(key: string) {
    return (this.constructor as typeof Resource).disabledKeys.includes(key);
  }

  /**
   * Check if the given key is allowed
   */
  protected isAllowedKey(key: string) {
    const allowedKeys = (this.constructor as typeof Resource).allowedKeys;
    return allowedKeys.length === 0 || allowedKeys.includes(key);
  }

  // ...
}
Enter fullscreen mode Exit fullscreen mode

You may get confused with the syntax this.constructor, why? because we are trying to access a static member from non static member, and also we need to access it from the child resource class not the base class, otherwise we could just used Resource.disabledKeys and Resource.allowedKeys.

In the first method isDisabledKey we check if the given key is in the disabledKeys array, if so then we return true otherwise false.

In the second method isAllowedKey we check if the allowedKeys array is empty, if so then we return true otherwise we check if the given key is in the allowedKeys array, if so then we return true otherwise false.

Now let's use these methods in our toJSON method.

// src/core/resources/resource.ts
// ...

export default class Resource {
  // ...

  /**
   * Final data output
   */
  protected data: Record<string, any> = {};

  /**
   * Transform resource to object, that's going to be used as the final output
   */
  public toJSON() {
    for (const key in this.output) {
      // first check if key is disabled
      if (this.isDisabledKey(key)) continue;

      if (!this.isAllowedKey(key)) continue;

      // get value type
      const valueType = this.output[key];

      // now get the value from the given resource data
      const value = get(
        this.resource,
        key,
        get(this.defaults, key, missingKey),
      );

      if (value === missingKey) {
        continue;
      }

      if (Is.empty(value)) continue;

      if (Array.isArray(value)) {
        this.data[key] = value.map(item =>
          this.transformValue(item, valueType),
        );
      } else {
        this.data[key] = this.transformValue(value, valueType);
      }
    }

    return this.data;
  }
  // ...
}
Enter fullscreen mode Exit fullscreen mode

We made two checks here before even getting the value type, the first one is to check if the given key is disabled, if so then we skip the transformation step and go to the next key.

The second one is to check if the given key is allowed, if so then we skip the transformation step and go to the next key.

Please note that i added a new property called data, this is going to be used later to add more features like customizing the final output and adding more complex outputs.

Using Disabled And Allowed Keys

Now let's open our users-list.ts file and we can add the following code

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

import User from "../models/user";
import UserResource from "../resources/user-resource";

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

  UserResource.disable("isPhoneVerified", "isActive");

  return {
    users: UserResource.collect(users),
  };
}
Enter fullscreen mode Exit fullscreen mode

This will disable the isPhoneVerified and isActive keys from being returned in the final output.

🎨 Conclusion

In this article, we learned how to disable and allow keys from being returned in the final output.

☕♨️ Buy me a Coffee ♨️☕

If you enjoy my articles and see it useful to you, you may buy me a coffee, 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

😍 Join our community

Join our community on Discord 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, 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

Packages & Libraries

React Js Packages

Courses (Articles)

💖 💪 🙅 🚩
hassanzohdy
Hasan Zohdy

Posted on December 3, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related