Renk API'si Tasarlamak: Renk Verisi için REST Uç Noktaları
Embed This Widget
Add the script tag and a data attribute to embed this widget.
Embed via iframe for maximum compatibility.
<iframe src="https://colorfyi.com/iframe/entity//" width="420" height="400" frameborder="0" style="border:0;border-radius:10px;max-width:100%" loading="lazy"></iframe>
Paste this URL in WordPress, Medium, or any oEmbed-compatible platform.
https://colorfyi.com/entity//
Add a dynamic SVG badge to your README or docs.
[](https://colorfyi.com/entity//)
Use the native HTML custom element.
Bir renk API'si, kaç tane aracın renk verisi tükettiğini düşünene kadar niş görünür: dönüşüme ihtiyaç duyan tasarım araçları, kontrastı doğrulayan erişilebilirlik denetleyicileri, adlandırılmış renk araması gerektiren renk seçici bileşenler ve uyum rengi üreten palet oluşturucular. Bunlardan herhangi birini inşa ediyorsanız ya da diğer geliştiricilere renk verisi sağlıyorsanız, iyi tasarlanmış bir REST API'ye ihtiyacınız var.
Bu kılavuz, tam tasarım yüzeyini kapsıyor: şema kararları, uç nokta yapısı, yanıt formatları, hata yönetimi ve hız sınırlaması — ColorFYI'daki Renk Dönüştürücü ve Kontrast Denetleyici'ye güç veren uç noktaları inşa eden birinin bakış açısından.
Renk Verisi için API Şema Tasarımı
Temel Renk Nesnesi
Bir rengin birden fazla gösterimi vardır — hex, RGB, HSL, CMYK, OKLCH — ve birden fazla meta veri alanı. Kanonik yanıt nesnesi, istemcilerin ek istekler yapmak zorunda kalmadan ihtiyaç duydukları formatı kullanmalarına olanak tanıyarak hepsini içermelidir:
{
"hex": "#FF5733",
"rgb": {
"r": 255,
"g": 87,
"b": 51,
"css": "rgb(255, 87, 51)"
},
"hsl": {
"h": 11,
"s": 100,
"l": 60,
"css": "hsl(11, 100%, 60%)"
},
"hsv": {
"h": 11,
"s": 80,
"v": 100
},
"cmyk": {
"c": 0,
"m": 66,
"y": 80,
"k": 0
},
"oklch": {
"l": 0.63,
"c": 0.19,
"h": 27.5,
"css": "oklch(0.63 0.19 27.5)"
},
"luminance": 0.215,
"is_dark": false,
"name": "Coral Red",
"name_source": "color_name_database",
"name_distance": 0.04
}
is_dark alanını (parlaklıktan türetilmiş) eklemek, istemcilerin WCAG parlaklık hesaplamasını kendileri uygulamak zorunda kalmamasını sağlar. name ve name_distance alanları, istemcilerin ayrı bir API çağrısı yapmadan en yakın adlandırılmış rengi göstermesine olanak tanır.
Adlandırma Kuralları
JSON anahtarları için snake_case kullanın (çoğu REST API ile tutarlı). İlgili alanları düzleştirmek yerine nesnelere yerleştirin (rgb, hsl, cmyk). İç içe nesneler daha okunabilir, JavaScript'te yapılandırması daha kolay ve yazılı arayüzlerle temiz bir şekilde eşleşir:
interface ColorResponse {
hex: string;
rgb: { r: number; g: number; b: number; css: string };
hsl: { h: number; s: number; l: number; css: string };
oklch: { l: number; c: number; h: number; css: string };
luminance: number;
is_dark: boolean;
name: string | null;
name_source: string | null;
name_distance: number | null;
}
Hex Normalleştirme
Hex renkleri birden fazla formatta kabul edin — # ile veya olmadan, 3 basamaklı veya 6 basamaklı, büyük harf veya küçük harf — ve herhangi bir işlemden önce API katmanında normalleştirin:
# Python/Django örneği
import re
def normalize_hex(raw: str) -> str:
"""Hex girişini # olmadan 6 basamaklı büyük harfe normalleştir."""
clean = raw.strip().lstrip('#').upper()
if not re.match(r'^[0-9A-F]{3}$|^[0-9A-F]{6}$', clean):
raise ValueError(f"Geçersiz hex rengi: {raw!r}")
# 3 basamaklıyı 6 basamaklıya genişlet
if len(clean) == 3:
clean = ''.join(c * 2 for c in clean)
return clean
Yanıtta normalleştirilmiş formu döndürün — bu belirsizliği ortadan kaldırır ve aşağı akış önbelleğini daha öngörülebilir hale getirir.
Hex/RGB/HSL Dönüşüm Uç Noktaları
GET /api/color/{hex}
Birincil uç nokta, belirli bir hex kodu için tam renk nesnesini döndürür. Renk Dönüştürücü'nün tüm format alanlarını aynı anda doldurmak için kullandığı budur:
GET /api/color/FF5733
GET /api/color/%23FF5733 (URL kodlu #)
GET /api/color/f57 (3 basamaklı, küçük harf)
Üçü de #FF5733 için aynı yanıtı döndürmelidir.
Yanıt:
{
"hex": "#FF5733",
"rgb": { "r": 255, "g": 87, "b": 51, "css": "rgb(255, 87, 51)" },
"hsl": { "h": 11, "s": 100, "l": 60, "css": "hsl(11, 100%, 60%)" },
"cmyk": { "c": 0, "m": 66, "y": 80, "k": 0 },
"oklch": { "l": 0.63, "c": 0.19, "h": 27.5, "css": "oklch(0.63 0.19 27.5)" },
"luminance": 0.215,
"is_dark": false,
"name": "Coral Red",
"name_source": "css_extended",
"name_distance": 0.08
}
POST /api/convert
Hex olmayan keyfi girdileri dönüştürmek için — CSS renk adları, RGB üçlüleri, HSL değerleri:
POST /api/convert
Content-Type: application/json
{
"input": "rgb(255, 87, 51)",
"from": "rgb"
}
Yanıt: Aynı tam renk nesnesi.
from değerleri olarak şunları kabul edin: hex, rgb, hsl, cmyk, oklch, name. Girdi formatının bildirilen from türüyle eşleştiğini doğrulayın ve uyumsuzluk durumunda net bir hata mesajıyla 422 döndürün.
Django ViewSet Örneği
# apps/api/views.py
from django.http import JsonResponse
from django.views import View
from apps.colors.engine import ColorEngine
class ColorDetailView(View):
def get(self, request, hex_code: str):
try:
normalized = normalize_hex(hex_code)
except ValueError as e:
return JsonResponse(
{"error": "invalid_hex", "message": str(e)},
status=422
)
engine = ColorEngine(normalized)
data = {
"hex": f"#{normalized}",
"rgb": engine.to_rgb_dict(),
"hsl": engine.to_hsl_dict(),
"cmyk": engine.to_cmyk_dict(),
"oklch": engine.to_oklch_dict(),
"luminance": engine.relative_luminance(),
"is_dark": engine.is_dark(),
"name": engine.nearest_name(),
"name_source": engine.nearest_name_source(),
"name_distance": engine.nearest_name_distance(),
}
response = JsonResponse(data)
response["Cache-Control"] = "public, max-age=86400, stale-while-revalidate=604800"
return response
Renk verilerini agresif biçimde önbelleğe alın — belirli bir hex kodu her zaman aynı çıktıyı üretir, bu nedenle önbellek çok uzun ömürlü olabilir.
Renk Arama ve Otomatik Tamamlama API'si
GET /api/search
Adlandırılmış renk araması, renk seçicilerdeki ve arama alanlarındaki otomatik tamamlamayı çalıştırır. Sorgu parametresi kısmi bir renk adıdır:
GET /api/search?q=coral
GET /api/search?q=teal&limit=5
GET /api/search?q=%230d&source=css // Hex önekiyle arama
Yanıt:
{
"results": [
{
"hex": "#FF7F50",
"name": "Coral",
"source": "css_named",
"score": 1.0
},
{
"hex": "#FF6B6B",
"name": "Light Coral",
"source": "css_extended",
"score": 0.85
},
{
"hex": "#E8735A",
"name": "Terra Cotta",
"source": "crayola",
"score": 0.62
}
],
"total": 3,
"query": "coral"
}
Arama Uygulaması Değerlendirmeleri
Küçük adlandırılmış renk veritabanları (~2.000 kayıt) için, bulanık eşleştirmeli bellek içi önek araması yeterince hızlıdır:
from difflib import SequenceMatcher
def search_colors(query: str, limit: int = 10) -> list[dict]:
q = query.lower().strip()
results = []
for color in NAMED_COLORS: # Önceden yüklenmiş liste
name = color["name"].lower()
if q in name:
# Tam alt dizi eşleşmesi: konuma göre puan
pos = name.index(q)
score = 1.0 - (pos / len(name)) * 0.3
else:
# Bulanık eşleşme
score = SequenceMatcher(None, q, name).ratio()
if score < 0.5:
continue
results.append({**color, "score": round(score, 3)})
results.sort(key=lambda x: x["score"], reverse=True)
return results[:limit]
10.000'den fazla kayıt içeren veritabanları için, milisaniyenin altında bulanık arama için trigram indekslemeli PostgreSQL'in pg_trgm uzantısını kullanın:
-- Uzantıyı etkinleştir
CREATE EXTENSION IF NOT EXISTS pg_trgm;
-- İndeks ekle
CREATE INDEX idx_color_name_trgm ON named_colors USING gin(name gin_trgm_ops);
-- Sorgu
SELECT hex, name, source, similarity(name, 'coral') AS score
FROM named_colors
WHERE name % 'coral'
ORDER BY score DESC
LIMIT 10;
Otomatik Tamamlama Optimizasyonu
Canlı yazarken arama otomatik tamamlama için düşük gecikme süresini optimize edin:
- İstemcide geri tepme — İstek göndermeden önce minimum 150 ms.
- Minimum sorgu uzunluğu belirleyin — 2 karakterden kısa sorguları reddedin (hemen boş sonuç döndürün).
- Sonuçları sorguya göre önbelleğe alın — Farklı kullanıcılardan gelen aynı sorgu aynı sonucu döndürür.
Cache-Control: public, max-age=3600kullanın. - Sonuç yoksa hızlı yanıt verin — Tam bulanık tarama yapmak yerine hemen
{"results": [], "total": 0}yanıtı verin.
Kontrast Denetleme Uç Noktası
GET /api/contrast
Kontrast API'si, Kontrast Denetleyici'nin motorudur. İki hex kodu alır ve her seviye için geçti/kaldı durumunu içeren WCAG kontrast oranını döndürür:
GET /api/contrast?fg=FF5733&bg=FFFFFF
GET /api/contrast?fg=000000&bg=FFFFFF
Yanıt:
{
"ratio": 3.02,
"ratio_formatted": "3.02:1",
"foreground": {
"hex": "#FF5733",
"luminance": 0.215
},
"background": {
"hex": "#FFFFFF",
"luminance": 1.0
},
"wcag": {
"aa_normal": false,
"aa_large": true,
"aaa_normal": false,
"aaa_large": false
},
"level": "AA Large",
"passes": true
}
level alanı, çiftin ulaştığı en yüksek WCAG seviyesini döndürür ("AAA", "AA", "AA Large" veya "Fail"). passes alanı, herhangi bir WCAG seviyesi karşılandığında true değerini alır — basit yeşil/kırmızı gösterge için kullanışlıdır.
Kontrast Hesaplama
def relative_luminance(hex_code: str) -> float:
r, g, b = hex_to_rgb(hex_code)
def linearize(v: int) -> float:
s = v / 255
return s / 12.92 if s <= 0.04045 else ((s + 0.055) / 1.055) ** 2.4
return 0.2126 * linearize(r) + 0.7152 * linearize(g) + 0.0722 * linearize(b)
def contrast_ratio(hex1: str, hex2: str) -> float:
L1 = relative_luminance(hex1)
L2 = relative_luminance(hex2)
lighter = max(L1, L2)
darker = min(L1, L2)
return round((lighter + 0.05) / (darker + 0.05), 2)
def wcag_result(ratio: float) -> dict:
return {
"aa_normal": ratio >= 4.5,
"aa_large": ratio >= 3.0,
"aaa_normal": ratio >= 7.0,
"aaa_large": ratio >= 4.5,
}
Erişilebilir Alternatifler Önermek
Kullanışlı bir uzantı: arka plana karşı kontrastı geçemeyen bir ön plan rengi verildiğinde, WCAG AA'yı elde eden minimum parlaklık ayarını önerin:
def suggest_accessible_foreground(fg_hex: str, bg_hex: str, target_ratio: float = 4.5) -> str:
"""Hedef oranı geçen fg_hex'in parlaklık ayarlı versiyonunu döndür."""
hsl = rgb_to_hsl(*hex_to_rgb(fg_hex))
bg_lum = relative_luminance(bg_hex)
is_dark_bg = bg_lum < 0.179
step = -2 if is_dark_bg else 2 # Açık arka planda koyulaştır, koyu arka planda aydınlat
current_l = hsl[2]
for _ in range(50):
current_l = max(0, min(100, current_l + step))
adjusted_hex = hsl_to_hex(hsl[0], hsl[1], current_l)
ratio = contrast_ratio(adjusted_hex, bg_hex)
if ratio >= target_ratio:
return adjusted_hex
return '#000000' if not is_dark_bg else '#FFFFFF'
Renk API'leri için Hız Sınırlaması
Renk API'lerinin Neden Hız Sınırlamasına İhtiyacı Var
Renk API'leri düşük riskli görünebilir, ancak şu saldırıların hedefi olabilirler: - Numaralandırma saldırıları: Tam renk adı veritabanını elde etmek için 16,7 milyon hex kodunu yinelemek. - Kazıma: Dönüşüm mantığınızı ücretsiz bir hesaplama kaynağı olarak kullanmak. - Kötüye kullanım: Diğerleri için hizmet kalitesini düşüren tek bir istemciden yüksek hacimli istekler.
Uygulama Stratejisi
Django API için django-ratelimit, Redis arka ucuyla dekoratör tabanlı hız sınırlaması sağlar:
# settings.py
RATELIMIT_USE_CACHE = 'default' # Django'nun önbellek arka ucunu kullanır (Redis önerilir)
# views.py
from django_ratelimit.decorators import ratelimit
@ratelimit(key='ip', rate='100/m', method='GET', block=True)
def color_detail_view(request, hex_code: str):
...
Hız Sınırı Yanıt Formatı
Hız sınırı aşıldığında, net bir yanıt gövdesi ve Retry-After başlığıyla 429 Too Many Requests döndürün:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1708012345
Content-Type: application/json
{
"error": "rate_limit_exceeded",
"message": "Dakikada 100 istek hız sınırını aştınız.",
"retry_after": 60
}
Kademeli Hız Sınırları
Makul bir kademeli yapı:
| Kademe | Sınır | Anahtar |
|---|---|---|
| Anonim | 60 istek / dakika | IP adresi |
| API anahtarı (ücretsiz) | 300 istek / dakika | API anahtarı |
| API anahtarı (ücretli) | 3000 istek / dakika | API anahtarı |
API anahtarları Authorization: Bearer {key} veya X-API-Key: {key} olarak iletilir. Kimliği doğrulanmış istekler için API anahtarını hız sınırı anahtarı olarak kullanın:
@ratelimit(key='header:x-api-key', rate='300/m', method='GET')
@ratelimit(key='ip', rate='60/m', method='GET')
def color_detail_view(request, hex_code: str):
# django-ratelimit her ikisini de kontrol eder; kimliği doğrulanmış istekler için daha geniş sınır kazanır
...
Yanıt Formatı En İyi Uygulamaları
Tutarlı Hata Şeması
Her hata yanıtı — doğrulama hatası, hız sınırı, bulunamadı — aynı şemayı izlemelidir:
{
"error": "invalid_hex",
"message": "'gggggg' değeri geçerli bir hex rengi değil. 3 veya 6 basamaklı hex dizesi bekleniyor.",
"field": "hex_code",
"value": "gggggg"
}
| Alan | Amaç |
|---|---|
error |
Makine tarafından okunabilir hata kodu (snake_case) |
message |
İnsan tarafından okunabilir açıklama |
field |
Hataya neden olan giriş alanı (doğrulama hataları için) |
value |
Geçersiz değer (hata ayıklamaya yardımcı olur) |
Koleksiyon Uç Noktaları için Sayfalandırma
limit ve offset ile arama uç noktası:
{
"results": [...],
"pagination": {
"total": 47,
"limit": 10,
"offset": 0,
"next": "/api/search?q=blue&limit=10&offset=10",
"prev": null
}
}
Her zaman total ekleyin, böylece istemciler tam sonuç kümesini bilmeden sayfalandırma kontrollerini gösterebilir.
Sürümleme Stratejisi
API'nizi bir başlıkta değil URL yolunda sürümleyin. URL sürümlemesi açık, CDN'ler tarafından önbelleğe alınabilir ve istemcilerin özel başlıklar ayarlamasını gerektirmez:
/api/v1/color/FF5733 # Sürüm 1
/api/v2/color/FF5733 # Sürüm 2 (büyük değişiklikler gerektiğinde)
Büyük sürüm yayınından sonra en az bir yıl boyunca önceki sürümleri koruyun. Eski sürümlerde kullanımdan kaldırma başlıkları kullanın:
Deprecation: Sun, 01 Jan 2026 00:00:00 GMT
Sunset: Sun, 01 Jan 2027 00:00:00 GMT
Link: </api/v2/color/FF5733>; rel="successor-version"
CORS Yapılandırması
Tarayıcı istemcileri tarafından tüketilen genel bir API için:
# settings.py (django-cors-headers kullanarak)
CORS_ALLOWED_ORIGINS = [
"https://yoursite.com",
"https://app.yoursite.com",
]
# Veya tamamen genel bir API için:
CORS_ALLOW_ALL_ORIGINS = True
# Her zaman yöntemleri ve başlıkları kısıtlayın
CORS_ALLOW_METHODS = ['GET', 'POST', 'OPTIONS']
CORS_ALLOW_HEADERS = ['Content-Type', 'Authorization', 'X-API-Key']
Önbellek Mimarisi
Renk verisi yüksek oranda önbelleğe alınabilir. #FF5733 için renk nesnesi hiçbir zaman değişmez — dönüşüm matematiği belirleyicidir. Önbellek stratejinizi buna göre yapılandırın:
| Uç Nokta | Cache-Control | CDN TTL |
|---|---|---|
/api/color/{hex} |
public, max-age=86400, stale-while-revalidate=604800 |
1 gün |
/api/search?q={q} |
public, max-age=3600 |
1 saat |
/api/contrast?fg=X&bg=Y |
public, max-age=86400 |
1 gün |
/api/palette/{hex} |
public, max-age=86400 |
1 gün |
Koşullu istekler için hex koduna dayalı bir ETag başlığı ekleyin:
response["ETag"] = f'"{hex_code}"'
response["Last-Modified"] = "Thu, 01 Jan 2026 00:00:00 GMT" # Statik — içerik hiçbir zaman değişmez
If-None-Match: "FF5733" gönderen istemciler, gövde olmadan 304 Not Modified yanıtı alır — tekrarlanan isteklerde bant genişliğinden tasarruf edilir.
Temel Çıkarımlar
- Kanonik renk nesnesi, istemcilerin farklı formatları almak için birden fazla istek yapmasına gerek kalmadan tüm format gösterimlerini (hex, RGB, HSL, CMYK, OKLCH) tek bir yanıtta içermelidir.
- Hex girişini agresif biçimde normalleştirin:
#kaldırın, 3 basamaklıyı genişletin, büyük harfe dönüştürün. Herhangi bir işlemden önce regex ile doğrulayın. - Kontrast uç noktası herhangi bir erişilebilirlik aracının çekirdeğidir — WCAG oranlarını, seviye başına geçti/kaldı durumunu ve tek bir yanıtta en yüksek geçen seviyeyi döndürün.
- Adlandırılmış renk araması küçük veritabanları için bellek içi önek aramasıyla güvenilir biçimde çalışır; büyük olanlar için PostgreSQL
pg_trgmkullanın. - Kimliği doğrulanmamış istekler için IP'ye göre hız sınırı uygulayın (60/dakika makuldür); daha yüksek katmanlar için API anahtarları kullanın.
- Her hata yanıtı en azından
error(makine tarafından okunabilir) vemessage(insan tarafından okunabilir) içeren aynı şemayı izlemelidir. - Renk verisi yüksek oranda önbelleğe alınabilir — dönüşüm uç noktaları için 24 saatlik CDN önbelleği uygundur; verimli önbellek geçersiz kılma için
ETagvestale-while-revalidatekullanın. - Bu API uç noktalarını çalışırken görmek için Renk Dönüştürücü ve Kontrast Denetleyici'yi deneyin.