Extend the Product Service
Build your own marketplace from scratch using Medusa
Now that our vendors have access to their store, I can tell they are getting bored. Indeed, without any things to sell, our back office is useless, therefore we’re spending this time expanding the product concept and adding a decent bit of customization.
What is the goal here ?
The benefit of this section of the tutorial is that it allows you to apply everything you’ve learned in prior sections.
First, we will:
-
Create a new file in the
models
folder, that will extend the core entity with new properties -
Create a new migration using the TypeORM CLI
-
Create a new file in the
services
folder that will initially only include our basic changes (LIFE_TIME
,this.loggedInUser_
…)
Once these steps are completed, we’ll get down to the essential of adding these features :
-
Create a product related to a vendor
-
List the products of a vendor
Extend the Product entity
Here is where we define the new schema for the product table. In fact, we want to associate a Product
with a Store
, therefore we use the same reasoning as the User
table we extended earlier
A relationship with the Store
implies an update of the previously extended Store
model
Create a Migration
Once the preceding parts are completed, we may create a migration to notify the database of certain changes; the command is as follows
Once the migration file has been created, we can update the up
and down
functions like this :
Perfect, now we can run build our server and run the migrations, after that, the database we should see the new column in the Product
table
Adding new features
Create a Product for a Store
To create a Product
tied to a Store
, we’ll start by extending the ProductService
and overriding the create
function to force the logged-in user’s store_id
into the product before inserting it. However, you will see type problems with the input type expected on the method, therefore we will need to expand the type to add our new store_id
property
Okay, at our level here, we can be sure that a User
who is logged in AND has a store_id
must be able to create a product for its store.
On the other hand, when a User
wants to retrieve products, there are currently no constraints preventing him from seeing ONLY its store’s products, let’s implement this feature.
List Products for a Store
ProductService.listAndCount is the function that retrieves products used in the back-office, therefore we’ll alter it to include the logged-in user’s store_id
to retrieve only his products. However, the selector of this function does not know the store_id
property at all, so we will expand the selector to make it aware of that new property
You can now try it on the Admin UI or directly with the API, and you should get the behavior expected.
You can also override others method like ProductService.retrieve
, ProductService.update
and more, depending on your needs
Common Issues
A product handle must be unique
The product.handle
might create an issue in the long term when creating a product for a store, as it’s supposed to be unique. You can for example either add a prefix or suffix containing the store_id
to avoid any problems :
I want to retrieve products from a specific store only from my storefront
For that you’ll need to create a loader, that will extend the default /store/products
relations and allowed fields.
First you’ll need to create a new loader in the /src/loaders/
directory :
Then we’ll extend the validators of the /store/products
API route, the goal here is to be able to add a query parameter /store/products?store_id=<STORE_ID>
, and the default Medusa validator for that API is not aware of the new property we wants to add.
Next step, is to create a file in the /src/api/
folder, named specifically index.ts
.
Now you can successfully retrieve all products from a specific store like this.
The URL is just an example, replace by your own backend URL.
I have TypeScript errors !
In the same way that we have notified the database of new changes thanks to migrations, we will have to do the same with our packages, which are not aware of new properties.
Remember to declare your types according to your needs. In our case, we only need the following types :
GitHub Branch
You can access the complete part’s code here.
Next Steps
We now have the foundation; vendors can access the admin UI and create/list products associated with their store; in the next phase, we will extend entities to allow each store to create its own shipping options.
Was this page helpful?