Is it possible for entities to transition between different use cases by means of the controller?

Currently, I am tasked with developing a route for processing ticket purchases for events. My approach involves utilizing a controller to handle incoming requests containing order data, client details, ticket information, and payment specifics. These requests are then delegated to appropriate use cases for execution.

One particular use case involves the creation of an Order entity, necessitating another use case to validate tickets using the Ticket entity. Once validation is successful, the Order is forwarded to the payment use case, resulting in the creation of a Transaction entity within the same controller structure as shown below:

export class CheckoutController implements Controller {

  constructor(
   private createOrder: CreateOrder,
   private makeTicketValidate: MakeTicketValidate,
   private makePayment: MakePayment,
   ){}

  async handle (request: CheckoutController.Request): Promise<HttpResponse> {

     const order: Order = this.createOrder(request)
     
     const isValid: boolean = await this.makeTicketValidate(order)

     if(!isValid) {
       return badRequest()
     }
     
     const transactionId = await this.makePayment(order)

     if(!transactionId) {
       return internalServerError()
     }
    
     return ok({transactionId})
     
  }
}

Although the above setup works seamlessly, I am left questioning its adherence to clean architecture principles. Could passing the Order entity between use cases through the controller be considered a code smell? Should multiple use cases coexist within a single controller, particularly when dealing with a significant amount of data? Would it be beneficial to implement a presenter to manage data transmission between components, or can the controller suffice for sending HTTP responses directly to the frontend?

I genuinely appreciate any insights shared by those knowledgeable on this topic!

To optimize data transfer between use cases, one option under consideration is implementing a data access object specifically for the 'orders' entity. Alternatively, segregating controllers to distribute responsibilities might enhance overall system efficiency.

Answer №1

When handling multiple use cases within a single controller, you are not straying from the principles of Clean Architecture. Another approach could involve invoking only one use case from the controller and then leveraging the second use case within the first one.

In Clean Architecture, it is common for use cases to interact with "request models" and produce "response models". However, there are instances where transferring entities between use cases directly can be a practical choice that remains in alignment with Clean Architecture principles.

A controller serves as an interface between external sources and your application's logic. Therefore, the decision to segregate a controller should primarily hinge on whether you intend to offer a distinct API surface for your application.

Directly returning response models or entities from the controller or presenter is ill-advised as it exposes your application's internal design to external elements (such as web APIs, UI, and tests). This tight coupling between the caller/UI and the application logic can significantly impede future modifications to your application logic, potentially rendering them extremely challenging or even unattainable. Instead, controllers and presenters should function as a protective barrier - also known as an "anti-corruption layer". (for more information, refer to: https://youtu.be/iD4wns3yH44)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

An error occured in angular2: Cannot access the 'title' property of undefined

Here is the code snippet for my custom component: export class MoviedetailComponent implements OnInit { movie:any constructor( private getmovie: GetmovieService, private router: Router, private rout: ActivatedRoute ) { } ngOnInit() { this.r ...

Exploring nested arrays of subdocuments in a query

UPDATE: It is advised not to use the special characters &" in the query. They are meant for updates only. SOLUTION: Thanks to Gibbs correct: const result : any = await mongoose.model('Events').update( { _id: eventId, ...

Combining portions of objects in Angular2

I want to combine two identical type observables in Angular2 and return an observable of the same type in a function. My goal is to: transform this setup: obs1.subscribe(obs => console.log(obs)) (where I receive): { count: 10, array: <some ...

The combination of types in a union allows for incorrect assignments of properties from the individual types involved

I'm struggling to grasp the concept of unions in TypeScript. Can someone explain why the following assignment is considered valid? I believed it would only be acceptable for const a = {a:12}, {a:123,b:23}, or {a:12,b:12,c:123}. type abcd = | { ...

What is the best way to showcase a file edited in Emacs within Atom?

The coding project I'm working on is built with Typescript, but I don't believe that's relevant. I've noticed that Emacs has a unique approach to indentation. According to the documentation, in Text mode and similar major modes, the TAB ...

How to access the audio element in Angular using ViewChild: Can it be treated as an

My goal is to include an audio element inside a component. Initially, I approached this by using traditional methods: $player: HTMLAudioElement; ... ngOnInit() { this.$player = document.getElementById('stream') } However, I wanted to follow T ...

Facing numerous "error TS1005" messages when performing a gulp build due to node_modules/@types/ [prop types] and [react] index.d.ts with SPFx Webpart

I am currently in the process of developing a custom spfx webpart that includes a feature to display link previews. In order to achieve this functionality, I integrated this specific library. However, I encountered some challenges during the implementation ...

Using TypeScript to import npm modules that are scoped but do not have the scope name included

We currently have private NPM packages that are stored in npmjs' private repository. Let's say scope name : @scope private package name: private-package When we install this specific NPM package using npm install @scope/private-package It ge ...

What's the most effective method for transferring data to different components?

How can I efficiently pass a user info object to all low-level components, even if they are grandchildren? Would using @input work or is there another method to achieve this? Here is the code for my root component: constructor(private _state: GlobalSta ...

Set the reactive forms to mark all controls within the form group as dirty

My Angular 6 application has a form with the following example code: export class SampleComponent implements OnInit { form: FormGroup; constructor(private fb: FormBuilder) { } ngOnInit() { this.form = new FormGroup({ firs ...

Utilize MaterialUI's Shadows Type by importing it into your project

In our project, we're using Typescript which is quite particular about the use of any. There's a line of code that goes like this: const shadowArray: any = Array(25).fill('none') which I think was taken from StackOverflow. Everything s ...

Enforcing object keys in Typescript based on object values

I'm looking to design a structure where the keys of an object are based on values from other parts of the object. For example: type AreaChartData = { xAxis: string; yAxis: string; data: { [Key in AreaChartData['xAxis'] | AreaChart ...

Executing docker command using nest.js

My question is related to integrating back-end Nest.js code with a running Cypress.js Docker container, while also having a front-end website. Is there a way for the user's action on the website to trigger a command that communicates with the Docker ...

Set the default requests header in Ionic 3 using data stored in Ionic Storage

This particular issue is related to retrieving a value from local storage. I am trying to set the default header (Authorization token) for all requests, but I can't seem to find a solution that works efficiently. Most of the resources available only e ...

Formatting code in Visual Studio 2017 for TypeScript files

When attempting to format my TypeScript Code using Ctrl+K+D, nothing seems to happen. Strangely, it works fine with all other code files. What could I be doing incorrectly? ...

Invoke a public method in TypeScript

I'm a newcomer to typescript. In my node-express application, I am trying to call a public function. However, I keep encountering an issue where this is always undefined, leading to errors whenever I attempt to call the public function. Below is the s ...

What is the functionality of "classnames" in cases where there are multiple classes sharing the same name?

Currently, I am reviewing some code that utilizes the npm utility classnames found at https://www.npmjs.com/package/classnames. Within the scss file, there are various classes with identical names (small and large), as shown below: .buttonA { &.smal ...

Encountering a Duplicate Types error while working with react, reactdom, and react-redux types simultaneously

I'm currently experimenting with using React-Redux in conjunction with TypeScript. Taking a look at my package.json, here's how it is structured: "dependencies": { "@types/react-dom": "15.5.0", "@types/react": "15.0.4", " ...

How can I retrieve all element attributes in TypeScript using Protractor?

I came across this solution for fetching all attributes using protractor: Get all element attributes using protractor However, I am working with TypeScript and Angular 6 and struggling to implement the above method. This is what I have tried so far: im ...

Generate a random string and return it as a value

I am looking to incorporate JavaScript code into my Angular application. I attempted the following approach: export class MerchantNewComponent extends FormBaseComponent { constructor(private merchantService: MerchantService, private route ...