#Added new properties to Medusa models, but they're not showing up in API responses

92 messages · Page 1 of 1 (latest)

pearl horizon
#

Hey everyone,

We recently added several new properties to our such as ProductCategory and Product. While these new properties are being returned correctly internally, they're not showing up in the API responses when we access routes such as /admin/product-categories and /admin/products.

We're using Medusa v1.8.1, node v18.12.1, and yarn v1.22.19.

We're wondering if we need to adapt something in a validator somewhere to make these new properties show up in the API responses. Any assistance or suggestions would be greatly appreciated.

Thank you!

wild crag
#

I managed to solve this by simply extending the defaultStoreProductCategoryFields in the api request

pearl horizon
#

where would one do that in vanilla routes? ^^

wild crag
#

mhmm I have my own route since I changed some of the behaviour

#

but check this out:

#

You would need to adjust it to ProductCategories obv

pearl horizon
#

Hmm ok i see.. But can i really not just adjust the defaultAdminProductFields?

pearl horizon
#

I don’t really want to create a new route for every legacy function I decide to update the props of

#

Iykwim

stable lagoon
#

you don't have to create a new route, you can extend the existing validator to be accepted by the core route

#

there is discussion that can help you if you search for them on discord

pearl horizon
# stable lagoon there is discussion that can help you if you search for them on discord

I found this post wich seems like its the right fit for me:
https://discord.com/channels/876835651130097704/1071551221959233607

I found the equivalent for create-product (att. 1)

Tho, i am unable to find something similar for the list-products / get-product. (the first one is used by the /products route) (att. 2)

I might have a fundamental thinking mistake but we're also approaching our deadlines for pitching this stack to our customer.

Would you be able to point me into the right direction again? We would greatly appreciate that.

Att. 3 shows what i found in the root of the admin/products/ structure. This seems related based on naming but not really in usage.

#

I also just noticed, that AdminGetProductsParams in att. 2 extends FilterableProductProps. Would that be the appropriate class to extend?

stable lagoon
#

The class ending by Params are for query params validation and the one ending with Req is for the body

pearl horizon
stable lagoon
#

To retrieve your catuom properties from the store product list end points you need to allow them, for that you can create a middleware that set req.includes = { customProp: true } then you can use the classic fields/expand query params

pearl horizon
#

So my issue isn't actually with any validators mentioned above? Do i understand that correctly?

stable lagoon
#

Yes in your case you just need to use the expand and fields, sorry for the consfusion. Though, you can still keep in mind the validators for the create/update aspect if needed

pearl horizon
stable lagoon
#

Like a classic middleware in express you target the route (any route it can be a core route) and you return it as part of your routers in the src/api/index and ut will automatically applied before the core route

pearl horizon
stable lagoon
#

We are doing our beat to provide a nice support 😇 thanks for the compliment

pearl horizon
#

this - f.e. - is a custom route that is directly taking it from the productService.

stable lagoon
#

Have you added to the fields query params? Otherwise it wond be selected, you can pass all the default fields + description_en

pearl horizon
#

I haven't done that, where would i extend / add to the list of query params used to list products?

stable lagoon
#

In the client, when you list the products you can pass the query parameters. I suggest you to have a look in the doc about fields and expand

pearl horizon
stable lagoon
#

By default the end point return some properties and relations, they are defined and don’t changed unless you use fields to specify the properties you want the api to return and expend for the relations

pearl horizon
#

Sadly i don't quite understand what you're referring to.

Where would i find these fields / extend them afterwards?

stable lagoon
#

If you call for example /admin/products?fields=id,created_at,description_en it will return those properties

pearl horizon
#

ohh yes, that works and returns the required field if told so specifically.

Are we able to extend the default set of fields returned? Since otherwise we would have to include them manually in the admin dashboard for every new field we include.

stable lagoon
#

Unfortunately for now you have to take the default fields and add it to the fields as well, but with your middleware you can add it by default to the fields query params while spreading the default fields so that it is managed by your middleware

#

You can import the default from the products/index

pearl horizon
#

i see. Well that'll work for now. Are there any plans on this being extendable? Not a big issue but probably a good qol feature.

stable lagoon
#

There is a plan indeed but it is not the top priority for now

pearl horizon
#

Understandable

Thanks very much for the assistance. Greatly appreaciate and im sure we'll be in touch ❤️

unreal prairie
pearl horizon
# stable lagoon You can look at this about the validator util and how to extend an existing vali...

Another question: When adding this - core routes work perfectly fine again. Tho - custom routes don't anymore. Any idea why this would be the case?

src/api/index.ts

export default () => {
  registerExtendedValidator(AdminPostProductsReq) // When this is present, /hello doesn't work. When its not - it does.

  const router = Router()

  router.get("/hello", (req, res) => {
    res.json({
      message: "Hello!",
    })
  })

  // getAdminRouter(router)
  // getStoreRouter(router)
  // getTestRouter(router)

  return router
}
#

/src/utils/extended-validators/products.ts

import { AdminPostProductsReq as MedusaAdminPostProductsReq } from "@medusajs/medusa";
import { IsOptional, IsString } from "class-validator";

export class AdminPostProductsReq extends MedusaAdminPostProductsReq {
  @IsString()
  @IsOptional()
  description_en: string

  @IsString()
  @IsOptional()
  marketing_text: string

  @IsString()
  @IsOptional()
  marketing_text_en: string
}
stable lagoon
#

or is stuck somewhere

#

you can also do registerExtendedValidator outside of the function

pearl horizon
pearl horizon
#

the registerExtendedValidator is straight taken from the message you sent me.

import { ClassConstructor } from "@medusajs/medusa";
import { ValidatorOptions } from 'class-validator';

const extendedValidators: any = []
let isInitialized = false

export function registerExtendedValidator<T extends ClassConstructor<any>>(classValidator: T): void {
  extendedValidators.push(classValidator)

  if (isInitialized) {
    return
  }

  isInitialized = true

  import('@medusajs/medusa/dist/utils/validator').then(module => {
    const originalValidator = module.validator
    module.validator = <T extends ClassConstructor<any> = any, V = any>(typedClass: T, plain: V, config?: ValidatorOptions): Promise<any> => {
      for (const extendedValidator of extendedValidators) {
        if (extendedValidator.name === typedClass.name) {
          typedClass = extendedValidator
          break
        }
      }
      return originalValidator(typedClass, plain, config)
    }
  })
}
stable lagoon
pearl horizon
# stable lagoon Can you follow the same process as here please https://discord.com/channels/8768...

I have implemented it
But its not logging anything when trying to access a route.

import { ClassConstructor } from "@medusajs/medusa";
import { ValidatorOptions } from 'class-validator';

const extendedValidators: any = []
let isInitialized = false

export function registerExtendedValidator<T extends ClassConstructor<any>>(classValidator: T): void {
  console.log("PRE VAL PUSH");
  extendedValidators.push(classValidator)
  console.log("PRE INIT");

  if (isInitialized) {
    return
  }

  isInitialized = true
  console.log("POST INIT");

  import('@medusajs/medusa/dist/utils/validator').then(module => {
    const originalValidator = module.validator
    module.validator = <T extends ClassConstructor<any> = any, V = any>(
      typedClass: T,
      plain: V,
      config?: ValidatorOptions
    ): Promise<any> => {
      for (const extendedValidator of extendedValidators) {
        console.log("VALIDATOR", extendedValidator.name);
        if (extendedValidator.name === typedClass.name) {
          console.log("MATCHED VALIDATOR", extendedValidator.name);
          typedClass = extendedValidator;
          break;
        }
      }
      return originalValidator(typedClass, plain, config);
    };
  });
}
stable lagoon
#

Have you re build?

pearl horizon
#

yessir

pearl horizon
# stable lagoon Have you re build?

Ignore my linting issues in the dist directory, but this is the built file. Core post request as stated work great with that. But any other custom route doesnt.

stable lagoon
#

what are your server logs?

pearl horizon
#

unfortunately thats all thats being logged

stable lagoon
#

you have the same thing as in the conv I shared you, your path are missing ./ at the bigining, can you add the proper path please

pearl horizon
stable lagoon
#

your import, local files are imported using ../utils/etc and node modules my-module

#

could you also check the api/index in dist

pearl horizon
#

But the src folder is set as the root directory. So these imports should definitely work. I'll add the direct path to the validator

pearl horizon
# stable lagoon could you also check the api/index in dist
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const admin_1 = require("api/routes/admin");
const store_1 = require("api/routes/store");
const test_1 = require("api/routes/test");
const express_1 = require("express");
const register_extended_validator_1 = require("utils/register-extended-validator");
const product_1 = require("utils/validators/product");
exports.default = () => {
    (0, register_extended_validator_1.registerExtendedValidator)(product_1.AdminPostProductsReq);
    const router = (0, express_1.Router)();
    router.get("/hello", (req, res) => {
        res.json({
            message: "Hello!",
        });
    });
    (0, admin_1.getAdminRouter)(router);
    (0, store_1.getStoreRouter)(router);
    (0, test_1.getTestRouter)(router);
    return router;
};
stable lagoon
#

have you re build?

pearl horizon
#

Yes i rebuild on every itteration

stable lagoon
#

that is strange 🤔

