Takip et

Neden Dinamik Bir Sidebar’a İhtiyaç Duyarız?

Docusaurus Benzeri FastAPI Sitesinde Dinamik Sidebar Oluşturma Rehberi

Modern dokümantasyon siteleri, kullanıcıların aradıkları bilgiye hızlıca ulaşmalarını sağlayan, iyi düzenlenmiş ve etkileşimli sidebar (kenar çubuğu) navigasyonuna sahiptir. Docusaurus gibi popüler statik site üreticileri bu konuda standartları belirlerken, FastAPI ile dinamik bir web sitesi geliştirirken benzer bir deneyimi nasıl sunabiliriz? Bu makalede, FastAPI ve Jinja2 kullanarak, dosya sistemi tabanlı veya yapılandırma dosyaları üzerinden dinamik olarak oluşturulan, Docusaurus benzeri bir sidebar yapısını adım adım inşa edeceğiz. Bu sayede, projenizin dokümantasyonunu yönetmek ve kullanıcılarınıza kesintisiz bir gezinme deneyimi sunmak artık çok daha kolay olacak. Hazır mısınız?


Günümüzün hızla değişen yazılım dünyasında, projelerin dokümantasyonu da sürekli güncellenme ihtiyacı hisseder. Manuel olarak yönetilen statik HTML sayfalarındaki navigasyon menüleri, her değişiklikte tek tek güncellenmesi gereken bir kabusa dönüşebilir. Özellikle büyük ve çok sayıda sayfa içeren dokümantasyon sitelerinde, bu durum geliştiriciler için ciddi bir zaman kaybı ve hata kaynağıdır. İşte bu noktada dinamik bir sidebar çözümü devreye girer. Peki, bu dinamik yaklaşım bize ne gibi avantajlar sunar?

Öncelikle, bakım kolaylığı en büyük artıdır. Yeni bir doküman sayfası eklediğinizde veya mevcut bir sayfayı sildiğinizde, sidebar’ınız otomatik olarak güncellenir. Bu, geliştiricilerin sadece içerik oluşturmaya odaklanmasını sağlar ve navigasyon elementleriyle uğraşma yükünü ortadan kaldırır. Bu durum, özellikle çevik geliştirme metodolojileri uygulayan ekipler için hayati önem taşır; zira içerik ve yapılandırma arasındaki ayrım netleşir, geliştirme süreçleri hızlanır.

İkinci olarak, tutarlılık sağlar. Tüm dokümantasyon sayfalarınızda aynı navigasyon yapısının kullanılması, kullanıcı deneyimi açısından kritik öneme sahiptir. Dinamik sidebar, tutarlı bir gezinme hiyerarşisi oluşturarak kullanıcıların sitenizde kaybolmasını engeller ve bilgiyi daha kolay bulmalarına yardımcı olur. Ayrıca, markanızın veya projenizin genel görsel kimliğini yansıtan tek tip bir arayüz sunar.

Üçüncü bir avantaj ise ölçeklenebilirliktir. Projeniz büyüdükçe ve dokümantasyonunuz genişledikçe, dinamik bir sistem bu büyümeye rahatlıkla ayak uydurabilir. Yüzlerce sayfa barındıran kompleks dokümantasyon siteleri bile, iyi tasarlanmış dinamik bir yapıyla kolayca yönetilebilir. Bu durum, uzun vadeli projeler için olmazsa olmaz bir özelliktir. Ek olarak, içerik yönetimi için farklı kaynaklardan (veritabanı, API’ler, farklı dosya türleri) veri çekme yeteneği sunar, bu da statik çözümlerle mümkün olmayan bir esneklik sağlar.

Son olarak, esneklik ve özelleştirme imkanları sunar. Sidebar’ınızın görünümünü ve davranışını merkezi bir yerden, genellikle bir yapılandırma dosyası (YAML veya JSON) aracılığıyla veya dosya sisteminin kendisini tarayarak kolayca değiştirebilirsiniz. Bu sayede, farklı kullanıcı grupları veya farklı bağlamlar için özelleştirilmiş navigasyon menüleri oluşturmak mümkün hale gelir. Örneğin, belirli rollerdeki kullanıcılar için farklı menü öğeleri gösterebilir veya projenin farklı versiyonlarına özel navigasyonlar sunabilirsiniz. Bu tür dinamik özelleştirmeler, kullanıcı deneyimini zenginleştirirken aynı zamanda geliştiricilere de büyük bir kontrol sağlar.

Peki, Docusaurus gibi araçlar bunu zaten yaparken, neden FastAPI ile kendi çözümümüzü inşa etmeliyiz? Docusaurus harika bir araçtır, ancak bazen daha fazla esnekliğe, özel bir arka uç entegrasyonuna veya sadece Python ekosistemi içinde kalma isteğine ihtiyacımız olabilir. Özellikle dokümantasyonunuz bir web uygulamasıyla iç içe geçmişse veya içeriği dinamik olarak bir veritabanından çekmek gibi daha karmaşık gereksinimleriniz varsa, FastAPI ile kendi çözümünüzü oluşturmak size tam kontrol sağlayacaktır. Bu yaklaşım, dokümantasyonunuzu bir statik site sınırlarının ötesine taşıyarak, API entegrasyonları, kullanıcı kimlik doğrulaması veya kişiselleştirilmiş içerik sunumu gibi özelliklerle zenginleştirme potansiyeli sunar. Kısacası, kontrolün tamamen sizde olduğu, projenizin özel ihtiyaçlarına göre şekillenebilen bir çözüm inşa etmek istiyorsanız, doğru yerdesiniz.

Sidebar Oluşturma Sürecinin Temel Kavramları ve Mimarisi

FastAPI ile Docusaurus benzeri bir sidebar oluşturmak, aslında birkaç temel teknolojinin ve yaklaşımın birleşimini gerektirir. Bu süreçte neler kullanacağımızı ve genel mimarinin nasıl işleyeceğini anlamak, adımları daha kolay takip etmenizi sağlayacaktır. Temelde, bir “yapılandırma” katmanı, bir “işleme” katmanı ve bir “sunum” katmanından bahsedebiliriz.

Yapılandırma Katmanı: İçeriğimizi Nasıl Tanımlarız?

Docusaurus gibi sistemler genellikle Markdown dosyalarını ve bunların dizin yapısını otomatik olarak algılayarak veya _category_.json, sidebar.js gibi yapılandırma dosyalarıyla çalışır. Bizim de benzer bir yaklaşıma ihtiyacımız var. İçeriğimizin (dokümanlarımızın) hangi sırayla ve hangi başlıklar altında sidebar’da görüneceğini belirlemeliyiz. Bunun için iki yaygın yöntem izlenebilir:

  1. Dosya Sistemi Tabanlı Yapılandırma: Dokümanlarınızı belirli bir klasör yapısı içinde tutarsınız (örneğin, docs/getting_started/introduction.md, docs/features/feature_x.md). FastAPI uygulamamız, bu klasör yapısını tarar ve her bir Markdown dosyasını bir sidebar öğesi olarak algılar. Klasör isimleri kategorileri, dosya isimleri ise sayfaları temsil edebilir. Bu yöntem, özellikle dosya tabanlı bir içerik yönetimi tercih edenler için oldukça pratik ve sürdürülebilirdir. Ancak, öğelerin sırasını veya başlıklarını dosya adlarından bağımsız olarak kontrol etmek istediğinizde sınırlayıcı olabilir.
  2. Harici Yapılandırma Dosyası (YAML/JSON): Sidebar’ınızın tüm yapısını (kategoriler, alt kategoriler, sayfalar ve bunların sırası) bir YAML veya JSON dosyası içinde açıkça tanımlarsınız (örneğin, sidebar.yaml). Bu dosya, uygulamanız tarafından okunur ve sidebar bu tanıma göre inşa edilir. Bu yöntem, dosya sistemi yapısından bağımsız olarak daha esnek bir sıralama ve başlıklandırma kontrolü sağlar. Ayrıca, tek bir merkezden sidebar’ın tüm görünümünü ve içeriğini yönetme imkanı sunar.

