Ошибки
Ошибки возвращаются в JSON, как и всё остальное, с соответствующим HTTP-статусом и кодом, по которому можно ветвить логику. Сообщение представляет собой предложение для ваших логов, а не для пользователей; его формулировка может меняться, код не изменится никогда.
Обёртка ошибки
{
"status": "error",
"error": {
"code": "invalid_request",
"message": "Parameter 'lat' must be a number between -90 and 90.",
"param": "lat"
}
}param присутствует, если проблему вызвал конкретный параметр. X-Request-Id задаётся и в ответах с ошибкой; укажите его, если обращаетесь в поддержку.
Коды
| HTTP | code | Когда | Что делать |
|---|---|---|---|
| 400 | invalid_request | Отсутствует обязательный параметр, значение имеет неверный формат или вне допустимого диапазона, в пакете больше 100 точек или адресов, запрошено больше 10 результатов. | Исправьте запрос. Не повторяйте его без изменений. |
| 401 | missing_key | Ключ не передан, а доступ без ключа на этом сервере отключён. По умолчанию он включён, и запрос без ключа просто обрабатывается. | Передайте ключ в X-API-Key, в виде bearer-токена или в key=. |
| 429 | quota_exceeded | Адрес исчерпал свои 2 500 бесплатных запросов на сегодня без ключа. | Дождитесь сброса (когда он произойдёт, показывают Retry-After и X-Quota-Reset) или передайте ключ с балансом или пакетом Unlimited. |
| 401 | invalid_key | Ключ не существует. | Проверьте, нет ли опечаток или обрезанной при копировании части. |
| 401 | key_revoked | Ключ был отозван в личном кабинете. | Используйте действующий ключ. |
| 402 | no_credits | Бесплатная дневная квота ключа исчерпана, а баланс аккаунта пуст. | Пополните баланс в личном кабинете картой или криптовалютой либо дождитесь сброса. |
| 403 | key_ip_limit | Все IP-слоты этого ключа на ближайшее время заняты другими адресами. | Используйте одну из машин, занимающих слоты, выдайте этой машине собственный ключ или добавьте пакет. См. IP-слоты. |
| 403 | account_suspended | Аккаунт заблокирован. | Проверьте письма от нас или создайте обращение в поддержку. |
| 404 | not_found | Путь не существует. Запрос без совпадений возвращает 200 с пустыми результатами, а не 404. | Проверьте путь и префикс версии. |
| 500 | server_error | Что-то сломалось на нашей стороне. | Повторите один раз через секунду. Ошибка записывается в лог и оповещает нас. Не засчитывается. |
| 503 | unavailable | Бэкенд временно недоступен. | Повторяйте с увеличивающейся задержкой. Не засчитывается. |
Что не является ошибкой
- Нет результатов. Прямое геокодирование бессмыслицы возвращает
200с"results": []. Обратное геокодирование точки в океане возвращает200с"result": null. Оба засчитываются как запрос. - Низкая точность. Результат с
"precision": "admin", когда вам нужен был дом, это успешный запрос, который нашёл меньше, чем вы надеялись. Проверяйте это поле. - Частные IP-адреса. Запрос для
10.0.0.1возвращает200с"is_private": trueи без местоположения.
Ошибки на совместимых хостах
Совместимые хосты возвращают ошибки в том формате, который использует исходный провайдер, поэтому существующая обработка работает. Например, пустой баланс это "status": "OVER_QUERY_LIMIT" с HTTP 200 на gapi.mygeocode.com, "statusCode": 429 в обёртке Bing на bing.mygeocode.com и {"status":"fail","message":"quota"} на ipapi.mygeocode.com; неверный ключ соответственно REQUEST_DENIED, 401 и invalid key. Заголовки X-Quota-* отправляются на каждом хосте в любом случае, поэтому при желании реальное состояние можно узнать из заголовков.
Разумная стратегия обработки
def call(url, params, tries=3):
for attempt in range(tries):
r = session.get(url, params=params, timeout=10)
if r.status_code == 200:
return r.json()
body = r.json()
code = body["error"]["code"]
if r.status_code in (500, 503):
time.sleep(0.2 * (2 ** attempt))
continue
# no_credits, key_ip_limit, invalid_request, invalid_key: retrying will not help
raise ApiError(code, body["error"]["message"], r.headers.get("X-Request-Id"))
raise ApiError("retries_exhausted", "Gave up after %d attempts" % tries, None)