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
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 }
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, } }
type TagHandler struct { store specifications.TagStore } func NewTagHandler(store specifications.TagStore) TagHandler { return TagHandler{ store: store, } }
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) } }
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) } }
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 }
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 ?
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) } }
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) }
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!