Skip to main content

Пример реализации фичи(post запрос)

1. Типизация данных

Файл: src/domain/user/interface/entities/index.ts

interface IUserEntities {
name: string
email: string
avatar_url: string
}

export type {IUserEntities}

Вынесли в сущность, чтоб избавиться от дублирования кода в port и в dto

Файл: src/domain/specialities/interface/dto/index.ts

import type {IBaseGetPaginationDto} from '@/domain/common/interface'
import type {IUserEntities} from '../entities'

interface IBaseUserDto extends IUserEntities {
id: string
}

type IUserArrayDto = Array<IBaseUserDto>

type IGetAllUserDto = IBaseGetPaginationDto<IUserArrayDto>
type ICreateUserDto = IBaseUserDto

export type {IBaseUserDto, IGetAllUserDto, ICreateUserDto}

2. Контракт порта

Файл: src/domain/user/interface/port/index.ts

import type {IBasePaginationPort} from '@/domain/common/interface'
import type {IUserEntities} from '@/domain/user/interface/entities'

type IGetAllUserPort = IBasePaginationPort
type ICreateUserPort = IUserEntities

export type {IGetAllUserPort, ICreateUserPort}


3. Контракт репозитория

Файл: src/domain/user/interface/repository/index.ts

import type {ICreateUserDto, IGetAllUserDto} from '../dto'
import type {ICreateUserPort, IGetAllUserPort} from '../port'

interface IUserRepository {
getAll: (port: IGetAllUserPort) => Promise<IGetAllUserDto>
create: (port: ICreateUserPort) => Promise<ICreateUserDto>
}

export type {IUserRepository}

4. Контракт use-case

Файл: src/domain/user/interface/use-case/index.ts

import type {IUseCase} from '@/domain/common/http/use-case'
import type {ICreateUserDto, IGetAllUserDto} from '../dto'
import type {ICreateUserPort, IGetAllUserPort} from '../port'

type IGetAllUsersUseCase = IUseCase<IGetAllUserPort, IGetAllUserDto>
type ICreateUsersUseCase = IUseCase<ICreateUserPort, ICreateUserDto>

export type {IGetAllUsersUseCase, ICreateUsersUseCase}

5. Реализация use-case

Файл: src/domain/user/use-case/get-all/index.ts

import type {ICreateUserDto} from '@/domain/user/interface/dto'

import type {ICreateUsersUseCase} from '@/domain/user/interface/use-case'

import type {ICreateUserPort} from '@/domain/user/interface/port'

import {BaseUsersUseCase} from '@/domain/user/common/use-case'

class CreateUsersUseCase extends BaseUsersUseCase implements ICreateUsersUseCase {
public async execute(port: ICreateUserPort): Promise<ICreateUserDto> {
return this._repository.create(port)
}
}

export {CreateUsersUseCase}

Файл: src/domain/user/common/use-case/index.ts

import type {IUserRepository} from '@/domain/user/interface/repository'

class BaseUsersUseCase {
protected readonly _repository: IUserRepository

constructor(UsersRepository: IUserRepository) {
this._repository = UsersRepository
}
}

export {BaseUsersUseCase}

BaseUsersUseCase уменьшает дублирование кода и позволяет переиспользовать репозиторий для других use-case.


6. Слой Data (FAKE API)

Файл: src/data/repository/user/index.ts

import {times} from 'es-toolkit/compat'

import {random} from 'es-toolkit'

import {HUNDRED, TEN} from '@/app/common/const'

import type {IBaseHttpService} from '@/data/repository/common'


import type {ICreateUserDto, IGetAllUserDto} from '@/domain/user/interface/dto'
import type {IUserRepository} from '@/domain/user/interface/repository'
import type {ICreateUserPort, IGetAllUserPort} from '@/domain/user/interface/port'

import {BaseRepository} from '@/data/repository/common'

class UserRepository extends BaseRepository implements IUserRepository {
constructor(httpService: IBaseHttpService) {
super(httpService)
}

//...

async create(port: ICreateUserPort): Promise<ICreateUserDto> {
return new Promise<ICreateUserDto>((resolve) => {
resolve({
id: crypto.randomUUID(),
...port,
})
})
}
}

export {UserRepository}

Файл: src/data/singleton/index.ts

import { HTTP_APP_SERVICE } from '@/data/repository/common'
import { UserRepository } from '@/data/repository/user'

const USER_REPOSITORY = new UserRepository(HTTP_APP_SERVICE)

export { USER_REPOSITORY }

7. Слой App (TanStack Query)

Файл: src/app/modules/user/case/registration/case/request/index.ts

import {useMutation} from '@tanstack/react-query'

import type {ICreateUserDto} from '@/domain/user/interface/dto'

import type {ICreateUserPort} from '@/domain/user/interface/port'

import {USER_REPOSITORY} from '@/data/singleton'
import {CreateUsersUseCase} from '@/domain/user/use-case/create'

const useCase = new CreateUsersUseCase(USER_REPOSITORY)

const useCreateUserRequest = () => {
const callback = async (port: ICreateUserPort): Promise<ICreateUserDto> => {
return useCase.execute(port)
}
return useMutation({mutationFn: callback})
}

export {useCreateUserRequest}

8. Presenter

Файл: src/app/modules/user/case/table/case/presenter/index.ts

import {useAppForm} from '@/app/tools/provider/tanstack-form'

import {useCreateUserRequest} from '../request'

import type {ICreateUserPort} from '@/domain/user/interface/port'

const useCreateUserPresenter = () => {
const {mutateAsync, ...props} = useCreateUserRequest()

const handleOnSuccess = () => {
form.reset()
}

const mutateWithReset = async (port: ICreateUserPort) => {
return mutateAsync(port, {
onSuccess: handleOnSuccess,
})
}

const form = useAppForm({
defaultValues: {
name: '',
email: '',
avatar_url: '',
},
validators: {onSubmit: async ({value}) => mutateWithReset(value)},
})

return {
form,
...props,
}
}
export {useCreateUserPresenter}