Maison > développement back-end > Golang > Réduisez la quantité de code en double lors du mappage des DTO dans Go

Réduisez la quantité de code en double lors du mappage des DTO dans Go

WBOY
Libérer: 2024-02-06 09:00:05
avant
572 Les gens l'ont consulté

在 Go 中映射 DTO 时减少重复代码的数量

Contenu de la question

J'apprends actuellement Go et j'apprécierais les idées des gens sur la meilleure façon de réduire la quantité de code en double.

La structure des dossiers des parties concernées est la suivante :

.
├── http
│   ├── handlers
│   └── routes
├── models
│   └── dto
├── specifications
└── store
    └── postgres
Copier après la connexion

Dans mon specations dossier j'ai 2 interfaces "stockage" :

type TaskStore interface {
    CreateTask(ctx context.Context, input dto.TaskCreate) error
    UpdateTask(ctx context.Context, id int, input dto.TaskUpdate) error
    GetTask(ctx context.Context, id int) (dto.TaskResult, error)
    ListTasks(ctx context.Context) ([]dto.TaskResult, error)
    DeleteTask(ctx context.Context, id int) error
}

type TagStore interface {
    CreateTag(ctx context.Context, input dto.TagCreate) error
    RenameTag(ctx context.Context, id int, input dto.TagUpdate) error
    ListTags(ctx context.Context) ([]dto.TagResult, error)
    GetTag(ctx context.Context, id int) (dto.TagResult, error)
    DeleteTag(ctx context.Context, id int) error
}
Copier après la connexion

store/postgres le dossier contient l'implémentation des tâches et des balises (modèle de référentiel).

Questions que je vois :

Dans mon dossier handlers, j'ai une structure qui prend les entrées de l'une des interfaces de stockage :

type TaskHandler struct {
    store specifications.TaskStore
}

func NewTaskHandler(store specifications.TaskStore) TaskHandler {
    return TaskHandler{
        store: store,
    }
}
Copier après la connexion
type TagHandler struct {
    store specifications.TagStore
}

func NewTagHandler(store specifications.TagStore) TagHandler {
    return TagHandler{
        store: store,
    }
}
Copier après la connexion

Ces gestionnaires contiennent des méthodes qui seront mappées aux chemins de l'API :

func (h TaskHandler) List() http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        tasks, err := h.store.ListTasks(r.Context())
        if err != nil {
            log.Err(err).Msg("failed to retrieve tasks")
            w.WriteHeader(http.StatusInternalServerError)
            return
        }
        render.JSON(w, r, tasks)
    }
}
Copier après la connexion
func (h TagHandler) List() http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        tags, err := h.store.ListTags(r.Context())
        if err != nil {
            log.Err(err).Msg("failed to retrieve tags")
            w.WriteHeader(http.StatusInternalServerError)
            return
        }
        render.JSON(w, r, tags)
    }
}
Copier après la connexion

Vous remarquerez que les méthodes List sur chaque gestionnaire sont fondamentalement les mêmes, à l'exception de l'interface utilisée par chaque magasin.

Comment modifier ce paramètre pour réduire le code en double ?

J'ai d'abord pensé pouvoir utiliser des génériques pour résoudre ce problème, par exemple :

type EntityStore[CreateDto any, UpdateDto any, ResultDto any] interface {
    Create(ctx context.Context, input CreateDto) error
    Update(ctx context.Context, id int, input UpdateDto) error
    List(ctx context.Context) ([]ResultDto, error)
    Get(ctx context.Context, id int) (ResultDto, error)
    Delete(ctx context.Context, id int) error
}
Copier après la connexion

Mais cela signifie mapper chaque type dans un gestionnaire, ce qui, je ne pense pas, soit une solution pratique.

Des suggestions sur la façon de mieux cartographier mes DTO et mes interfaces ?


Bonne réponse


Vous pouvez avoir une fonction d'assistance

func ListHandler[T any](name string, lister func(ctx context.Context) ([]T, error)) func(w http.ResponseWriter, r *http.Request) {
    return func(w http.ResponseWriter, r *http.Request) {
        list, err := lister(r.Context())
        if err != nil {
            log.Err(err).Msg("failed to retrieve " + name)
            w.WriteHeader(http.StatusInternalServerError)
            return
        }
        render.JSON(w, r, list)
    }
}
Copier après la connexion

Alors vous aurez

func (h TaskHandler) List() http.HandlerFunc {
    return ListHandler("tasks", h.store.ListTasks)
}

func (h TagHandler) List() http.HandlerFunc {
    return ListHandler("tags", h.store.ListTags)
}
Copier après la connexion

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:stackoverflow.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal