What are the steps to integrating a repository into the clean architecture design pattern?

I have been following Uncle Bob's clean architecture principles in developing my medical application's API. However, I am facing some challenges in determining where certain components should be implemented.

Within my application layer, I have a CreateTreatmentPlanUseCase which injects two repositories: AbstractPatientRepo and AbstractTreatmentPlanRepo.

export class CreateTreatmentPlanUseCase implements UseCase<CreateTreatmentPlanRequestDto, Promise<Response>> {
    protected patientRepository: AbstractPatientRepository
    protected treatmentPlanRepository: AbstractTreatmentPlanRepository

    constructor(
        patientRepository: AbstractPatientRepository,
        treatmentPlanRepository: AbstractTreatmentPlanRepository
    ) {
        this.patientRepository = patientRepository
        this.treatmentPlanRepository = treatmentPlanRepository
    }
}

In my interface adapters layer, I have a controller located in the web directory.

export default class CreateTreatmentPlanController {
    protected useCase: CreateTreatmentPlanUseCase

    constructor(useCase: CreateTreatmentPlanUseCase) {
        this.useCase = useCase
    }

    public async execute(req: express.Request, res: express.Response) {
        const dto = <CreateTreatmentPlanRequestDto>req.body

        const treatmentPlanOrError = await this.useCase.execute(dto)

        if (treatmentPlanOrError.isFailure()) {

        }
    }
}

My question is, where should I instantiate the CreateTreatmentPlanUseCase and CreateTreatmentPlanController? Should this be done in the interface adapters layer or in the frameworks/infrastructure layer?

  1. Where is the appropriate place to instantiate the CreateTreatmentPlanUseCase and CreateTreatmentPlanController? Is it in the interface adapters layer or the frameworks/infrastructure layer?

Answer №1

I'm a bit confused about where to place the CreateTreatmentPlanUseCase and CreateTreatmentPlanController. Should they be in the interface adapters layer or in the frameworks/ infrastructure layer?

It's recommended to place them in the infrastructure layer. Since you're working with JavaScript, specifically TypeScript, you can create a js module to set up the use cases. This module can then import the necessary use case definition module(s).

For example, you can create a module called usecases.js, or usecases.ts in your case. Within this module, you'll import the required modules like this:

import { CreateTreatmentPlanUseCase } from 'CreateTreatmentPlanUseCase'
import { PatientRepositoryImpl } from 'PatientRepositoryImpl'
import { TreatmentPlanRepositoryImpl } from 'TreatmentPlanRepositoryImpl'

Then, you can set up your use case like so:

const patientRepository = new PatientRepositoryImpl();
const treatmentRepository = new TreatmentPlanRepositoryImpl();

export const createTreatmentPlanUseCase = new CreateTreatmentPlanUseCase(
                                            patientRepository,
                                            treatmentRepository
                                            );

Once you have a module for the setup, you can import it in your controller module:

import { createTreatmentPlanUseCase } from 'usecases' 

You may organize your modules differently, but the main concept remains the same. It's common practice to separate the setup from the definition in JavaScript for better code organization and maintainability.

EDIT

Currently, my use-cases are in the application layer and controllers in the adapters layer. I am also creating repository implementations in the adapters layer. Is this the right approach or should the repository implementations go in the infrastructure/database layer?

It's acceptable to have them in the adapter layer. However, instead of creating a directory named adapters and placing all controllers and repositories there, consider creating separate directories for controllers and repositories. A more organized approach would be to create feature-specific directories with modules named repository.ts, controller.ts, and usecase.ts.

 +- package.json
 |
 +- treatments
    |
    +- create
       |
       +- usecase.ts
       |
       +- repository.ts
       |
       +- controller.ts

This structure provides better clarity and focuses on features rather than technical details like the adapters layer.

Should I have a controllers directory with a folder per use-case, import the repos there, construct the use case, and pass that to the controller?

That approach is fine, especially if your controllers are use-case oriented. It promotes encapsulation, as other modules won't be able to access the use cases unless explicitly exported. It aligns with the concept of package by feature, as discussed in the clean architecture principles.

In a similar scenario, your directory structure could look like this:

 +- package.json
 |
 +- treatments
    |
    +- create.ts // use cases, repositories, controllers, etc.

EDIT

If I adopt the package by feature approach and need to reference PatientRepository, is it okay to import the interface from the Patient directory/package?

While you can do this, it's often beneficial to follow the interface segregation principle and create repositories that are feature-driven. For instance, if you have a use case called CreateTreatmentPlanUseCase, consider creating a repository named CreateTreatmentPlanRepository specific to that use case. This approach may lead to some duplicated code but results in decoupled and more focused use case repositories.

Alternatively, you can create a common repository module shared by multiple use case repositories. This ensures that common methods are explicitly defined and prevents accidental changes that only apply to one use case. Ultimately, it's your decision to choose the best approach and be willing to refactor when necessary.

Answer №2

Within the realm of Clean Architecture, the crucial task of structuring the application occurs within the confines of the "main component." It is at this juncture that we intricately link together all the finer details and implement dependency injection.

One may regard this component as a pivotal part of the infrastructure layer or even as the outermost layer within the overall architectural framework. Some proponents even advocate for the creation of a dedicated project solely for this purpose: https://medium.com/@gsferreira/the-missing-project-that-fixes-everything-in-net-5ca5ba35c6ae

