Как вложить конечные точки в клиент API с интерфейсами, сохраняя читабельность - PullRequest
0 голосов
/ 09 ноября 2018

Я пытаюсь составить простой API-клиент, который застрял, пытаясь понять, как сделать его читабельным и тестируемым. Как я могу составить вложенную структуру, сохраняя ее тестируемой?

Код Psuedo:

type VehicleEndpoint struct {
    Car CarEndpoint
    VehicleGetter
}

type VehicleGetter interface {
    Get(string) Vehicle
}

type Vehicle struct {
    kind string
}

type VehicleClient struct {
    http.Client
    url string
}

func (v *VehicleClient) Get(kind string) Vehicle {
    resp := v.Do(v.url, kind)
    return Vehicle{
        kind: resp.Kind
    }
}


type CarEndpoint struct
...

type CarGetter interface
...

type Car struct
...

type CarClient struct
...


type API struct {
    Vehicle VehicleEndpoint
}

api := API{
    Vehicle: VehicleEndpoint{
        VehicleGetter: VehicleClient{
            http.Client{},
        }
        Car: CarEndpoint{
          CarGetter: CarClient{
            http.Client{},
          }
       }
    }
}

Теперь я могу вызывать API следующим образом:

api.Vehicle.Car.Get(kind)

Это дает мне очень удобочитаемую (вложенную) реализацию для работы, однако мне нелегко насмехаться над этими конечными точками, потому что использование интерфейса эффективно удаляет любое распознавание вложенной структуры. Каков был бы рекомендуемый способ создания API-интерфейса, обеспечивающего его удобочитаемость при одновременной проверке каждой конечной точки?

1 Ответ

0 голосов
/ 09 ноября 2018

Вы боретесь с языком и переносите ваши увлечения ООП на язык, который не предназначен для этого.

Лично я бы изменил направление и использовал бы старые добрые плоские структуры и функции.

Хотя, если вы хотите продолжить свой дизайн, вы можете смоделировать не интерфейс, а целый стек http. Вы можете тестировать свой код с гораздо большей уверенностью, поскольку вы тестируете реальную http полезную нагрузку по сравнению с совершением вызовов к вашим интерфейсам.

Ввести HttpClient в Vehicle: func NewVehicle(httpClient *http.Client){}

В тестовом коде используйте *http.ServeMux:

mux.Handle("/path1", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // assessments and mocked response
}))
mux.Handle("/path2", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // assessments and mocked response
}))
// fallback to show not implemented routes
result.mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        result.t.Errorf("Not Supported route %q", r.URL.Path)
}))

Сервер Http сборки:

server := httptest.NewServer(mux)

Создание Http-клиента с сервера мультиплексирования:

client := server.Client()
...