Каков идиоматический способ обработки версий API

Я создаю сервер в Go, предназначенный для мобильного приложения. Мне нужно иметь возможность поддерживать несколько версий API для случаев, когда пользователи не обновляют приложение. Основная проблема с управлением версиями — вернуть данные в правильном формате для версии мобильного приложения.

Я видел, что есть три основных способа сделать это.
A. Один из способов — иметь один обработчик маршрута на /, а затем позволить этой функции анализировать URL-адрес для управления версиями.
Пример:

func main() {
http.HandleFunc("/", routes.ParseFullURI)
}

B. Используйте библиотеку, такую ​​как gorilla/mux, для обработки шаблонов внутри маршрутизатора, но я видел некоторые предупреждает, что это может быть слишком медленно.
Пример:

  func main() {
            mux.HandleFunc("{version:}/", routes.ParseVersionForHome)
            mux.HandleFunc("{version:}/getData", routes.ParseVersionForGetDAta)
            mux.HandleFunc("{version:}/otherCall", routes.ParseVersionForOtherCall)
            }

C. Иметь отдельные URL-адреса, которые не меняются, но на основе заголовка делятся на разные версии. Пример:

func main() {
   http.HandleFunc("/", routes.ParseHeaderForVersionForHome)
   http.HandleFunc("/getData", routes.ParseHeaderForVersionForGetData)
   http.HandleFunc("/otherCall", routes.ParseHeaderForVersionForOtherCall)
}

Я обеспокоен тем, что вариант 1 будет слишком грязным с точки зрения кода. Я обеспокоен тем, что вариант 2 будет слишком медленным с точки зрения производительности, и я обеспокоен тем, что вариант 3 будет труден для обработки клиентом или может привести к путанице, поскольку версия не имеет четкой маркировки.

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


person Avik    schedule 21.04.2015    source источник
comment
Если вы говорите об API через HTTP(S), то обычно используется что-то вроде http://example.com/api/v1/…. Или вы больше спрашиваете, как реализовать такой шаблон на сервере Go?   -  person Dave C    schedule 21.04.2015
comment
Я спрашиваю, как это сделать на сервере Go. Я объясню дальше в своем вопросе.   -  person Avik    schedule 21.04.2015
comment
1 и 2 в основном эквивалентны, в первом вы просто выполняете маршрутизацию самостоятельно. Если gorilla/mux работает слишком медленно, не используйте его (даже HandleFunc по умолчанию использует маршрутизатор: http.ServeMux). 3 не имеет ничего общего с Go, просто хотите ли вы, чтобы ваши клиенты использовали заголовки или нет (что не должно иметь большого значения)   -  person JimB    schedule 21.04.2015
comment
Что ж, 3 имеет отношение к Go, потому что он четко определяет возможные маршруты в классе, а не в реализации функции. т.е. где вы видите список поддерживаемых API. Я объясню это более ясно на примере.   -  person Avik    schedule 21.04.2015
comment
Многие маршрутизаторы позволяют группировать разные маршруты. Возможно, вы захотите изучить это.   -  person placeybordeaux    schedule 21.04.2015
comment
@placeybordeaux Спасибо. Это привело меня к следующему: заголовок ="как я могу создать отдельные группы маршрутов с различным промежуточным ПО в goji golang"> stackoverflow.com/questions/25298646/ Может быть, это правильное направление. Вы хотите превратить это в полный ответ? Нужно пойти посмотреть, есть ли у Годжи эталоны.   -  person Avik    schedule 21.04.2015
comment
Не волнуйтесь о скорости маршрутизатора. На https://github.com/julienschmidt/go-http-routing-benchmark вы видите тайминги (для маршрута одного запроса) в тысячах наносекунд, как в микросекундах, так и в тысячных долях миллисекунды. Это настолько небольшая стоимость по сравнению, скажем, с записью в базу данных, что мне трудно даже понять это интуитивно.   -  person twotwotwo    schedule 21.04.2015
comment
(Чтобы было ясно, я думаю, что эхо — отличное достижение! Круто видеть нетривиальный нераспределяющий компонент. Но я не хочу, чтобы кто-то чувствовал, что он должен использовать его, чтобы получить хорошую производительность API.)   -  person twotwotwo    schedule 21.04.2015
comment
@twotwotwo Я собираюсь использовать Redis в качестве базы данных, поэтому мне нужно убедиться, что анализ URL-адреса не является узким местом.   -  person Avik    schedule 21.04.2015
comment
@Avik Абсолютно не будет. Общение с Redis будет на порядок (от одной цифры до десятков миллисекунд) медленнее, чем ваша маршрутизация. Даже имея более 5000 маршрутов, ваш маршрутизатор даже близко не приблизится к этому. Также обратите внимание, что Echo делает выделение — оно создает пул. Использование пула (get/put) не учитывается при расчете результатов распределения эталона.   -  person elithrar    schedule 22.04.2015
comment
@elithrar Я сейчас в замешательстве. Redis выполняет около 72 запросов в миллисекунду. Эхо оценивается в 4,5 миллисекунды на запрос на основе переменной? Я неправильно читаю цифры?   -  person Avik    schedule 22.04.2015


Ответы (1)


Существует множество фреймворков маршрутизации, которые позволяют группировать, например, с помощью эха (очень хороший фреймворк, если вам нужна скорость).

package main

import "github.com/labstack/echo"

func ping(c *echo.Context) {
        c.String(200, "pong")
}

func main() {
        e := echo.New()

        v1 := e.Group("/v1")
        v1.Get("/ping", ping)

        v2 := e.Group("/v2")
        v2.Get("/ping", ping)

        e.Run(":4444")
}

Я думаю, что это довольно чисто.

Я уверен, что многие другие фреймворки позволяют это сделать. Я точно знаю, что мартини помогает, но это не идиоматическая структура...

person placeybordeaux    schedule 21.04.2015
comment
Спасибо. Теперь мне просто нужно найти лучшую библиотеку для своих нужд, но это, похоже, самый распространенный подход к версионированию в Go. Список библиотек, поддерживающих группировку и работающих быстро, кажется почти бесконечным! - person Avik; 21.04.2015
comment
Привет, я искал в сети, и мне было трудно понять, является ли ping одной и той же функцией, и если да, то как я различаю, какая группа вызвала ее, чтобы вернуть разные результаты. - person Avik; 26.04.2015
comment
Пинг - та же функция. В контексте ping вы можете найти предоставленный URL-адрес. Я предполагал, что вы будете вызывать разные функции для разных версий. - person placeybordeaux; 30.04.2015