AstroWay/api v2.95.1 · blog
усі системи в нормі

X-Cache header: видимий cache-status для оптимізації клієнтських інтеграцій

Кожна response API тепер несе X-Cache: MISS | HIT | BYPASS — клієнт відразу бачить чи запит обчислений з нуля, чи витягнутий з кешу. Це відкриває cache hit % колонку в /dashboard/usage та дозволяє оптимізувати інтеграцію без guesswork.

Server-side кеш у нас працював давно — детермінований чарт-розрахунок для тієї самої date/time/lat/lon повертається з кешу, не повторно через WASM ephemeris. Але клієнт цього не бачив. У dashboard колонка “cache hit %” показувала тому, що бекенд логував cache-outcome у внутрішню метрику, а не у відповідь.

Тепер кожна response несе один з трьох заголовків:

X-Cache: HIT # обслужено з кешу
X-Cache: MISS # обчислено з нуля, результат збережено
X-Cache: BYPASS # не кешується за дизайном

Це маленька зміна — заголовок плюс одна колонка в api_request_log — але вона відкриває цілий клас оптимізацій, які раніше були сліпою плямою.

Terminal window
curl -I -X POST https://api.astroway.info/v1/chart \
-H "X-Api-Key: aw_live_..." \
-H "Content-Type: application/json" \
-d '{
"date": "1990-05-15",
"time": "14:30",
"timezoneOffset": 3,
"latitude": 50.45,
"longitude": 30.52
}' | grep -i x-cache
# X-Cache: MISS

Виконати другий раз з тим самим тілом запиту:

Terminal window
# X-Cache: HIT

Для ендпоінтів типу /v1/transits/now (динамічний час) — X-Cache: BYPASS, бо результат залежить від поточного Date.now() і кешувати немає сенсу.

Які ендпоінти що повертають

Section titled “Які ендпоінти що повертають”

