В приведенном ниже примере упрощенного кода мы выполняем десятки различных вызовов API с использованием библиотеки Go от нашего поставщика.
Библиотека поставщика предоставляет нам определение тел вызовов API:
// body of api call A
type requestBodyA struct {
aa string
bb int32
}
// body of api call B
type requestBodyB struct {
id string
}
И с функциями, которые выполняют вызовы для нас:
// fn performs api call A
func callCreateA(body requestBodyA) {
fmt.Println("Value of body is: ", body)
// makes api call using body requestBodyA
}
// fn performs api call B
func callCreateB(body requestBodyB) {
fmt.Println("Value of body is: ", body)
// makes another api call using body requestBodyB
}
Мы используем их для создания наших собственных функций CRUD, где мы читаем файлы конфигурации и выполняем вызовы создания / чтения / обновления / удаления:
func createA() {
bodyA := requestBodyA{
aa: "asdasfsd",
bb: 15,
}
// api retry loop
for i := 1; i <= 3; i++ {
// do some pre-checks (generic)
callCreateA(bodyA)
// check for errors (generic)
// check if error is recoverable (generic)
// if not return error (generic)
// if yes use the for loop and try the call again in 1,2,3,5,8,13, .. seconds (generic)
}
}
func createB() {
bodyB := requestBodyB{
id: "someUniqueId",
}
for i := 1; i <= 3; i++ {
// do some pre-checks (generic)
callCreateB(bodyB)
// check for errors (generic)
// check if error is recoverable (generic)
// if not return error (generic)
// if yes use the for loop and try the call again in 1,2,3,5,8,13, .. seconds (generic)
}
}
Как вы можете видеть в функциях createA
, createB
, мы повторяем много общего кода c (предварительные проверки, обработка ошибок, повтор l oop и многое другое) в каждом CRUD FN мы создаем. Поскольку мы имеем дело с более чем 30 ресурсами, каждый из которых имеет свою собственную функцию вызова API создания, чтения, обновления и уничтожения, мы копируем один и тот же код более 100 раз.
Я бы хотел переместить все c наполняет некоторый genericApiCaller () и присваивает ему тело вызова в виде одного параметра и имени или указатель на функцию вызова API в качестве второго параметра.
Проблема 1: callCreateA
и callCreateB
needs «тело» разных типов. Было бы намного проще, если бы они использовали интерфейс {}, но эти функции исходят из SDK производителя, и было бы неразумно изменять их (причины обновления и т. Д. c). Как динамически утверждать «body interface {}» genericApiCaller () для «body requestBodyA» или «body requestBodyB»? Утверждение времени выполнения невозможно в Go, но я не нашел подходящего решения для него.
Проблема 2: Как передать функции с различными типами параметров в качестве параметра для genericApiCaller ()?
https://play.golang.org/p/incf-NEaSJ3