Services | Medusa Development Course
By Viktor Holik
By Viktor Holik
Welcome to our Medusa Development Course! In this series, you'll learn how to get your development environment ready and take your first steps in building a Medusa-powered e-commerce application. We'll walk you through everything step by step, helping you master Medusa’s modular architecture and build the key features you need.
This course was made by Viktor Holik, our Software Engineer and Medusa Expert.
In this episode, we’ll go through improving Medusa’s SupplierService by making a few updates, like adding transaction support, handling configurations, and adjusting the service’s behavior. We’ll also look at how to set up service lifetimes and how to extend existing services in Medusa, which is helpful when you need to add your own logic.
You can find the transcription of the guide below.
Let's refactor the SupplierService a bit. I'll remove the console logs that we have left on the previous chapter.
You have already seen the usage of build query in the previous chapters, so also I forget about adding and using build query in the retrieve method, so let's fix that. As a selector, I will only add ID in the object, and also let's fix the argument of find one method.
The next thing I want to improve is the update method in the service. So I will add a new variable called update, and I will use object.assign method to assign new values to the previous supplier properties. And I will pass this update object in the save method.
Also, I want to add transactions on this method, so I should use this.atomicPhase function in order to do that. And it takes a callback with the manager as an argument, and instead of using this.active manager, I should use just manager from that callback. Also, let's return a result of this transaction.
Also I should do the same with the create and delete, so I will just copy that first line and insert it in the create method. Also let's not forget about changing the manager.
The next thing you might need in your services is config module. So I will create a new property in the supplier service called ConfigModule underscore, and I will add a typing of ConfigModule from Medusa package. And what you should do is assign this ConfigModule underscore from the dependency container, and also let's not forget about adding right typings.
This ConfigModule is a reference of a config that you have in the Medusa config.js file. It is helpful when you want to return some configurations of the backend, like GVT Secret for example.
As we have added the transaction to the services, we should actually use the transactions in the route handlers. In order to do that we should resolve the manager from the dependency container. Let's also add entity manager type from typeorm package as a generic. And now you can use manager.transaction function, and also you should use the supplier service with transaction function to attach a transaction manager to your method.
You might have a situation when you first create something and then update it, but some error occurred in the update method. So when using a transaction, the creation method actually rollbacks and you don't have a new record in the database. I actually not using this, so I will just return the result of create method. Also I should do the same with the deletion and the updating of a record, so I will do the same in this both route handlers. Now besides achieving the supplier, I could also attach a relations of products and not only return just supplier values, but also return the products of that particular supplier.
Now I want to talk about the service lifetimes in the details. So, the first service lifetime is a single tone, and so every time you resolve a service that is single tone, you get the same instance. When there is lifetime scope to use, a new instance of a service is created and reused in the scope of the dependency container. And the last one is transient, which creates a new instance of a service on every resolve. You can change the lifetime of a service using the static property lifetime, and also you should pass the lifetime value from the package avilix.
As Medusa is a commerce engine that has commerce modules, and all of that modules have their services the whole use you can see the query repository of Medusa. For example, our service comes with the logic behind the authentication of a user and a customer, card service contains the logic behind the card.
And so you might have situation when you want to overwrite or extend some existing logic of that service. I should create a new file that should be the same as the service name in a Medusa repository, in my case it would be product service, and this service should be extended from the Medusa product service. Also, let's not forget about importing this Medusa product service. As Medusa default services have lifetime of singletone, I would change their lifetime to be scoped.
Now I should add constructor method, and as argument take the container, and pass that container to the super Medusa product service class. And also let's not forget about default exporting their product service. If you would open the product service type definition, you would see the whole list of the methods of the service, their parameter sets, and the return types.
Now I want to overwrite the retrieve method and change the logic to be "if the product is not published, then return 404 status, that means the product is not found." If you're overwriting the existing methods of the services, you should be aware that it could have negative effects, such as bugs. In our case, it would generate a bug in the admin panel. So when I go to the draft product from the product list, I would get 404 status, and I would not be able to change product.
If you want to see the full services reference in the Medusa, in a more friendly way, you should definitely check out the services reference from the Medusa docs.
With these updates, your SupplierService is now set up. Using transactions, accessing configuration settings, and adjusting service lifetimes allows for more control and reduces the chance of errors.
In the next chapter, we will understand Medusa's data loading processes and how to efficiently initialize your application.
We hope you found Viktor's tutorial insightful and helpful.
Welcome to our Medusa Development Course! Build the user interface for managing suppliers and updating product suppliers in Medusa’s admin panel.
Welcome to our Medusa Development Course! Create and customize subscribers to respond to key events, like sending an email when an order is placed.