pearl horizon
# stable lagoon have you re build?
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const admin_1 = require("api/routes/admin");
const store_1 = require("api/routes/store");
const test_1 = require("api/routes/test");
const express_1 = require("express");
const register_extended_validator_1 = require("../utils/register-extended-validator");
const product_1 = require("../utils/validators/product");
exports.default = () => {
    console.log(`PRE VAL`);
    (0, register_extended_validator_1.registerExtendedValidator)(product_1.AdminPostProductsReq);
    console.log(`POST VAL`);
    const router = (0, express_1.Router)();
    router.get("/hello", (req, res) => {
        res.json({
            message: "Hello!",
        });
    });
    (0, admin_1.getAdminRouter)(router);
    (0, store_1.getStoreRouter)(router);
    (0, test_1.getTestRouter)(router);
    return router;
};
pearl horizon
stable lagoon
#

i you put a log before the util and after it in the api/index, do you get the logs?

#

also, just an advice, you can return an array of routers, so that you don't have to attach everything on the same router if you want

pearl horizon
stable lagoon
#

none of the logs?

pearl horizon
stable lagoon
#

can you screen short your dist structure please

#

also, can you update the path of your api import using ./

pearl horizon
stable lagoon
#

humm looks nice 👍 can you update the path, last thing we will try is to log in the loader catch block as the error might be swallowed

pearl horizon
stable lagoon
#

ahah that is weird 😂

pearl horizon
#

ah damn - wrong screenshot lmao

stable lagoon
#

ca you log the error in node modules/@medusajs/medusa/dist/loaders/plugins.ts in the register api

stable lagoon
pearl horizon
# stable lagoon are you sure the build contains the console?

Im sorry, i've been in a telco.

Yes, this is the built file:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = require("express");
const admin_1 = require("./routes/admin");
const store_1 = require("./routes/store");
const test_1 = require("./routes/test");
exports.default = () => {
    const router = (0, express_1.Router)();
    console.log(`PRE ROUTE`);
    router.get("/hello", (req, res) => {
        res.json({
            message: "Hello!",
        });
    });
    console.log(`POST ROUTE`);
    (0, admin_1.getAdminRouter)(router);
    (0, store_1.getStoreRouter)(router);
    (0, test_1.getTestRouter)(router);
    return router;
};
pearl horizon
# stable lagoon ca you log the error in node modules/@medusajs/medusa/dist/loaders/plugins.ts in...

Don't ask me to explain it, but adding a log into the file you mentioned just got my logs to work.

⠋ Initializing plugins
PRE VAL
PRE VAL PUSH
PRE INIT
POST INIT
POST VAL
PRE ROUTE
POST ROUTE
(node:10183) ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time
✔ Plugins intialized – 814ms
✔ Subscribers initialized – 17ms
✔ API initialized – 61ms
⠙ Initializing defaults
warn:    You don't have any notification provider plugins installed. You may want to add one to your project.
✔ Defaults initialized – 457ms
✔ Indexing event emitted – 8ms
✔ Server is ready on port: 9000 – 9ms
::1 - - [14/Apr/2023:14:44:41 +0000] "GET /hello HTTP/1.1" 304 - "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.39"
info:    Processing SEARCH_INDEX_EVENT which has 1 subscribers
/admin/products/ middleware has been called.
VALIDATOR AdminPostProductsReq
::1 - - [14/Apr/2023:14:44:44 +0000] "GET /admin/products/prod_01GXZXRCK6DZ83HAPEB7DBSDG0 HTTP/1.1" 304 - "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.39"

My custom routes are working again but the validator for the products push route doesn't anymore.

stable lagoon
#

Okay I suggest you to move the registerExtendedValidator into a loader such as

src/loaders/index.ts
export default async function () {
  // here you call the util etc
  await registerExtendedValidator....
}

and
update the utils such as

export async function registerExtendedValidator<T extends ClassConstructor<any>>(classValidator: T): void {
  console.log("PRE VAL PUSH");
  extendedValidators.push(classValidator)
  console.log("PRE INIT");

  if (isInitialized) {
    return
  }

  isInitialized = true
  console.log("POST INIT");

    const module.= await import('@medusajs/medusa/dist/utils/validator')
    const originalValidator = module.validator
    module.validator = <T extends ClassConstructor<any> = any, V = any>(
      typedClass: T,
      plain: V,
      config?: ValidatorOptions
    ): Promise<any> => {
      for (const extendedValidator of extendedValidators) {
        console.log("VALIDATOR", extendedValidator.name);
        if (extendedValidator.name === typedClass.name) {
          console.log("MATCHED VALIDATOR", extendedValidator.name);
          typedClass = extendedValidator;
          break;
        }
      }
      return originalValidator(typedClass, plain, config);
    };
}
#

can you try that please

#

it will be better located plus you will be able to await it and it will not interfer with your router

pearl horizon
#

on it!

#

Alright, Validator and custom routes are running as intended. Tho, post requests where the validator is supposed to get extended are not.

pearl horizon
#

Well, everything seems to be working now! I must admit this stufferoo gets really confusing.. Especially without an extensive documentation about all of this.

However as always we appreciate your support!