#zod Error type extending Module / Endpoint in V2

1 messages · Page 1 of 1 (latest)

jaunty geyser
#

Been trying for hours now, I cannot get the endpoint to create a customer extended:

  1. I am just trying to add the field "company" to the customer creation endpoint.
  2. I send a request from the signup from from the nextjs Starter and attach a "company" key in the formdata. I then POST this to the store/customers endpoint when creating the customer:
server:dev: error:   Invalid request: Unrecognized fields: 'company'
server:dev: MedusaError: Invalid request: Unrecognized fields: 'company'
server:dev:     at zodValidator (/node_modules/@medusajs/medusa/src/api/utils/zod-helper.ts:126:13)
server:dev:     at processTicksAndRejections (node:internal/process/task_queues:95:5)
server:dev:     at async validateBody (node_modules/@medusajs/medusa/src/api/utils/validate-body.ts:30:27) {
server:dev:   __isMedusaError: true,
server:dev:   type: 'invalid_data',
server:dev:   code: undefined,
server:dev:   date: 2024-09-23T09:57:39.506
server:dev: }
server:dev: ::1 - - [23/Sep/2024:09:57:39 +0000] "POST /store/customers HTTP/1.1" 400 95 "-" "node"

I adjusted my middleware to allow for this field:

import { defineMiddlewares } from "@medusajs/medusa";
import { z } from "zod";

export default defineMiddlewares({
  routes: [
    {
      matcher: "/store/customers",
      method: ["POST"],
      additionalDataValidator: {
        company: z.string().optional(),
      },
    },
  ],
});

I just cant make sense of it and the docs are not really helpful to be honest... Does anyone know what I am doing wrong? My #1 thought is that the matcher does not match correctly on the route / a different route is actually affected.

outer patio
jaunty geyser
#

I did indeed not do that but now I need to extend all types by additional_data?
Typescript complains now when I call e.g.:

    const { customer: createdCustomer } = await sdk.store.customer.create(
      { ...customerForm, additional_data: {xyz: "ACME"} },
      {},
      customHeaders
    )

saying that additional_data does not exist on type StoreCreateCustomer...?

What would be the newly proposed way to extend types then? Afais I would have to extend the HttpTypes.StoreCreateCustomer type somewhere.

#
server:dev: error:   Invalid request: Unrecognized fields: 'additional_data'
server:dev: MedusaError: Invalid request: Unrecognized fields: 'additional_data'
server:dev:     at zodValidator (node_modules/@medusajs/medusa/src/api/utils/zod-helper.ts:126:13)
server:dev:     at processTicksAndRejections (node:internal/process/task_queues:95:5)
server:dev:     at async validateBody (node_modules/@medusajs/medusa/src/api/utils/validate-body.ts:30:27) {
server:dev:   __isMedusaError: true,
server:dev:   type: 'invalid_data',
server:dev:   code: undefined,
server:dev:   date: 2024-09-23T12:45:59.817Z
server:dev: }
server:dev: ::1 - - [23/Sep/2024:12:45:59 +0000] "POST /store/customers HTTP/1.1" 400 112 "-" "node"

Mhmm this does not seem to work quite yet

#

This is the payload:

{
store:dev: first_name: 'X',
store:dev: last_name: 'Y',
store:dev: email: '[email protected]',
store:dev: phone: '+1791234987',
store:dev: additional_data: { company: 'ACME' }
}

jaunty geyser
#

I'd really appreciate some help here as it is blocking us. The docs are rather non-expressive here.

I Post to my endpoint /store/customers and have the following body:

[{
  "company_name": "",
  "first_name": "John",
  "last_name": "Doe",
  "email": "[email protected]",
  "phone": "+1234567890",
  "password": "password123",
  "additional_data": {
    "salutation": "male"
  }
}]

I then get this error on the server validator:

error: Invalid request: Unrecognized fields: 'additional_data'
MedusaError: Invalid request: Unrecognized fields: 'additional_data'
    at zodValidator (/path/to/node_modules/@medusajs/medusa/src/api/utils/zod-helper.ts:126:13)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async validateBody (/path/to/node_modules/@medusajs/medusa/src/api/utils/validate-body.ts:30:27) {
  __isMedusaError: true,
  type: 'invalid_data',
  code: undefined,
  date: 2024-09-30T09:37:34.678Z
}
::1 - - [30/Sep/2024:09:37:34 +0000] "POST /store/customers HTTP/1.1" 400 91 "-" "node"

This is my middleware to extent the endpoint /store/customers:

import { defineMiddlewares } from "@medusajs/medusa";
import { z } from "zod";

export default defineMiddlewares({
  routes: [
    {
      matcher: "/store/customers",
      method: ["POST"],
      additionalDataValidator: {
        salutation: z.enum(["male", "female", "company"]),
      },
    },
  ],
});

What am I missing here? Thanks for any help here!

jaunty geyser
#

I looked into this a bit further:

  1. Looking at the middleware the store/customers endpoint is validated via the StoreCreateCustomer (found here: https://github.com/medusajs/medusa/blob/develop/packages/medusa/src/api/store/customers/validators.ts#L7C14-L7C33)

  2. This is where the config is happening: https://github.com/medusajs/medusa/blob/develop/packages/medusa/src/api/store/customers/middlewares.ts#L26

  3. However, StoreCreateCustomer is NOT a function afaik but a ZodObject. Hence, this line here in the validate-body middleware would not be called, hence the zodSchema would not be extended by the requests additionalDataValidator:

 try {
      let schema: z.ZodObject<any, any> | z.ZodEffects<any, any>
      if (typeof zodSchema === "function") {
        schema = zodSchema(req.additionalDataValidator)
      } else {
        schema = zodSchema
      }

      req.validatedBody = await zodValidator(schema, req.body)
      next()
    } catch (e) {
      next(e)
    }
  }

from here:
https://github.com/medusajs/medusa/blob/develop/packages/medusa/src/api/utils/validate-body.ts#L22C4-L35C4

Can anyone confirm this as the root issue? I am not super deep in the V2 code so I might be overseeing a basic here....

GitHub

Building blocks for digital commerce. Contribute to medusajs/medusa development by creating an account on GitHub.

GitHub

Building blocks for digital commerce. Contribute to medusajs/medusa development by creating an account on GitHub.

GitHub

Building blocks for digital commerce. Contribute to medusajs/medusa development by creating an account on GitHub.

jaunty geyser
#

Same goes for metadata - cannot parse it upon customer creation. THis seems very odd that it is not part of the accpeted type...

jaunty geyser
#

Can anyone from the Medusa team support here or share a sample repo where an extension is done successfully incl updates and reads from endpoints incl the custom module that extends a core module? I have tried everything but I simply cannot wrap my head around the issue

spark halo
#

Running into similar issues right now, can anyone support here?

severe herald
#

import { validateAndTransformBody} from "@medusajs/medusa/api/utils/validate-body"

#

try like that

jaunty geyser
#

thanks! But we are trying to add additional fields not part of the original type

#

Or do you mean the validateandTransform body accepts an additional_data object?

jaunty geyser
severe herald
#

it's strange

jaunty geyser
#

But am I the only one trying to extend a model and pass additional data or am I the only one not getting how its done 🤣?

jaunty geyser
#

Ok I’m taking this to GitHub now i guess. How come no one else has this issue / is extending core modules? It’s odd to me

jaunty geyser
swift epoch
#

I have the same / similar issue. I've extended Product module with additional properties which are optional in the middleware but even with that I can't create a product right now because validator complains that additional_data are required. I assume it's because additionalDataValidator in middleware has type ZodRawShape and the validator expect there will be always additional_data and it cannot be marked as partial.

jaunty geyser
#

Thanks for pointing that out. I looked through the Medusa core code and I also think it’s an actual bug

#

While the additional_data bug should be fixed fairly easy, my much bigger concern is how I can attach the extended module to each call to the module without having to override every single endpoint in the core module.

swift epoch
#

I haven't tried it yet but I think you should be able to get extended module by adding another middleware but with GET method and you can define middleware to request extended data. Using example from the docs I think it could be done like this:

  routes: [
    {
      matcher: "/admin/products",
      method: ["GET"],
      middlewares: [
        async (req, res, next) => {
          const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)

          const {
            data: [product],
          } = await query.graph({
            entity: "product",
            fields: ["brand.*"],
            filters: {
              id: req.params.id,
            },
          })

          res.json({ brand: product.brand })
        },
      ],
    },
  ],
})

but as I said, I haven't tried it yet so I don't know if it's really gonna to work 🙂

#

still you have to add some logic to every endpoint you need to extend but at least you don't have to override the core module

jaunty geyser
#

Thanks looks interesting! Unless I can pass the additional data I am not getting to the second part yet though 😂

jaunty geyser
#

