Reduce the amount of duplicate code when mapping DTOs in Go

WBOY
Release: 2024-02-06 09:00:05
forward
535 people have browsed it

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

Question content

I'm currently learning Go and would appreciate people's insights on how best to reduce the amount of duplicate code.

The folder structure of the relevant parts is as follows:

.
├── http
│   ├── handlers
│   └── routes
├── models
│   └── dto
├── specifications
└── store
    └── postgres
Copy after login

In my specations folder I have 2 "storage" interfaces:

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
}
Copy after login
The

store/postgres folder contains the implementation of tasks and tags (repository mode).

Questions I saw:

In my handlers folder I have a struct that accepts input from one of the storage interfaces:

type TaskHandler struct {
    store specifications.TaskStore
}

func NewTaskHandler(store specifications.TaskStore) TaskHandler {
    return TaskHandler{
        store: store,
    }
}
Copy after login
type TagHandler struct {
    store specifications.TagStore
}

func NewTagHandler(store specifications.TagStore) TagHandler {
    return TagHandler{
        store: store,
    }
}
Copy after login

These handlers contain methods that will be mapped to api paths:

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)
    }
}
Copy after login
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)
    }
}
Copy after login

You'll notice that the List methods on each handler are basically the same, except for the interface used by each store.

How can I change this setting to reduce duplicate code?

I initially thought I could use generics to solve this problem, for example:

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
}
Copy after login

But this means mapping each type into a handler, which I don't think is a practical solution.

Any suggestions on how to better map my DTOs and interfaces?


Correct answer


You can have a helper function

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)
    }
}
Copy after login

Then you will have

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

func (h TagHandler) List() http.HandlerFunc {
    return ListHandler("tags", h.store.ListTags)
}
Copy after login

The above is the detailed content of Reduce the amount of duplicate code when mapping DTOs in Go. For more information, please follow other related articles on the PHP Chinese website!

source:stackoverflow.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!