In the context of a CLI program, this component would likely serve as the primary entry point, whereas in a web application, it would typically entail configuring the web framework, such as "Startup.cs" in Asp.Net.

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

This error occurs when trying to assign a value to a property of a variable that is currently undefined

Having some issues with assigning the latitude and longitude values to a variable in my code. I am able to retrieve them correctly, but when trying to use them in another method (onUpload()), I am facing some errors. export class latlonComponent implement ...

how can I convert div attributes into JSON format

I am working with the following div element: <div class="specialbreak"> This div has been saved in a JavaScript variable. My goal is to convert this div into JSON format so that I can easily access the class name. Although I attempted to use JSON ...

Switching effortlessly between Fixed and Relative positioning

As I work on creating a unique scrolling experience, I aim to have elements stop at specific points and animate before returning to normal scroll behavior once the user reaches the final point of the page. Essentially, when div X reaches the middle of the ...

Tips for passing a function and an object to a functional component in React

I am struggling with TypeScript and React, so please provide clear instructions. Thank you in advance for your help! My current challenge involves passing both a function and an object to a component. Let's take a look at my component called WordIte ...

The InMemoryCache feature of Apollo quietly discards data associated with fragments that are declared on the main

After sending the following query to my GraphQL server: fragment B on root_query { foo { id } } query A { ...B } The data received from the server includes the foo field. However, when I retrieve it using Apollo's InMemoryCache a ...

Converting floating point numbers to fixed floating point numbers in JavaScript

Consider this scenario: I need to calculate 3 divided by 6, which equals 0.5 as a floating number. However, when I used the javascript toFixed(6) method to round it to 6 decimal points, it returned '0.500000' as a string instead of a floating num ...

Using CSS to position elements absolutely while also adjusting the width of the div

In one section of my website, I have a specific div structure. This structure consists of two divs stacked on top of each other. The first div is divided into two parts: one part with a width of 63% and another part with a button. Beneath the first div, t ...

Typescript - Certain implementations may eliminate the optionality of properties

After exploring multiple versions of the Omit implementation, including the one displayed by Intellisense when hovering over Omit, I'm struggling to grasp why certain implementations are homomorphic while others are not. Through my investigation, I&a ...

The message sent back by Django Rest Framework is: "a legitimate integer must be provided"

I have integrated a react form within my Django application, supported by the rest framework in the backend. When I submit the form without entering any value in the integer field, I encounter the following error message from the rest API: "a valid integer ...

Viewing HTML web pages using Mozilla Firebox

Printing an HTML table with lots of content has been a challenge for me. Google Chrome didn't work, so I switched to Mozilla Firefox. However, now Firefox is breaking the page inside the table. My question is how can I trigger print preview in Firefox ...

Utilizing a plugin to execute a function in Wordpress

I'm currently facing the challenge of combining two WordPress plugins without the need to modify one to fit into the other seamlessly. My main question is: How can I call a function from one plugin that exists outside of another plugin? For example, ...

Displaying numbers individually with commas in a Django template

I am facing an issue where the number being typed into a text field does not have commas separating the thousands For example, if the user types 500000, it displays as 500000 instead of 500,000 This issue is present in the models section of the code: so_ ...

What Are the Possible Use Cases for Template Engine in Angular 2?

For the development of a large single page application (SPA) with Angular 2.0, I have decided to utilize a template engine like JADE/PUG in order to enhance clarity and clean up the code. My goal is to achieve optimal performance for the application. Th ...

Troubleshooting: Issue with Vue-Router failing to load component

I have been in the process of developing a website using Vue and Vue-Router locally. Upon completion, I push my changes with git to the production server which updates the site files. Recently, I encountered an issue with a payment status page that is wor ...

"Enhancing Collaboration with NextJs Multi-Zones' Unified Header

Currently, I have two applications named admin-shell and delivery-management, both of which are being managed using Multi Zones in NextJs. These applications share a common header with navigation links, but I am encountering difficulties navigating betwee ...

Exploring multiple states within an interval function in React Native

I'm struggling to find the right words for this question. I've encountered an issue where I need to constantly check and update a complex state object within an interval loop in my program. To simplify, let's say it consists of just a counte ...

Which specific web framework supports the functionalities of Microsoft Dynamics CRM 2011?

Is there an SDK available from Microsoft that can help me create a web product with similar rich ajax features as Microsoft Dynamics CRM 2011? I have considered using Microsoft SharePoint Foundation 2010, but I am concerned that it is designed for small o ...

Issue with ngx-bootstrap custom typeahead feature malfunctioning

I'm facing an issue while trying to develop a customized typeahead feature that is supposed to search my API every time the user inputs something, but it's not functioning as expected. The autocomplete() function isn't even getting accessed. ...

Having trouble reading the length property of undefined in Angular 7

Seeking to obtain a picture link of the object. The objects are stored in an array and the typescript method looks like this: getMealPicture(orderLineMeal: OrderLine): string { for (let meal of this.meals) { if (meal.id === orderLineMeal.mealId) ...

Can a different div or HTML element be used in place of the text "Hello World"?

<body onload="myfunction('target')"><div id="target"> "Hey there!" </div></body> Can we replace the text "Hey there!" with another HTML element or div? This is currently a left-to-right marquee text. <script language= ...