Biz bu makalede ikinci yönteme, yani harici bir YAML yapılandırma dosyasına odaklanacağız çünkü bu, daha esnek ve Docusaurus’un “sidebar.js” mantığına daha yakın bir kontrol sunar. YAML, hem okunabilirliği hem de hiyerarşik veri tanımlama yeteneği sayesinde bu tür yapılandırmalar için idealdir.

İşleme Katmanı: FastAPI ve Python’ın Gücü

Yapılandırma dosyamızı veya dosya sistemimizi okuduktan sonra, bu ham veriyi HTML’e dönüştürebileceğimiz anlamlı bir Python veri yapısına çevirmemiz gerekir. İşte burada FastAPI’nin gücünü kullanacağız:

  • Dosya Okuma ve Ayrıştırma: FastAPI uygulamamız, sidebar.yaml dosyasını okuyacak ve içeriğini Python objelerine (listeler, dictionary’ler) dönüştürecek. Python’ın yaml kütüphanesi bu işlem için biçilmiş kaftandır.
  • Veri Yapısının Oluşturulması: Okunan yapılandırmaya göre, her bir sidebar öğesi için uygun bir veri modeli (örneğin, SidebarItem adında bir Pydantic modeli) oluşturabiliriz. Bu modeller, öğenin başlığını, URL’sini, alt öğelerini (eğer varsa) ve diğer metadata’sını içerecektir. Bu adım, hem veriyi düzenli tutar hem de tip güvenliği sağlar.
  • İçerik Yönetimi (Markdown): Sidebar öğelerinin işaret ettiği gerçek doküman içerikleri genellikle Markdown dosyalarıdır. Uygulamamız, bu Markdown dosyalarını okumalı ve HTML’e çevirmelidir. python-markdown veya markdown-it-py gibi kütüphaneler bu dönüşüm için kullanılabilir. Bu sayede, yazarlar sadece Markdown ile içerik oluştururken, web arayüzünde bu içerik otomatik olarak zengin HTML’e dönüştürülür.

Sunum Katmanı: Jinja2 ile HTML Oluşturma