So I think the problem is that the store API routes do not have a WithAdditionalData() wrapper around the exported types... I do not have the local medusa set up right now, so I cannot really make a pull req. Can anyone from Medusa confirm? E.g. here, this should be wrapped so that it is:

export const StoreUpdateCustomerAddress = WithAdditionalData(StoreCreateCustomerAddress)

Or is the issue even further down?

https://github.com/medusajs/medusa/blob/develop/packages/medusa/src/api/store/customers/validators.ts#L32

GitHub

Building blocks for digital commerce. Contribute to medusajs/medusa development by creating an account on GitHub.

kindred lichen
#

hey, i've got a side question (since it's been hard to get an answer from someone but you might've crossed this road already) - I see you are getting the product by id along with its brand, do you know if would possible to add a filter on the brand? for example, get the product by id and its brand if it matches a criteria. I've run into this issue where I need to filter data on another module but the lack of documentation is driving me crazy 😄

jaunty geyser
#

I think in the docs it says that’s not possible for now. But might be mistake.

kindred lichen
#

that's a huge limitation then, do you know any workaround?

jaunty geyser
#

No don’t know. Can you open another thread for this? Don’t want to mix up the topics here. Thanks 😄

#

Ah saw you just did

jaunty geyser
jaunty geyser
#

As I said: I think it’s just about extending the Store API types to accept the additional data. For someone from the Medusa team with a proper local setup this should be done in 20 minutes I believe 😅 thanks for getting involved @supple orbit

paper saddle
#

hi @supple orbit - thank you for your nice words - I am not a part of Medusa team so I cannot help here directly 🙂 I am not sure guys if you need help with the analysis - it is quite long thread and hard for me to catch up

jaunty geyser
harsh gorge
#

Same problem here.

harsh gorge
#

I was able to solve this issue locally for me by following steps in (https://docs.medusajs.com/development/fundamentals/local-development)

Than I change the validators.ts to accept nulish value.

diff --git a/packages/medusa/src/api/utils/validators.ts b/packages/medusa/src/api/utils/validators.ts
index c3aff0abb0..4626432021 100644
--- a/packages/medusa/src/api/utils/validators.ts
+++ b/packages/medusa/src/api/utils/validators.ts
@@ -17,7 +17,7 @@ export const WithAdditionalData = <T extends ZodObject<any, any>>(
       })
     } else {
       schema = originalSchema.extend({
-        additional_data: additionalDataValidator,
+        additional_data: additionalDataValidator.nullish(),
       })
     }

And then
medusa-dev -s --packages@medusajs/medusa

Learn how to perform local development in the Medusa monorepo. This includes how to use the dev CLI tool and perform unit, integration, and plugin tests.

jaunty geyser
#

Ok good to know there is actually a bug. Was doubting my sanity especially after Kasper confirmed everything is in place. Will try to use your workaround for now. Thanks!

harsh gorge
#

@jaunty geyser I think my problem is not the same as yours.

I'm extending the admin/products route.
I added the additionalDataValidator src/api/middlewares.ts

When I'm try to create a new Product in Admin UI the admin/products route throws similar exception because the Admin Ui is not sending additional_data

jaunty geyser
#

Ah ok. Haven’t checked in detail yet

#

I think the whole extending endpoints logic is not consistently applied to all endpoints yet. I see a lot of DMs of people asking me if I solved this since they are having the same issue

harsh gorge
#

I'm studying medusa v2 since last week.

Some examples in docs causes problems in Admin UI. This patch is only to fix my issues and continue studing

Currently I'm not working on a real project.

jaunty geyser
#

Ok I kind of gave up 😂 no one reacting from Medusa also not on git (qn has 8 upvotes now so seems to be a common problem)

kind quartz
#

Hi @jaunty geyser , i you still have the problem, extend core module seems to works in V2.2, i just followed the doc from https://docs.medusajs.com/learn/customization/custom-features/module to https://docs.medusajs.com/learn/customization/extend-features/query-linked-records and i was able to see the extended attributes when requesting a product via the api

thorn creek
#

i Have exactly the same probleme with the store/customer
i try to add aditional data field

#

im scared when i see all the thread and no solution 💀

#

the admin/customers accept additional data and i can do what i want with that 🆗

#

but the store/customer doesnt accept addional data

thorn creek
#

I finally solve this pb ..
on the storeFront api, you cant add field additional_data

#

but there is a field named metadata by default

#

u can pass any bonus information
metadata: {
favorite_color: "blue",
newsletter_subscription: true,
referral_source: "social_media"
}

faint bridge
#

Did anyone find a solution for this issue?