Hatalar
Tüm hatalar aynı zarfla döner. Mantığınızı error.code üzerine kurun; message İngilizcedir ve değişebilir, kullanıcıya göstermek için uygun değildir.
{ "error": { "code": "VALIDATION_ERROR", "message": "Invalid calculation input", "details": { "fields": [{ "field": "amount", "reason": "SCALE_EXCEEDED", "message": "amount allows at most 2 fractional digits" }] } }, "requestId": "8a3e7260-dcb6-4227-acdb-88b2a07774e8"}requestId, X-Request-Id başlığıyla aynıdır. Destek isterken bu değeri iletin.
Hata kodları
Bölüm başlığı “Hata kodları”| Kod | HTTP | Ne zaman | Yeniden dene? |
|---|---|---|---|
VALIDATION_ERROR |
422 (bozuk JSON: 400, içerik türü: 415) | Parametre/gövde şeması veya hesaplama girdisi hatası. | Hayır, isteği düzeltin. |
NOT_FOUND |
404 | Araç yok, yayında değil veya istenen dilde değil; bilinmeyen adres. | Hayır. |
CONFLICT |
409 | details.reason = "VERSION_OUTDATED": gönderdiğiniz version artık canlı değil. |
Tanımı yeniden alıp tekrar deneyin. |
CALCULATION_ERROR |
422 / 500 | 422: bu girdilerle sonuç tanımsız. 500: araç geçici olarak hesaplanamıyor. | 422: hayır. 500: bir süre sonra. |
RATE_UNAVAILABLE |
422 | asOf tarihinde yürürlükte oran yok veya oran kullanılamıyor. |
Tarihi değiştirin. |
PAYLOAD_TOO_LARGE |
413 | Gövde 16 KB’ı aşıyor. | Hayır. |
RATE_LIMITED |
429 | Hız sınırı aşıldı. | Retry-After kadar bekleyip evet. |
TIMEOUT |
504 | İstek 15 sn içinde tamamlanamadı. | Evet (geri çekilmeyle). |
SERVICE_UNAVAILABLE |
503 | Hizmet geçici olarak kullanılamıyor. | Evet (geri çekilmeyle). |
MAINTENANCE |
503 | Araç geçici olarak bakımda. | Retry-After sonra evet. |
INTERNAL_ERROR |
500 | Beklenmeyen hata; ayrıntı yalnızca sunucu kayıtlarında. | Evet, birkaç kez; sürerse requestId ile bildirin. |
details alanları
Bölüm başlığı “details alanları”Parametre veya gövde şeması: details.issues[]
Bölüm başlığı “Parametre veya gövde şeması: details.issues[]”{ "issues": [{ "path": "inputs.amount", "message": "Invalid input", "code": "invalid_union" }] }path hatalı alanın yolu, code şema doğrulayıcısının kodudur (invalid_type, unrecognized_keys…). Geçersiz asOf için details.field = "asOf" döner.
Hesaplama girdisi: details.fields[]
Bölüm başlığı “Hesaplama girdisi: details.fields[]”{ "fields": [{ "field": "vatRateOption", "reason": "MISSING_INPUT", "message": "vatRateOption is required" }] }reason |
Anlamı |
|---|---|
MISSING_INPUT |
Zorunlu alan gönderilmedi. |
NULL_INPUT |
Değer null. |
INVALID_INPUT |
Değer geçersiz (ör. tanımda olmayan enum değeri). |
TYPE_MISMATCH |
Tür uyuşmuyor. |
OUT_OF_RANGE |
min/max dışında. |
SCALE_EXCEEDED |
Fazla ondalık hane. |
UNKNOWN_INPUT |
Tanımda olmayan alan. |
Bu hataları kullanıcıya alan bazında göstermek için fields[].field ile formunuzdaki alanı eşleştirin; metni kendi dilinizde üretin.
Hesaplama hatası: details.reason
Bölüm başlığı “Hesaplama hatası: details.reason”422 CALCULATION_ERROR için: DIVISION_BY_ZERO, CALCULATION_OVERFLOW, INVALID_DATE_OPERATION, INVALID_ARGUMENT, NO_SOLUTION. Girdi kombinasyonu matematiksel olarak anlamsızdır; kullanıcıdan değeri değiştirmesini isteyin.
Oran yok: RATE_UNAVAILABLE
Bölüm başlığı “Oran yok: RATE_UNAVAILABLE”{ "error": { "code": "RATE_UNAVAILABLE", "message": "No rate is in force for the requested date", "details": { "rates": ["tr.vat.standard"], "asOf": "1990-01-01" } }, "requestId": "…" }Hız sınırı: RATE_LIMITED
Bölüm başlığı “Hız sınırı: RATE_LIMITED”Retry-After başlığı (saniye) ve details.retryAfterSeconds ile gelir. Ayrıntı: Hız sınırları.
İşleme stratejisi
Bölüm başlığı “İşleme stratejisi”- 4xx’i yeniden denemeyin (429 ve 409 hariç): istek düzeltilmeden aynı sonucu verir.
- 429 ve 503
MAINTENANCE:Retry-Afterkadar bekleyin. - 5xx, 504 ve ağ hataları: üstel geri çekilme ve rastgelelikle (jitter) 2–3 kez deneyin.
- Her zaman
requestId’yi kaydedin.
async function calculate(key, body, attempt = 0) { const response = await fetch(`https://api.mirac-ozdemir.com/v1/public/tools/by-key/${key}/calculate`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), signal: AbortSignal.timeout(20_000), }); if (response.ok) return response.json();
const { error, requestId } = await response.json().catch(() => ({ error: { code: 'INTERNAL_ERROR' } })); const retryAfter = Number(response.headers.get('Retry-After')); const retryable = response.status === 429 || response.status >= 500;
if (retryable && attempt < 3) { const wait = retryAfter > 0 ? retryAfter * 1000 : 2 ** attempt * 500 + Math.random() * 250; await new Promise((resolve) => setTimeout(resolve, wait)); return calculate(key, body, attempt + 1); } throw Object.assign(new Error(error.code), { code: error.code, details: error.details, requestId });}import random, time, requests
def calculate(key, body, attempts=3): url = f"https://api.mirac-ozdemir.com/v1/public/tools/by-key/{key}/calculate" for attempt in range(attempts + 1): r = requests.post(url, json=body, timeout=20) if r.ok: return r.json() retryable = r.status_code == 429 or r.status_code >= 500 if not retryable or attempt == attempts: err = r.json().get("error", {}) raise RuntimeError(f"{err.get('code')} (requestId={r.json().get('requestId')})") wait = float(r.headers.get("Retry-After", 0)) or (2 ** attempt * 0.5 + random.random() * 0.25) time.sleep(wait)