Не всі ендпоінти кешуються — і це навмисно. Розбивка:

  • Детерміновані чарт-розрахунки (/v1/chart, /v1/houses, /v1/aspects, /v1/synastry, /v1/dasha/*, /v1/vargas/*) — кешуються повністю. Очікувано MISS → HIT pattern.
  • Time-dependent (/v1/transits/now, /v1/horoscope/today, /v1/moon/phase-now) — BYPASS. Кеш би міг бути правильним лише до кінця хвилини, тому простіше не кешувати взагалі.
  • AI-generated content (/v1/horoscope/personal, /v1/interpret/*) — BYPASS. LLM-відповіді не детерміновані навіть на однаковий промпт, кешувати = фіксувати випадковість.
  • Render endpoints (/v1/render/*) — MISS/HIT для деяких, BYPASS для тих, що приймають великі payload-и (eclipse-path з 500 точками).

Маркер на конкретний endpoint видно зразу з response — не треба читати документацію щоб зрозуміти кешується чи ні.

Pricing impact — кешовані запити все одно коштують

Section titled “Pricing impact — кешовані запити все одно коштують”

Це найважливіша річ для розуміння — кешовані запити продовжують deduct credits на той самий tier, що й MISS. Чому:

  1. Pricing у нас calibrated на business value endpoint-а, не на CPU-cost. /v1/chart коштує однаково чи WASM крутився, чи ні — клієнт отримав однаковий чарт.
  2. Прозорість. Не хочемо ситуації коли один user-base платить за MISS, а інший за HIT (теоретично через “пощастило з кешем”). Pricing predictable.
  3. Cache infrastructure — це інфра, не value-add. Ми її субсидуємо у tier’і.

Але це не значить що X-Cache беззмістовний у pricing-контексті — він видимо показує архітектурні можливості для клієнта (див. наступний розділ).

Що з цим робити на клієнтській стороні

Section titled “Що з цим робити на клієнтській стороні”

Чотири практичні pattern-и:

Якщо ви бачите X-Cache: MISS для запиту, який сценарієм може повторитись (натальна карта тієї самої людини), кешуйте локально у Redis/Memcached/IndexedDB. Server-side кеш у нас має TTL і evict policy — ваш клієнтський шар з контрольованим TTL уникне лишніх credit-deduct.

import { AstroWay } from "@astroway/sdk";
const cache = new Redis();
const client = new AstroWay({
apiKey: process.env.ASTROWAY_KEY,
// optional: hook on response headers
onResponse(req, res) {
const cacheStatus = res.headers["x-cache"];
metrics.increment(`astroway.cache.${cacheStatus.toLowerCase()}`);
},
});
async function getChart(input: ChartInput) {
const cacheKey = `chart:${hashChart(input)}`;
const cached = await cache.get(cacheKey);
if (cached) return JSON.parse(cached);
const chart = await client.chart.create(input);
await cache.set(cacheKey, JSON.stringify(chart), "EX", 86400);
return chart;
}

Якщо ваш сервіс приймає масові запити на однакові birth-data (онбординг кампанія, де колеги тестують однаковими демо-даними), використовуйте промісовий dedupe:

const inFlight = new Map<string, Promise<Chart>>();
function getChart(input: ChartInput) {
const key = hashChart(input);
if (inFlight.has(key)) return inFlight.get(key)!;
const promise = client.chart.create(input);
inFlight.set(key, promise);
promise.finally(() => inFlight.delete(key));
return promise;
}

Це не зекономить credits (кожен виклик все одно зараховує), але прибирає затори при concurrency-сплесках.

Якщо в продукті є ритуальні чарти (популярні daily-horoscope знаки), pre-warm-те їх scheduled cron-ом. Перший виклик дня — MISS, всі наступні до evict-у — HIT. Користувач отримує subsecond response.

4. Dashboard insight: де ви над-платите

Section titled “4. Dashboard insight: де ви над-платите”

Нова колонка cache hit % у /dashboard/usage за endpoint показує:

  • HIT% = 90+ — endpoint добре кешується, ймовірно той самий чарт пересилається кілька разів. Розгляньте client-side dedupe (#2).
  • HIT% = 0 і BYPASS — endpoint не кешується дизайном (transits/now, AI). Це нормально.
  • HIT% = 50% і MISS — половина запитів несе унікальні параметри, половина — повтори. Worth-while client-side cache.
  • HIT% низький + endpoint детермінований — підозріло. Перевірте чи ваш клієнт не додає випадкових fields у payload (timestamps, request-id), які забивають кеш-ключ.

Технічна імплементація — для curious

Section titled “Технічна імплементація — для curious”

Tracking коштує одну колонку у api_request_log.cache_status (enum: MISS|HIT|BYPASS, migration 030). Колонка populate-нута з того ж handler-а, який приймає рішення про кеш-lookup — додатковий запит до DB не робиться.

GET /v1/me/usage/endpoints тепер повертає реальне cache_hit_pct замість null для кожного endpoint-а у вашій історії. SDK-метод client.me.usage.endpoints() отримає поле автоматично (типи у наступному codegen-релізі).

Cache instrumentation відкриває проміжний рівень оптимізацій між “no caching” і “full edge cache”. Наступні штрихи у роадмапі:

  • Cache-Control респонсний заголовок з реальним TTL для кешованих endpoint-ів — дозволить CDN/proxy-кеш на стороні клієнта
  • If-None-Match ETags — повторні MISS-перевірки без повного payload-у у відповіді
  • Per-user cache statistics у dashboard з можливістю invalidate (наприклад, форсовано пересчити certain chart після виправлення birth-time)

Документація — /docs/api/ → Performance & Caching. Конкретний X-Cache reference — у секції headers кожного endpoint-а.

AstroWay team

Інженерна команда AstroWay API. Ми загортаємо Swiss Ephemeris у чистий REST і пишемо про нудні деталі, які насправді важливі.

// побудуй на цьому

Той самий Swiss Ephemeris, що й у Solar Fire — у 4 рядках коду.

Безкоштовний ключ без картки. 5 000 викликів на місяць до першої оплати.

Більше з блогу усі дописи →

Engineering 2026-05-19

White-label PDF без WordPress: inline branding через одне поле

Поле whitelabel у схемах усіх 12 ендпоінтів /v1/reports/* тепер приймає не лише boolean (читати DB-конфіг), а й inline-об'єкт з 15 полями. Це знімає прив'язку до WordPress-користувача — будь-який SaaS-консумент API може брендувати PDF на льоту, без okремої admin-сторінки.

Changelog 2026-05-14

Pricing v2: пакети, прозорість, річна знижка 25% — підсумок Тижня 1

За 7 днів ми переробили pricing model: уніфікували Reports, додали 3 add-on пакети ($9 Esoteric, $19 Vedic, $99 Reports), бахнули 25% знижку на річний з roll-over невикористаних кредитів, і опублікували вартість усіх 700+ ендпоінтів. Що це значить для вашої інтеграції.

Human Design 2026-04-22

Запуск AstroWay API: повний стек астрологічних розрахунків з точністю Swiss Ephemeris

Три роки ми будували обчислювальний шар астрології для власних споживчих продуктів. Тепер відкриваємо API для зовнішніх розробників. Ось що всередині, чому ми це зробили і які жорсткі компроміси прийняли.