FastAPI doğrudan HTML üretmek yerine, genellikle şablon motorlarıyla entegre çalışır. Jinja2, Python dünyasında en popüler ve güçlü şablon motorlarından biridir. İşte nasıl kullanacağımız:

  • Şablon Yükleme: FastAPI, Jinja2 şablonlarını belirli bir klasörden (örneğin, templates) yükleyecek şekilde yapılandırılabilir.
  • Dinamik HTML Oluşturma: İşleme katmanında hazırladığımız Python veri yapısını (sidebar menü öğeleri ve doküman içeriği), bir Jinja2 şablonuna (örneğin, base.html veya docs.html) parametre olarak göndereceğiz.
  • Sidebar’ın Render Edilmesi: Jinja2 şablonu, bu veri yapısını kullanarak dinamik olarak bir
      ve
    • etiketlerinden oluşan bir sidebar menüsü oluşturacak. Bu şablon içinde döngüler (for loop), koşullu ifadeler (if statement) ve değişkenler kullanılarak kompleks menü yapıları inşa edilebilir. Ayrıca, ana içerik alanı için de Markdown’dan dönüştürülen HTML içeriği buraya yerleştirilecektir. Bu sayede, tüm sayfanın HTML yapısı tek bir yerden yönetilirken, sidebar ve içerik dinamik olarak değişebilir.

    Bu üç katmanı bir araya getirerek, sadece birkaç dosya değişikliğiyle otomatik olarak güncellenen, güçlü ve esnek bir dokümantasyon sitesi navigasyonu oluşturabiliriz. Bu mimari, modülerliği ve ayrımı destekleyerek projenizi daha sürdürülebilir hale getirir. Şimdi bu teorik bilgiyi pratiğe dökme zamanı!

    Adım 1: Proje Yapısını Oluşturma ve Gerekli Kütüphaneleri Kurma

    Her büyük projenin temelinde sağlam bir yapılandırma yatar. Docusaurus benzeri bir dokümantasyon sitesi oluştururken de benzer bir yaklaşıma ihtiyacımız var. İlk adım olarak, projemizin temel dizin yapısını oluşturalım ve gerekli Python kütüphanelerini kuralım. Bu adım, daha sonraki geliştirmeler için düzenli ve anlaşılır bir temel sağlayacaktır.

    Proje Dizini Yapısı

    Aşağıdaki gibi bir dizin yapısı, hem dokümantasyon içeriğimizi hem de FastAPI uygulamamızın kodunu düzenli bir şekilde barındırmamızı sağlar:

    
    fastapi-docs-site/
    ├── docs/
    │   ├── getting-started/
    │   │   ├── introduction.md
    │   │   └── installation.md
    │   ├── features/
    │   │   ├── feature-x.md
    │   │   └── feature-y.md
    │   └── _category_.yaml  # İsteğe bağlı, kategoriler için metadata
    ├── templates/
    │   ├── base.html
    │   └── doc_page.html
    ├── static/
    │   ├── css/
    │   │   └── style.css
    │   └── js/
    │       └── main.js
    ├── sidebar.yaml
    ├── main.py
    ├── requirements.txt
    └── .gitignore
    

    Bu yapıyı biraz açalım:

    • fastapi-docs-site/: Projemizin ana dizini.
    • docs/: Tüm Markdown dokümanlarımızın bulunduğu ana klasör. İçindeki alt klasörler (örneğin, getting-started, features) doğrudan sidebar kategorilerini temsil edebilir veya yapılandırma dosyamızda referans göstereceğimiz gruplamaları oluşturur. Her bir .md dosyası, tek bir doküman sayfasına karşılık gelir.
    • templates/: Jinja2 şablon dosyalarımızın yer alacağı dizin. base.html genel sayfa yapımızı (header, footer, sidebar konteyneri vb.) tanımlarken, doc_page.html spesifik olarak doküman içeriğinin nasıl yerleştirileceğini ve base.html'i nasıl genişleteceğini belirler.
    • static/: CSS, JavaScript ve resimler gibi statik dosyalarımızın bulunduğu dizin. Bu dosyalar doğrudan tarayıcı tarafından erişilebilir olacaktır.
    • sidebar.yaml: Sidebar'ımızın yapısını ve içeriğini tanımlayacağımız YAML yapılandırma dosyası. Bu dosya, docs/ klasöründeki içeriğin nasıl gruplandırılacağını ve hangi sırada gösterileceğini belirleyecek.
    • main.py: FastAPI uygulamamızın ana kodu, rotaları ve mantığı burada yer alacak.
    • requirements.txt: Projemizin bağımlılıklarını listeleyen dosya.
    • .gitignore: Git versiyon kontrol sistemi tarafından görmezden gelinecek dosyaları belirler (örneğin, sanal ortamlar, geçici dosyalar).

    Gerekli Kütüphaneleri Kurma

    Projemizin çalışabilmesi için birkaç temel Python kütüphanesine ihtiyacımız var. Bu kütüphaneler, FastAPI uygulamasını çalıştırmak, Jinja2 şablonlarını işlemek, YAML yapılandırmalarını okumak ve Markdown içeriğini HTML'e dönüştürmek için kullanılacak. requirements.txt dosyanızı aşağıdaki gibi oluşturabilirsiniz:

    
    fastapi==0.111.0
    uvicorn==0.29.0
    Jinja2==3.1.4
    PyYAML==6.0.1
    markdown==3.6
    python-multipart==0.0.9 # FastAPI'nin form verilerini işlemesi için gerekli olabilir
    

    Daha sonra, bu bağımlılıkları bir sanal ortamda (virtual environment) kurmak en iyi uygulamadır. Böylece projenizin bağımlılıkları sisteminizdeki diğer Python projelerinden izole edilmiş olur:

    
    # Sanal ortam oluşturma
    python -m venv venv
    
    # Sanal ortamı etkinleştirme (Linux/macOS)
    source venv/bin/activate
    
    # Sanal ortamı etkinleştirme (Windows)
    .\venv\Scripts\activate
    
    # Bağımlılıkları kurma
    pip install -r requirements.txt
    

    Bu komutlar, projeniz için gerekli tüm araçları yükleyecek ve geliştirme ortamınızı hazırlayacaktır. Artık temel altyapımız hazır olduğuna göre, bir sonraki adımda sidebar yapılandırma dosyamızı oluşturmaya geçebiliriz. Bu düzenli kurulum, gelecekteki olası sorunları minimize eder ve projenizi daha yönetilebilir kılar. Bu sayede, içerik geliştirmeye ve uygulamanın mantığına daha fazla odaklanabilirsiniz.

    Adım 2: Sidebar Yapılandırmasını Tanımlama (sidebar.yaml ile)

    Dinamik sidebar'ımızın kalbi, onun nasıl görüneceğini ve hangi sayfaları içereceğini belirleyen yapılandırma dosyasıdır. Docusaurus'un sidebar.js dosyalarına benzer şekilde, biz de bir sidebar.yaml dosyası kullanarak bu yapıyı tanımlayacağız. YAML, hiyerarşik verileri insan tarafından okunabilir bir formatta ifade etmek için idealdir ve bu nedenle dokümantasyon yapılandırması için mükemmel bir seçimdir.

    sidebar.yaml Dosyasının Yapısı

    sidebar.yaml dosyasının, dokümanlarınızın mantıksal gruplamalarını ve bu gruplar içindeki sayfaların sırasını net bir şekilde belirtmesi gerekmektedir. İşte örnek bir sidebar.yaml içeriği:

    
    - type: category
      label: Başlangıç
      collapsible: true
      collapsed: false
      items:
        - type: doc
          id: getting-started/introduction
          label: Giriş
        - type: doc
          id: getting-started/installation
          label: Kurulum
        - type: doc
          id: getting-started/first-steps
          label: İlk Adımlar
    
    - type: category
      label: Özellikler
      collapsible: true
      collapsed: true
      items:
        - type: doc
          id: features/feature-x
          label: X Özelliği
        - type: doc
          id: features/feature-y
          label: Y Özelliği
    
    - type: link
      label: Harici Bağlantı
      href: https://fastapi.tiangolo.com/
      target: _blank
    
    - type: doc
      id: legal/privacy-policy
      label: Gizlilik Politikası
    

    Bu yapılandırma dosyasını daha yakından inceleyelim:

    • Her bir ana öğe, bir kategori, doküman veya harici bir bağlantı olabilir. Bu, type anahtarıyla belirtilir.
    • type: category: Bir grup dokümanı temsil eder.
      • label: Sidebar'da görünecek kategori başlığı.
      • collapsible: (İsteğe bağlı, varsayılan true) Kategorinin genişletilebilir/daraltılabilir olup olmadığını belirler.
      • collapsed: (İsteğe bağlı, varsayılan true) Sayfa yüklendiğinde kategorinin varsayılan olarak daraltılmış mı (true) yoksa açık mı (false) olacağını belirtir.
      • items: Bu kategoriye ait olan dokümanları veya alt kategorileri içeren bir liste.
    • type: doc: Tek bir doküman sayfasını temsil eder.
      • id: Doküman dosyasının docs/ klasörü içindeki yolunu belirtir, ancak .md uzantısı olmadan. Örneğin, getting-started/introduction ID'si, docs/getting-started/introduction.md dosyasına karşılık gelir. Bu ID aynı zamanda URL yolu olarak da kullanılacaktır (örn. /docs/getting-started/introduction).
      • label: Sidebar'da görünecek doküman başlığı.
    • type: link: Harici bir web sitesine yönlendiren bir bağlantıyı temsil eder.
      • label: Sidebar'da görünecek bağlantı başlığı.
      • href: Bağlantının yönlendireceği URL.
      • target: (İsteğe bağlı) Bağlantının yeni bir sekmede açılıp açılmayacağını belirler (örneğin, _blank).

    Doküman İçerik Dosyalarını Oluşturma

    Yukarıdaki sidebar.yaml dosyasıyla eşleşecek şekilde, docs/ klasörünüzde bazı Markdown dosyaları oluşturmalısınız. Örneğin:

    docs/getting-started/introduction.md

    
    # Hoş Geldiniz!
    
    Bu, projemizin başlangıç dokümantasyonudur. Amacımız, sizi hızlıca alıştırmak ve projenin temel prensiplerini anlamanızı sağlamaktır.
    
    Projemiz Hakkında
    
    Bu proje, modern web uygulamaları geliştirmek için tasarlanmış bir araç setidir.
    
    İlgili Bağlantılar:
    - [Kurulum](/docs/getting-started/installation)
    

    docs/getting-started/installation.md

    
    # Kurulum Rehberi
    
    Projemizi bilgisayarınıza kurmak için aşağıdaki adımları izleyin:
    
    1. Python 3.9 veya üzeri yüklü olduğundan emin olun.
    2. Proje dizinine gidin ve bağımlılıkları yükleyin:
       
    pip install -r requirements.txt

    3. Uygulamayı başlatın:

    uvicorn main:app --reload

    Gereksinimler

    - Python 3.9+
    - FastAPI
    - Uvicorn

    Bu .md dosyalarının her biri, sidebar.yaml'deki id alanlarıyla eşleşen yollarda yer almaktadır. Markdown dosyalarınızın başlıkları (örneğin, # Hoş Geldiniz!) genellikle sayfa içinde görünürken, sidebar'da gösterilecek başlıklar sidebar.yaml'deki label alanından gelecektir. Bu ayrım, hem SEO dostu URL'ler oluşturmanıza hem de kullanıcı dostu menü başlıkları kullanmanıza olanak tanır.

    Bu yapılandırma, dokümantasyonunuzun hem statik yapısını hem de dinamik gezinme mantığını belirler. Bir sonraki adımda, FastAPI uygulamamızın bu YAML dosyasını nasıl okuyacağını ve işleyeceğini inceleyeceğiz. Bu adım, statik yapılandırmayı dinamik bir Python nesnesine dönüştürmenin ve web uygulamamızın anlayabileceği bir formata getirmenin temelini oluşturur.

    Adım 3: FastAPI ile Yapılandırmayı Okuma ve İşleme

    Şimdi sıra, oluşturduğumuz sidebar.yaml dosyasını FastAPI uygulamamız içinde kullanışlı bir veri yapısına dönüştürmeye geldi. Bu adımda Python'ın yaml kütüphanesini kullanarak dosyayı okuyacak, ardından bu veriyi FastAPI'nin Jinja2 şablonlarına aktarabileceği bir formata getireceğiz. Ayrıca, Markdown dokümanlarını HTML'e çevirme işlevini de bu bölümde ele alacağız.

    YAML Yapılandırmasını Yükleme Fonksiyonu

    Öncelikle, main.py dosyanıza YAML dosyasını okuyacak bir yardımcı fonksiyon ekleyelim:

    
    # main.py
    
    import yaml
    from pathlib import Path
    from markdown import markdown
    from fastapi import FastAPI, Request
    from fastapi.responses import HTMLResponse
    from fastapi.staticfiles import StaticFiles
    from fastapi.templating import Jinja2Templates
    
    # Projenin kök dizini
    BASE_DIR = Path(__file__).resolve().parent
    
    # YAML dosyasını yükleme fonksiyonu
    def load_sidebar_config(config_path: Path):
        with open(config_path, 'r', encoding='utf-8') as file:
            return yaml.safe_load(file)
    
    # Markdown'ı HTML'e çevirme fonksiyonu
    def convert_markdown_to_html(md_path: Path) -> str:
        with open(md_path, 'r', encoding='utf-8') as file:
            md_content = file.read()
        return markdown(md_content, extensions=['fenced_code', 'tables', 'attr_list'])
    
    # FastAPI uygulamasını başlat
    app = FastAPI()
    
    # Statik dosyaları bağla (CSS, JS vb.)
    app.mount("/static", StaticFiles(directory=BASE_DIR / "static"), name="static")
    
    # Jinja2 şablonlarını yükle
    templates = Jinja2Templates(directory=BASE_DIR / "templates")
    
    # Sidebar yapılandırmasını yükle
    try:
        sidebar_config = load_sidebar_config(BASE_DIR / "sidebar.yaml")
    except FileNotFoundError:
        print("Hata: sidebar.yaml dosyası bulunamadı. Lütfen kontrol edin.")
        sidebar_config = [] # Boş liste ile devam et
    except Exception as e:
        print(f"Hata: sidebar.yaml yüklenirken bir sorun oluştu: {e}")
        sidebar_config = []
    

    Bu kod bloğunda:

    • BASE_DIR: Projenizin kök dizinini belirler. Bu, tüm dosya yollarının göreceli olarak yönetilmesini kolaylaştırır.
    • load_sidebar_config: Verilen yoldaki YAML dosyasını okur ve Python'ın sözlük/liste yapısına dönüştürür. Hata yönetimi de eklenmiştir.
    • convert_markdown_to_html: Belirtilen yoldaki Markdown dosyasını okur ve markdown kütüphanesi kullanarak HTML'e dönüştürür. extensions parametresi, daha zengin Markdown özelliklerini (kod blokları, tablolar vb.) desteklemek için önemlidir.
    • app = FastAPI(): Uygulamamızı başlatır.
    • app.mount("/static", ...): static/ klasörümüzdeki CSS ve JS gibi dosyaları /static URL yolu üzerinden erişilebilir kılar.
    • templates = Jinja2Templates(...): Jinja2 şablon motorumuzu templates/ klasörümüzü işaret ederek başlatır.
    • sidebar_config = load_sidebar_config(...): Uygulama başlatılırken sidebar.yaml dosyasını yükler ve sidebar_config değişkeninde tutarız. Bu sayede her istekte dosyayı okumak zorunda kalmayız.

    Doküman Sayfaları için FastAPI Rotası

    Şimdi, /docs/ prefix'i altındaki tüm doküman sayfalarını dinamik olarak işleyecek bir FastAPI rotası tanımlayalım. Bu rota, URL'deki doküman ID'sini alacak, ilgili Markdown dosyasını bulacak, onu HTML'e çevirecek ve Jinja2 şablonuna gönderecektir.

    
    # main.py dosyasına ekleyin
    
    @app.get("/docs/{doc_id:path}", response_class=HTMLResponse)
    async def read_doc(request: Request, doc_id: str):
        """
        Dinamik olarak doküman sayfalarını yükler ve render eder.
        doc_id: URL'deki doküman yolu (örn. getting-started/introduction)
        """
        doc_path = BASE_DIR / "docs" / f"{doc_id}.md"
    
        if not doc_path.is_file():
            # Eğer dosya yoksa 404 hatası döndür
            return templates.TemplateResponse(
                "404.html",
                {"request": request, "sidebar_config": sidebar_config, "title": "Sayfa Bulunamadı"},
                status_code=404
            )
    
        # Markdown içeriğini HTML'e çevir
        doc_content_html = convert_markdown_to_html(doc_path)
    
        # Sayfa başlığını Markdown dosyasının ilk H1 başlığından veya doc_id'den al
        # Daha sofistike bir başlık çekme mekanizması kurulabilir.
        # Şimdilik, sadece doc_id'yi kullanabiliriz veya Markdown içeriğinden ilk H1'i parse edebiliriz.
        first_h1_match = next((line for line in doc_content_html.split('\n') if line.strip().startswith('

    ')), None) page_title = doc_id.replace('-', ' ').replace('/', ' ').title() # Varsayılan başlık if first_h1_match: #

    ve

    etiketlerini temizle page_title = first_h1_match.replace("

    ", "").replace("

    ", "").strip() # Jinja2 şablonunu render et return templates.TemplateResponse( "doc_page.html", { "request": request, "sidebar_config": sidebar_config, "doc_content": doc_content_html, "current_doc_id": doc_id, # Aktif sayfayı işaretlemek için "title": page_title } ) @app.get("/", response_class=HTMLResponse) async def read_root(request: Request): """ Ana sayfa yönlendirmesi veya varsayılan bir başlangıç sayfası. """ # İsteğe bağlı olarak, ana sayfadan direkt ilk dokümana yönlendirebilirsiniz. if sidebar_config and sidebar_config[0].get('type') == 'category' and sidebar_config[0].get('items'): first_doc_id = sidebar_config[0]['items'][0]['id'] return templates.TemplateResponse( "doc_page.html", { "request": request, "sidebar_config": sidebar_config, "doc_content": convert_markdown_to_html(BASE_DIR / "docs" / f"{first_doc_id}.md"), "current_doc_id": first_doc_id, "title": sidebar_config[0]['items'][0]['label'] } ) return templates.TemplateResponse( "home.html", # Eğer home.html yoksa, doc_page.html'i kullanıp boş içerik geçebilirsiniz {"request": request, "sidebar_config": sidebar_config, "title": "Ana Sayfa", "doc_content": "

    Hoş Geldiniz!

    Lütfen soldaki menüden bir doküman seçin.

    "} )

    Bu rotada yapılanlar:

    • @app.get("/docs/{doc_id:path}", ...): /docs/ ile başlayan ve sonrasında herhangi bir yola sahip olan tüm istekleri yakalar. {doc_id:path} kısmı, / karakterlerini de içeren bir yolu doc_id değişkenine atamamızı sağlar.
    • doc_path = BASE_DIR / "docs" / f"{doc_id}.md": Gelen doc_id ile docs/ klasöründeki ilgili Markdown dosyasının tam yolunu oluşturur.
    • if not doc_path.is_file(): Dosyanın gerçekten var olup olmadığını kontrol eder. Yoksa, bir 404 (Sayfa Bulunamadı) şablonu döndürülür.
    • doc_content_html = convert_markdown_to_html(doc_path): Markdown dosyasını HTML'e çevirir.
    • page_title = ...: Sayfa başlığını, URL'den veya Markdown içeriğindeki ilk H1 etiketinden dinamik olarak alır. Bu, tarayıcı sekmesinde veya sayfa içinde doğru başlığın görüntülenmesi için önemlidir.
    • return templates.TemplateResponse(...): doc_page.html şablonunu render ederken, request objesini, sidebar_config (menü için), doc_content (ana içerik için), current_doc_id (aktif menü öğesini işaretlemek için) ve title değişkenlerini şablona gönderir.
    • @app.get("/"): Ana sayfa isteğini karşılar. Varsayılan olarak ilk dokümanı yüklemeyi veya basit bir karşılama sayfası göstermeyi seçebilirsiniz.

    Bu adımlarla, FastAPI uygulamamız artık YAML yapılandırmasını okuyabiliyor ve doküman içeriğini işleyip HTML'e çevirebiliyor. Sırada, bu veriyi kullanarak dinamik sidebar'ımızı HTML şablonlarında nasıl oluşturacağımız var.

    Adım 4: Jinja2 Şablonları ile Sidebar'ı Oluşturma

    Şimdiye kadar, FastAPI uygulamamız sidebar.yaml dosyamızı okuyabiliyor ve Markdown içeriğini HTML'e çevirebiliyor. Ancak bu veriyi bir web arayüzüne taşımamız gerekiyor. İşte bu noktada Jinja2 şablonları devreye giriyor. templates/ klasörümüzde base.html ve doc_page.html olmak üzere iki ana şablon oluşturacağız. Bu şablonlar, uygulamanın genel yapısını ve sidebar'ın render edilme mantığını içerecek.

    templates/base.html (Temel Sayfa Yapısı)

    Bu şablon, HTML sayfamızın temel iskeletini, etiketini, genel CSS bağlantılarını ve ana layout elementlerini (header, footer, ana içerik alanı ve sidebar'ın yer tutucusu) tanımlar. Diğer şablonlar bu dosyayı genişleterek kendi içeriklerini yerleştireceklerdir.

    
    
    
    
        
        
        {{ title }} | Proje Dokümantasyon
        
        
        
        
    
    
        
    
        
    {% block content %}{% endblock %}

    © 2023 Proje Dokümantasyon. Tüm Hakları Saklıdır.

    Yukarıdaki base.html şablonunda dikkat etmemiz gerekenler:

    • {{ title }}: FastAPI'den gelen sayfa başlığı buraya yerleştirilir.
    • url_for('static', path='/css/style.css'): FastAPI'nin StaticFiles mount'u üzerinden CSS dosyasına dinamik olarak yol oluşturur.
    • , : SEO için önemli meta etiketleridir.

    • : Sidebar menümüzü barındıran ana eleman.
    • {% for item in sidebar_config %}: FastAPI'den gelen sidebar_config listesi üzerinde döngü yaparız. Bu, her bir kategori, doküman veya harici bağlantı için HTML oluşturmamızı sağlar.
    • {% if item.type == 'category' %}: Eğer öğe bir kategoriyse, genişletilebilir bir yapı oluştururuz. İç içe döngü ile kategori içindeki alt öğeleri (dokümanlar veya bağlantılar) işleriz. collapsed ve collapsible bayrakları dinamik olarak CSS sınıflarını kontrol eder.
    • {% if current_doc_id == sub_item.id %}: Aktif olarak görüntülenen doküman sayfasını sidebar'da işaretlemek için kullanılır, böylece kullanıcı nerede olduğunu bilir.
    • url_for('read_doc', doc_id=sub_item.id): FastAPI rotamıza (read_doc) dinamik URL oluşturur.
    • {% block content %}{% endblock %}: Burası, base.html'i genişleten diğer şablonların kendi içeriklerini yerleştireceği ana alandır.

    templates/doc_page.html (Doküman Sayfası Şablonu)

    Bu şablon, base.html'i genişleterek ana doküman içeriğini (doc_content) content bloğuna yerleştirir.

    
    {% extends "base.html" %}
    
    {% block content %}
        
    {{ doc_content | safe }}
    {% endblock %}

    Burada {{ doc_content | safe }} ifadesi önemlidir. Jinja2 varsayılan olarak HTML içeriğini kaçış karakterlerine dönüştürür (güvenlik için). Ancak Markdown'dan çevrilen içeriğimiz zaten güvenli bir HTML olduğu için, | safe filtresini kullanarak Jinja2'ye bu içeriği olduğu gibi render etmesini söyleriz.

    templates/404.html (Sayfa Bulunamadı Şablonu)

    Olmayan bir doküman sayfasına erişildiğinde gösterilecek basit bir hata sayfası:

    
    {% extends "base.html" %}
    
    {% block content %}
        

    404 - Sayfa Bulunamadı

    Aradığınız doküman sayfası bulunamadı. Lütfen URL'yi kontrol edin veya sidebar'dan başka bir sayfa seçin.

    Ana Sayfaya Dön

    {% endblock %}

    static/css/style.css (Temel Stil Tanımları)

    Sidebar'ımızın ve genel layout'umuzun düzgün görünmesi için biraz CSS ekleyelim. Bu CSS aynı zamanda mobil uyumluluğu da göz önünde bulunduracaktır.

    
    /* style.css */
    :root {
        --primary-color: #007bff;
        --secondary-color: #6c757d;
        --bg-color: #f8f9fa;
        --text-color: #343a40;
        --sidebar-width: 280px;
        --navbar-height: 60px;
    }
    
    body {
        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
        margin: 0;
        padding: 0;
        background-color: var(--bg-color);
        color: var(--text-color);
        line-height: 1.6;
    }
    
    .navbar {
        background-color: var(--primary-color);
        color: white;
        padding: 0.8rem 1rem;
        position: fixed;
        width: 100%;
        top: 0;
        left: 0;
        z-index: 1000;
        box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        height: var(--navbar-height);
        display: flex;
        align-items: center;
    }
    
    .navbar-brand {
        color: white;
        text-decoration: none;
        font-size: 1.5rem;
        font-weight: bold;
        margin-left: 1rem;
    }
    
    .wrapper {
        display: flex;
        min-height: calc(100vh - var(--navbar-height)); /* Topbar yüksekliğini düş */
        padding-top: var(--navbar-height); /* Topbar kadar boşluk bırak */
    }
    
    .sidebar {
        width: var(--sidebar-width);
        background-color: #ffffff;
        border-right: 1px solid #e0e0e0;
        padding: 1.5rem 0;
        box-shadow: 2px 0 5px rgba(0,0,0,0.05);
        position: fixed;
        height: calc(100% - var(--navbar-height));
        overflow-y: auto;
        top: var(--navbar-height);
        left: 0;
    }
    
    .sidebar-nav {
        list-style: none;
        padding: 0;
        margin: 0;
    }
    
    .sidebar-category {
        margin-bottom: 0.5rem;
    }
    
    .category-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 0.75rem 1.5rem;
        cursor: pointer;
        font-weight: bold;
        color: var(--primary-color);
        background-color: #e9ecef;
        border-bottom: 1px solid #dee2e6;
    }
    
    .category-header:hover {
        background-color: #e2e6ea;
    }
    
    .toggle-icon {
        width: 0;
        height: 0;
        border-left: 5px solid transparent;
        border-right: 5px solid transparent;
        border-top: 5px solid var(--primary-color);
        transition: transform 0.2s ease-in-out;
    }
    
    .sidebar-category.open .toggle-icon {
        transform: rotate(180deg);
    }
    
    .category-items {
        list-style: none;
        padding: 0;
        margin: 0;
        overflow: hidden; /* Collapse animation */
        transition: max-height 0.3s ease-out;
    }
    
    .category-items.collapsed {
        max-height: 0;
    }
    
    .category-items:not(.collapsed) {
        max-height: 500px; /* Büyük bir değer verin */
    }
    
    
    .sidebar-item a {
        display: block;
        padding: 0.75rem 1.5rem 0.75rem 2rem; /* Alt öğeleri biraz içeriden başlat */
        color: var(--text-color);
        text-decoration: none;
        transition: background-color 0.2s, color 0.2s;
        font-size: 0.95rem;
    }
    
    .sidebar-item a:hover {
        background-color: #f0f0f0;
        color: var(--primary-color);
    }
    
    .sidebar-item.active a {
        background-color: var(--primary-color);
        color: white;
        font-weight: bold;
    }
    
    .content {
        margin-left: var(--sidebar-width);
        flex-grow: 1;
        padding: 2rem;
        max-width: 900px;
    }
    
    .doc-article h1, .doc-article h2, .doc-article h3, .doc-article h4, .doc-article h5, .doc-article h6 {
        color: var(--primary-color);
        margin-top: 2rem;
        margin-bottom: 1rem;
    }
    
    .doc-article p {
        margin-bottom: 1rem;
    }
    
    .doc-article pre {
        background-color: #272727;
        color: #f8f8f2;
        padding: 1rem;
        border-radius: 5px;
        overflow-x: auto;
        font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;
        margin-bottom: 1.5rem;
    }
    
    .doc-article code {
        background-color: rgba(0,0,0,0.05);
        padding: 0.2em 0.4em;
        border-radius: 3px;
        font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;
        font-size: 0.9em;
    }
    
    .doc-article pre code {
        background-color: transparent;
        padding: 0;
        border-radius: 0;
    }
    
    .doc-article table {
        width: 100%;
        border-collapse: collapse;
        margin: 1rem 0;
    }
    
    .doc-article th, .doc-article td {
        border: 1px solid #ddd;
        padding: 8px;
        text-align: left;
    }
    
    .doc-article th {
        background-color: #f2f2f2;
        font-weight: bold;
    }
    
    .footer {
        background-color: var(--secondary-color);
        color: white;
        text-align: center;
        padding: 1rem;
        font-size: 0.9rem;
        margin-top: auto; /* Footer'ı alta sabitlemek için */
    }
    
    .error-page {
        text-align: center;
        padding: 5rem 2rem;
    }
    
    .expert-tip {
        background-color: #fff3cd; /* Sarımsı arka plan */
        border-left: 4px solid #ffc107; /* Sarı kenarlık */
        padding: 1rem 1.5rem;
        margin: 1.5rem 0;
        color: #664d03; /* Koyu sarımsı metin */
        border-radius: 4px;
        font-style: italic;
        box-shadow: 0 1px 3px rgba(0,0,0,0.1);
    }
    
    /* Mobil Uyumlu Tasarım */
    @media (max-width: 992px) {
        .sidebar {
            width: 250px;
        }
        .content {
            margin-left: 250px;
            padding: 1rem;
        }
    }
    
    @media (max-width: 768px) {
        .wrapper {
            flex-direction: column;
            padding-top: calc(var(--navbar-height) + 1rem); /* Topbar ve biraz daha boşluk */
        }
        .sidebar {
            position: static; /* Mobil'de sidebar'ı statik yap */
            width: 100%;
            height: auto;
            border-right: none;
            border-bottom: 1px solid #e0e0e0;
            box-shadow: 0 2px 5px rgba(0,0,0,0.05);
            padding: 0; /* İç dolguyu kaldır */
        }
        .content {
            margin-left: 0;
            padding: 1.5rem;
        }
        .category-items {
            max-height: 0; /* Mobil'de varsayılan olarak daraltılmış */
        }
        .sidebar-category.open .category-items {
            max-height: 500px; /* Açık olduğunda genişlet */
        }
        .category-header {
            padding: 1rem;
            font-size: 1.1rem;
        }
        .sidebar-item a {
            padding: 0.75rem 1.5rem 0.75rem 1.5rem;
        }
        .navbar-brand {
            font-size: 1.2rem;
        }
    }
    

    static/js/main.js (Sidebar Etkileşimleri)

    Kategorilerin daraltılıp genişletilmesi için basit bir JavaScript kodu ekleyelim:

    
    // main.js
    document.addEventListener('DOMContentLoaded', function() {
        const categoryHeaders = document.querySelectorAll('.category-header');
    
        categoryHeaders.forEach(header => {
            header.addEventListener('click', function() {
                const category = this.closest('.sidebar-category');
                const categoryItems = category.querySelector('.category-items');
                
                // Toggle 'open' class on the category
                category.classList.toggle('open');
                
                // Toggle 'collapsed' class on category items for CSS transition
                categoryItems.classList.toggle('collapsed');
            });
        });
    
        // Sayfa yüklendiğinde mevcut aktif kategoriyi aç
        const activeItem = document.querySelector('.sidebar-item.active');
        if (activeItem) {
            let parentCategoryItems = activeItem.closest('.category-items');
            while (parentCategoryItems) {
                parentCategoryItems.classList.remove('collapsed');
                let parentCategory = parentCategoryItems.closest('.sidebar-category');
                if (parentCategory) {
                    parentCategory.classList.add('open');
                }
                parentCategoryItems = parentCategoryItems.parentElement.closest('.category-items');
            }
        }
    });
    

    Bu JS kodu, kategori başlıklarına tıklanıldığında ilgili category-items listesini genişletir veya daraltır. Ayrıca, sayfa yüklendiğinde aktif olan doküman öğesinin üst kategorilerini otomatik olarak açar, böylece kullanıcı nerede olduğunu kolayca görebilir. Bu basit JavaScript, Docusaurus benzeri kullanıcı deneyimini sağlamak için yeterli olacaktır.

    Bu şablonlar ve stil dosyalarıyla, FastAPI uygulamamız artık dinamik olarak oluşturulan bir sidebar'a sahip, okunabilir ve modern görünümlü bir dokümantasyon sitesi sunabilir. Bir sonraki ve son adımda, bu parçaları bir araya getirip FastAPI uygulamasını nasıl başlatacağımıza ve çalıştıracağımıza bakacağız.

    Adım 5: FastAPI Uygulamasını Entegre Etme ve Çalıştırma

    Şimdiye kadar tüm gerekli bileşenleri hazırladık: Proje yapısını kurduk, sidebar.yaml ile navigasyonu tanımladık, Markdown dokümanlarımızı oluşturduk ve Jinja2 şablonlarımızla HTML çıktısı için zemini hazırladık. Artık main.py dosyamızda tüm bu parçaları bir araya getirerek FastAPI uygulamamızı çalışır hale getirebiliriz.

    Aşağıda, main.py dosyasının son hali bulunmaktadır. Önceki adımlarda oluşturduğumuz fonksiyonları ve rotaları içerir.

    
    # main.py
    
    import yaml
    from pathlib import Path
    from markdown import markdown
    from fastapi import FastAPI, Request
    from fastapi.responses import HTMLResponse
    from fastapi.staticfiles import StaticFiles
    from fastapi.templating import Jinja2Templates
    
    # Projenin kök dizini
    BASE_DIR = Path(__file__).resolve().parent
    
    # YAML dosyasını yükleme fonksiyonu
    def load_sidebar_config(config_path: Path):
        try:
            with open(config_path, 'r', encoding='utf-8') as file:
                return yaml.safe_load(file)
        except FileNotFoundError:
            print(f"Hata: Yapılandırma dosyası bulunamadı: {config_path}")
            return []
        except yaml.YAMLError as e:
            print(f"Hata: YAML ayrıştırma hatası: {e}")
            return []
        except Exception as e:
            print(f"Hata: load_sidebar_config sırasında beklenmeyen hata: {e}")
            return []
    
    # Markdown'ı HTML'e çevirme fonksiyonu
    def convert_markdown_to_html(md_path: Path) -> str:
        try:
            with open(md_path, 'r', encoding='utf-8') as file:
                md_content = file.read()
            # Kod blokları, tablolar ve özellik listeleri için uzantıları ekle
            return markdown(md_content, extensions=['fenced_code', 'tables', 'attr_list', 'nl2br'])
        except FileNotFoundError:
            return "Doküman bulunamadı."
        except Exception as e:
            return f"Markdown dönüştürme hatası: {e}"
    
    # FastAPI uygulamasını başlat
    app = FastAPI(
        title="Proje Dokümantasyon Sitesi",
        description="FastAPI ile dinamik olarak oluşturulmuş dokümantasyon sayfası.",
        version="1.0.0",
    )
    
    # Statik dosyaları bağla (CSS, JS vb.)
    # Bu, tarayıcının /static/css/style.css gibi yollardan dosyalara erişmesini sağlar
    app.mount("/static", StaticFiles(directory=BASE_DIR / "static"), name="static")
    
    # Jinja2 şablonlarını yükle
    templates = Jinja2Templates(directory=BASE_DIR / "templates")
    
    # Sidebar yapılandırmasını uygulama başladığında bir kez yükle
    sidebar_config = load_sidebar_config(BASE_DIR / "sidebar.yaml")
    
    # --- Rotlar ---
    
    @app.get("/docs/{doc_id:path}", response_class=HTMLResponse)
    async def read_doc(request: Request, doc_id: str):
        """
        Dinamik olarak doküman sayfalarını yükler ve render eder.
        doc_id: URL'deki doküman yolu (örn. getting-started/introduction)
        """
        doc_path = BASE_DIR / "docs" / f"{doc_id}.md"
    
        if not doc_path.is_file():
            # Eğer dosya yoksa 404 hatası döndür
            return templates.TemplateResponse(
                "404.html",
                {"request": request, "sidebar_config": sidebar_config, "title": "Sayfa Bulunamadı"},
                status_code=404
            )
    
        # Markdown içeriğini HTML'e çevir
        doc_content_html = convert_markdown_to_html(doc_path)
    
        # Sayfa başlığını Markdown dosyasının ilk H1 başlığından veya doc_id'den al
        # Burada daha sağlam bir başlık çıkarma mekanizması kullanılabilir.
        # Örneğin, Markdown metnini parse edip ilk H1'i bulmak gibi.
        # Basitlik adına, şimdilik doc_id'den türetilmiş bir başlık veya doğrudan Markdown içeriğinden ilk H1.
        page_title_candidate = doc_id.replace('-', ' ').replace('/', ' ').title()
        
        # Markdown içeriğinden ilk H1'i çekmek için daha dikkatli bir yaklaşım
        # Markdown çıktısı HTML olduğu için, HTML içindeki 

    etiketini arayalım. import re h1_match = re.search(r'

    (.*?)', doc_content_html, re.IGNORECASE) if h1_match: page_title = h1_match.group(1).strip() else: page_title = page_title_candidate # Jinja2 şablonunu render et return templates.TemplateResponse( "doc_page.html", { "request": request, "sidebar_config": sidebar_config, "doc_content": doc_content_html, "current_doc_id": doc_id, # Aktif sayfayı işaretlemek için "title": page_title } ) @app.get("/", response_class=HTMLResponse) async def read_root(request: Request): """ Ana sayfa yönlendirmesi veya varsayılan bir başlangıç sayfası. """ # Ana sayfayı direkt ilk dokümana yönlendirelim veya özel bir ana sayfa gösterebiliriz. if sidebar_config and isinstance(sidebar_config, list) and sidebar_config: first_doc_item = None # Sidebar'daki ilk 'doc' tipindeki öğeyi bul for item in sidebar_config: if item.get('type') == 'doc': first_doc_item = item break elif item.get('type') == 'category' and item.get('items'): for sub_item in item['items']: if sub_item.get('type') == 'doc': first_doc_item = sub_item break if first_doc_item: break if first_doc_item: first_doc_id = first_doc_item['id'] # İlk dokümanın içeriğini yükleyip ana sayfa olarak göster return templates.TemplateResponse( "doc_page.html", { "request": request, "sidebar_config": sidebar_config, "doc_content": convert_markdown_to_html(BASE_DIR / "docs" / f"{first_doc_id}.md"), "current_doc_id": first_doc_id, "title": first_doc_item.get('label', first_doc_id.replace('-', ' ').replace('/', ' ').title()) } ) # Eğer sidebar boşsa veya ilk doküman bulunamazsa, genel bir karşılama sayfası göster return templates.TemplateResponse( "home.html", # Bu şablonu oluşturmanız gerekebilir veya doc_page.html kullanabilirsiniz { "request": request, "sidebar_config": sidebar_config, "title": "Hoş Geldiniz", "doc_content": "

    Hoş Geldiniz!

    Soldaki menüden bir doküman seçerek başlayın.

    " } )

    Uygulamayı Çalıştırma

    Projenizi oluşturdunuz, kütüphanelerinizi kurdunuz ve tüm kodları yerleştirdiniz. Şimdi uygulamayı çalıştırmanın zamanı geldi. Terminalinizi açın, projenizin ana dizinine (fastapi-docs-site/) gidin ve aşağıdaki komutu çalıştırın:

    
    uvicorn main:app --reload
    

    Bu komut:

    • uvicorn: FastAPI uygulamalarını çalıştırmak için kullanılan ASGI sunucusudur.
    • main:app: main.py dosyasındaki app isimli FastAPI uygulamasını ifade eder.
    • --reload: Bu bayrak, kodunuzda her değişiklik yaptığınızda uygulamanın otomatik olarak yeniden yüklenmesini sağlar. Geliştirme sürecinde çok faydalıdır.

    Uygulama başarıyla başlatıldığında, terminalinizde şuna benzer bir çıktı göreceksiniz:

    
    INFO:     Will watch for changes in these directories: ['/path/to/your/fastapi-docs-site']
    INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
    INFO:     Started reloader process [xxxxx]
    INFO:     Started server process [xxxxx]
    INFO:     Waiting for application startup.
    INFO:     Application startup complete.
    

    Artık tarayıcınızı açıp http://127.0.0.1:8000 adresine giderek dinamik dokümantasyon sitenizi görebilirsiniz. Sidebar'ınızın sidebar.yaml dosyasında tanımladığınız gibi göründüğünü, linklere tıkladığınızda Markdown dosyalarınızın HTML'e çevrilerek yüklendiğini ve aktif sayfanın sidebar'da vurgulandığını fark edeceksiniz. Mobil cihazlarda sidebar'ın nasıl davranacağını görmek için tarayıcınızın geliştirici araçlarını kullanarak ekran boyutunu küçültebilirsiniz. CSS'deki @media sorguları sayesinde, daha küçük ekranlarda sidebar'ın farklı bir düzende (örneğin, üstte genişletilebilir menü olarak) göründüğünü göreceksiniz. Bu, kullanıcı deneyimini her boyuttaki ekran için optimize etmenize yardımcı olur.

    İleri Seviye Optimizasyonlar ve Geliştirmeler

    Artık temel dinamik sidebar yapımızı kurduğumuza göre, projemizi daha sağlam, performanslı ve kullanıcı dostu hale getirecek ileri seviye konulara değinelim. Bu optimizasyonlar, büyük ölçekli dokümantasyon siteleri veya özel gereksinimleri olan projeler için kritik öneme sahiptir.

    1. Dinamik İçerik Güncellemeleri için Dosya Takibi

    Mevcut kurulumumuzda, sidebar.yaml dosyasını veya Markdown içeriğini değiştirdiğinizde, değişikliklerin web sitesinde görünmesi için FastAPI uygulamasını yeniden başlatmanız gerekir (eğer uvicorn --reload kullanmıyorsanız). Üretim ortamında bu pratik değildir. watchdog gibi bir kütüphane kullanarak docs/ klasöründeki veya sidebar.yaml dosyasındaki değişiklikleri dinleyebilir ve bir değişiklik algılandığında sidebar_config'i otomatik olarak yeniden yükleyebiliriz. Bu, uygulamanın çalışmaya devam ederken içeriğin canlı olarak güncellenmesini sağlar.

    
    # Örnek: main.py içinde bir background task veya event listener olarak
    import asyncio
    from watchdog.observers import Observer
    from watchdog.events import FileSystemEventHandler
    
    class ConfigChangeHandler(FileSystemEventHandler):
        def __init__(self, app_instance, config_path):
            super().__init__()
            self.app = app_instance
            self.config_path = config_path
    
        def on_modified(self, event):
            if event.src_path == str(self.config_path):
                print(f"[{event.src_path}] güncellendi, sidebar yapılandırması yeniden yükleniyor...")
                # Bu işlem senkron olduğu için dikkatli olun, büyük dosyalarda bloklama yapabilir.
                # Alternatif olarak, güncellemeyi bir Queue'ye atıp başka bir process'te işleyebilirsiniz.
                self.app.state.sidebar_config = load_sidebar_config(self.config_path) # FastAPI uygulaması içindeki state'i güncelleyin
    
    # Uygulama başlangıcında observer'ı başlatma (FastAPI lifecycle events ile)
    # @app.on_event("startup")
    # async def startup_event():
    #     event_handler = ConfigChangeHandler(app, BASE_DIR / "sidebar.yaml")
    #     observer = Observer()
    #     observer.schedule(event_handler, path=str(BASE_DIR), recursive=True)
    #     observer.start()
    #     app.state.observer = observer # Kapanışta durdurmak için sakla
    
    # @app.on_event("shutdown")
    # def shutdown_event():
    #     if hasattr(app.state, 'observer'):
    #         app.state.observer.stop()
    #         app.state.observer.join()
    

    Bu yaklaşım, içerik yönetimini daha dinamik hale getirir ve geliştirici deneyimini önemli ölçüde iyileştirir.

    2. Caching (Önbellekleme) Mekanizmaları

    Her istekte Markdown dosyasını okumak ve HTML'e çevirmek, özellikle yüksek trafikli sitelerde performans sorunlarına yol açabilir. Bu sorunu çözmek için önbellekleme kullanabiliriz:

    • Lru Cache: Python'ın functools.lru_cache dekoratörü, fonksiyon çağrılarının sonuçlarını önbelleğe almak için basit ama etkili bir yoldur. Markdown'dan HTML'e çeviren fonksiyona uygulayabiliriz.
    • Redis/Memcached: Daha büyük ölçekli veya dağıtık sistemler için, Redis veya Memcached gibi harici önbellekleme sistemleri kullanılabilir. FastAPI içinde bir Cache bağımlılığı oluşturarak, sayfa içeriklerini veya hatta tüm render edilmiş HTML parçalarını önbelleğe alabilirsiniz.
    
    # functools.lru_cache kullanımı
    from functools import lru_cache
    
    @lru_cache(maxsize=128) # Son 128 farklı dosyanın sonucunu önbelleğe al
    def convert_markdown_to_html(md_path: Path) -> str:
        # ... mevcut kod ...
    

    Bu basit ekleme, Markdown dönüştürme performansını belirgin şekilde artıracaktır.

    3. Arama Fonksiyonu Entegrasyonu

    Dokümantasyon sitelerinin vazgeçilmezi olan arama işlevi, kullanıcıların bilgiye hızlıca ulaşmasını sağlar. FastAPI üzerinde bir arama motoru entegre edebilirsiniz:

    • Basit Metin Araması: Tüm Markdown dosyalarını tarayarak ve arama terimini içeren dosyaları listeleyerek basit bir arama yapabilirsiniz. Bu, küçük dokümantasyon siteleri için yeterli olabilir.
    • Tam Metin Arama Motorları: Elasticsearch, Algolia veya Whoosh (Python tabanlı) gibi daha gelişmiş tam metin arama motorlarını entegre etmek, daha hızlı, daha alakalı ve esnek arama sonuçları sunar. İçerik güncellendiğinde arama indeksini de güncellemek önemlidir.
    
    # Arama endpoint'i örneği
    # @app.get("/search", response_class=HTMLResponse)
    # async def search_docs(request: Request, query: str):
    #     results = []
    #     # Gerçek dünyada burada bir arama motoru (Elasticsearch, Whoosh vb.) entegrasyonu olur.
    #     # Basit bir örnek olarak, sadece dosya isimlerinde arama yapalım.
    #     for item in sidebar_config:
    #         if item.get('type') == 'doc' and query.lower() in item['label'].lower():
    #             results.append(item)
    #         elif item.get('type') == 'category':
    #             for sub_item in item.get('items', []):
    #                 if sub_item.get('type') == 'doc' and query.lower() in sub_item['label'].lower():
    #                     results.append(sub_item)
    #     
    #     return templates.TemplateResponse(
    #         "search_results.html", # Arama sonuçları için ayrı bir şablon
    #         {"request": request, "sidebar_config": sidebar_config, "title": f"Arama Sonuçları: {query}", "query": query, "results": results}
    #     )
    

    4. Çok Dilli Destek

    Uluslararası projeler için dokümantasyonun birden çok dilde sunulması gerekebilir. Bunu uygulamak için:

    • Her dil için ayrı docs/ klasörleri (örn. docs/en/, docs/tr/) ve ayrı sidebar.yaml dosyaları tutulabilir.
    • Kullanıcının dil tercihini (tarayıcı ayarlarından veya URL parametresinden) algılayarak dinamik olarak doğru dil setini yükleyebilirsiniz.

    Bu, kullanıcıların kendi ana dillerinde dokümantasyona erişmesini sağlayarak genel kullanıcı deneyimini artırır.

    5. Özelleştirilebilir Temalar

    Docusaurus gibi sistemlerde tema desteği yaygındır. Bizim kurulumumuzda, templates/ ve static/ klasörlerini farklı temaları destekleyecek şekilde genişletebiliriz. Kullanıcılar URL parametresi veya bir ayarla tema seçimi yapabilir ve FastAPI bu seçime göre farklı şablon ve CSS dosyalarını yükleyebilir. Bu, projenizin görsel kimliğini esnek bir şekilde yönetmenizi sağlar.

    Bu ileri düzey optimizasyonlar, FastAPI ile kurduğunuz dokümantasyon sitesinin sadece işlevsel değil, aynı zamanda performanslı, ölçeklenebilir ve çeşitli kullanıcı ihtiyaçlarına yanıt verebilir olmasını sağlayacaktır. Her bir adım, projenizin olgunluk seviyesini artırırken, geliştirici ve kullanıcı deneyimini de iyileştirmeye odaklanmıştır.

    Sonuç ve Sıkça Sorulan Sorular

    Bu makalede, FastAPI ve Jinja2'nin gücünü kullanarak, Docusaurus benzeri dinamik ve esnek bir dokümantasyon sitesi sidebar'ı nasıl oluşturulacağını adım adım öğrendik. sidebar.yaml gibi yapılandırma dosyaları aracılığıyla menü öğelerini tanımlamanın, Markdown içeriğini HTML'e çevirmenin ve tüm bu bileşenleri FastAPI uygulamasında bir araya getirmenin inceliklerini keşfettik. Ortaya çıkan çözüm, statik site üreticilerinin sunduğu kolaylığı dinamik bir web uygulamasının esnekliğiyle birleştirerek, projenizin dokümantasyonunu yönetmek için güçlü bir temel sunmaktadır. Bu yaklaşım, sadece içerik oluşturmaya odaklanmanızı sağlamakla kalmaz, aynı zamanda bakım kolaylığı, tutarlılık ve ölçeklenebilirlik gibi önemli avantajları da beraberinde getirir.

    Uygulamamız artık Markdown dokümanlarını otomatik olarak HTML'e dönüştürebiliyor, yapılandırılabilir bir menü ile gezinme sağlıyor ve basit CSS/JS entegrasyonuyla modern bir görünüm sunuyor. Ayrıca, mobil uyumlu tasarım ipuçları ve ileri seviye optimizasyon önerileriyle (önbellekleme, dosya takibi, arama entegrasyonu), projenizi daha da geliştirebileceğiniz yolları gösterdik. FastAPI'nin sunduğu performans ve Jinja2'nin şablonlama yetenekleriyle birleşen bu mimari, kendi özel dokümantasyon çözümünüzü inşa etmek isteyen herkese ilham verecektir.

    Sıkça Sorulan Sorular (SSS)

    1. S: Neden Docusaurus gibi hazır bir aracı kullanmak yerine kendi çözümümüzü FastAPI ile inşa etmeliyiz?
      C: Docusaurus harika bir araç olsa da, FastAPI ile kendi çözümünüzü inşa etmek size daha fazla esneklik ve kontrol sağlar. Özellikle dokümantasyonunuz bir FastAPI web uygulamasıyla sıkı entegrasyon gerektiriyorsa, API'lerden dinamik içerik çekmeniz gerekiyorsa, özel kimlik doğrulama veya yetkilendirme mekanizmaları uygulayacaksanız, veya sadece Python ekosistemi içinde kalmayı tercih ediyorsanız, bu yaklaşım daha uygun olabilir.
    2. S: Sidebar'da çok sayıda doküman olursa performans sorunları yaşar mıyım?
      C: Mevcut haliyle, sidebar.yaml dosyasının büyük olması veya çok sayıda Markdown dosyasının her istekte okunup işlenmesi potansiyel bir performans darboğazı yaratabilir. Bu nedenle, makalede bahsedilen lru_cache gibi önbellekleme tekniklerini veya daha büyük projeler için Redis gibi harici bir önbellekleme çözümünü kullanmanız şiddetle tavsiye edilir.
    3. S: Markdown dosyalarına ek olarak başka formatlarda (örn. reStructuredText, AsciiDoc) doküman ekleyebilir miyim?
      C: Evet, convert_markdown_to_html fonksiyonu gibi kendi özel dönüştürücü fonksiyonlarınızı yazarak ve FastAPI rotanızda bu fonksiyonları çağırarak farklı doküman formatlarını destekleyebilirsiniz. Örneğin, python-docutils kütüphanesini kullanarak reStructuredText dosyalarını HTML'e çevirebilirsiniz. sidebar.yaml'deki type alanını genişleterek farklı formatları belirtebilirsiniz.
    4. S: Sidebar'a dinamik olarak kategori veya doküman eklemenin bir yolu var mı?
      C: Evet. Mevcut kurulum, sidebar.yaml dosyasını değiştirmenizi gerektirir. Ancak, ileri seviye bir yaklaşım olarak, bir yönetim paneli veya API endpoint'i aracılığıyla veritabanında saklanan kategori/doküman bilgilerini güncelleyebilir ve FastAPI uygulamanızın bu veritabanından sidebar'ı oluşturmasını sağlayabilirsiniz. Ayrıca, watchdog ile dosya değişikliklerini izleyerek otomatik güncelleme de mümkündür.
    5. S: Doküman sayfalarında resimler veya diğer statik varlıklar nasıl kullanılır?
      C: Resimlerinizi ve diğer statik varlıklarınızı static/ klasörünün uygun alt dizinlerine (örn. static/images/) yerleştirebilirsiniz. Markdown dosyalarınızda bu varlıklara referans verirken, FastAPI'nin statik dosya sunumu için ayarladığı /static/ URL ön ekini kullanmalısınız. Örneğin: ![Resim Açıklaması](/static/images/my-image.png). Bu, tarayıcının doğru dosyayı bulmasını sağlar.
    Yorumlar
    İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
    Yorum Yaz

    Bir yanıt yazın

    E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

    Gönder

    E-posta Bülteni
    Yazılım Topluluğuna Katılın
    En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.
    Exit mobile version