Etzel Art of Digital Manufacturing
Bize ulaşın
Lunex 1.6.0 kullanım kılavuzu

Uygulamalı örnek: sipariş API'si

Tam sözleşme ve route ile doğru istek, şema hatası ve iş hatasını deneyin.

Hazır sipariş önizleme projesini indirin veya aşağıdaki adımlarla kendiniz oluşturun. İçe alma rehberi dosyaları ve ilk çalıştırmayı açıklar. ZIP help-order-preview kimliğini kullanır; aşağıdaki elle oluşturma anlatımında help-orders-api kullanılır. Sözleşme ve route aynıdır.

Bu örnekte POST /orders/preview işlemi hazırlayacaksınız. İstek müşteri kodu ve miktar taşır; route gösterim amaçlı birim fiyatla toplamı hesaplar. Doğru istek 200, şemaya uymayan istek 400, örnekteki iş sınırını aşan istek 422 verir. Böylece sözleşme, doğrulama ve iş mantığının farklı sorumluluklarını aynı API üzerinde görebilirsiniz.

Örnek bir sipariş önizlemesidir: veritabanına kayıt oluşturmaz, ödeme almaz, SAP’ye veya kuyruğa bağlanmaz. Birim fiyat sabit olarak 25 TRY kullanılır. Gerçek sipariş oluşturma akışında kalıcılık, fiyat kaynağı ve tekrar gönderim davranışı ayrıca tasarlanmalıdır.

1. Projeyi hazırlayın

  1. Geliştirme ortamında Projects → Create project seçin. Name için Orders Help API, Project ID için help-orders-api girin.
  2. Architecture → OpenAPI üzerinden sözleşmeyi oluşturun.
  3. Aşağıdaki sözleşmeyi API editörünün Source görünümüne yerleştirin ve Save seçin.
  4. API access içinde API exposure → Disabled seçin ve Save yapın. İlk denemeler için dış erişim veya credential hazırlığı gerekmez; geliştirici yetkisiyle Running project kullanacaksınız.
{
  "openapi": "3.1.0",
  "info": {"title": "Orders Help API", "version": "1.0.0"},
  "servers": [{"url": "/api"}],
  "paths": {
    "/orders/preview": {
      "post": {
        "operationId": "previewOrder",
        "summary": "Calculate an order preview",
        "description": "Demonstration only. No order is stored.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {"$ref": "#/components/schemas/OrderRequest"},
              "example": {"customerId": "C-100", "quantity": 2}
            }
          }
        },
        "responses": {
          "200": {
            "description": "Order preview calculated",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/OrderPreview"},
                "example": {"customerId": "C-100", "quantity": 2, "unitPrice": 25, "total": 50, "currency": "TRY"}
              }
            }
          },
          "400": {
            "description": "Request does not satisfy the contract",
            "content": {
              "application/problem+json": {
                "schema": {"$ref": "#/components/schemas/ContractProblem"}
              }
            }
          },
          "422": {
            "description": "Demonstration order limit exceeded",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/BusinessError"},
                "example": {"code": "ORDER_LIMIT", "message": "Preview supports at most 20 units."}
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "OrderRequest": {
        "type": "object",
        "required": ["customerId", "quantity"],
        "additionalProperties": false,
        "properties": {
          "customerId": {"type": "string", "minLength": 1, "example": "C-100"},
          "quantity": {"type": "integer", "minimum": 1, "maximum": 100, "example": 2},
          "note": {"type": "string", "maxLength": 200}
        }
      },
      "OrderPreview": {
        "type": "object",
        "required": ["customerId", "quantity", "unitPrice", "total", "currency"],
        "properties": {
          "customerId": {"type": "string"},
          "quantity": {"type": "integer"},
          "unitPrice": {"type": "number"},
          "total": {"type": "number"},
          "currency": {"type": "string", "enum": ["TRY"]}
        }
      },
      "ContractProblem": {
        "type": "object",
        "properties": {
          "type": {"type": "string"},
          "title": {"type": "string"},
          "status": {"type": "integer"},
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "location": {"type": "string"},
                "rule": {"type": "string"},
                "message": {"type": "string"}
              }
            }
          }
        }
      },
      "BusinessError": {
        "type": "object",
        "required": ["code", "message"],
        "properties": {"code": {"type": "string"}, "message": {"type": "string"}}
      }
    }
  }
}

Form görünümünde Paths → /orders/preview → previewOrder seçin. Request body sekmesindeki model OrderRequest, başarılı response modeli OrderPreview olmalıdır. Components → Schemas içinden ortak tanımları inceleyebilirsiniz.

2. Route ve bağımlılıkları hazırlayın

Source → Files → application.properties dosyasını açın. camel.jbang.dependencies listesindeki mevcut değerleri koruyarak camel-jackson ve camel-groovy ekleyin. Başlangıç listesi yalnızca camel-console ise satır şöyle olur:

camel.jbang.dependencies=camel-console,camel-jackson,camel-groovy

Bu kütüphaneler JSON’u nesneye çevirmek, hesabı yapmak ve sonucu JSON olarak yazmak içindir. Runtime daha önce başladıysa yeni bağımlılıklar için durdurup yeniden Run yapın.

Source → Files → Create file ile orders.camel.yaml oluşturun. Code görünümüne aşağıdaki içeriği yerleştirin ve Saved durumunu bekleyin:

- route:
    id: order-preview
    from:
      uri: direct:previewOrder
      steps:
        - unmarshal:
            json:
              library: Jackson
        - setHeader:
            name: Content-Type
            constant: application/json
        - choice:
            when:
              - simple: "${body[quantity]} > 20"
                steps:
                  - setHeader:
                      name: CamelHttpResponseCode
                      constant: 422
                  - setBody:
                      constant: '{"code":"ORDER_LIMIT","message":"Preview supports at most 20 units."}'
            otherwise:
              steps:
                - setBody:
                    groovy:
                      expression: |
                        [customerId: body.customerId,
                         quantity: body.quantity,
                         unitPrice: 25,
                         total: body.quantity * 25,
                         currency: 'TRY']
                - marshal:
                    json:
                      library: Jackson
                - setHeader:
                    name: CamelHttpResponseCode
                    constant: 200

Designer görünümünde Direct, Unmarshal, Set Header ve Choice adımlarını görebilirsiniz. OrderRequest miktarı 1–100 arasında kabul eder. Route’taki 20 sınırı ise bu örneğin ayrıca uyguladığı iş kuralıdır. Gerçek projede böyle bir kural müşteri limiti veya stok bilgisinden gelebilir.

JSON doğrulaması route’a bir iş nesnesi hazırlamaz; gövde metni korunur. Bu nedenle hesaplamadan önce Unmarshal kullanıyoruz. Sonuç nesnesini JSON’a çeviren Marshal, metin birleştirmeden alan değerlerini doğru biçimde yazmamızı sağlar.

3. Önce Mock, sonra gerçek çağrı yapın

  1. API design → previewOrder → Try it açın.
  2. Target → Mock, Request content type → application/json seçin. Gövdeye {"customerId":"C-100","quantity":2} girip Send kullanın. Sözleşmedeki örnek toplam 50 görünür.
  3. Proje başlığından Run seçin. Runtime’ın çalışmasını bekleyin; Target → Running project seçip gerekirse Refresh runtime status kullanın.
  4. Response content type (Accept) için No preference seçin; böylece yanıtı tek bir biçimle sınırlamayın.
  5. Aynı gövdeyi gönderin. HTTP 200 ve aşağıdaki alanları bekleyin:
{"customerId":"C-100","quantity":2,"unitPrice":25,"total":50,"currency":"TRY"}

Şimdi miktarı 3 yapın. Gerçek çağrı total: 75 üretmelidir. Mock’taki açık response örneği ise miktarı değiştirmenizle hesaplanmaz; 50 kalabilir. Bu fark, gerçek iş mantığının çalıştığını anlamanın bir yoludur.

Try it içinde Running project hedefiyle gönderilen miktar 2 için HTTP 200 ve toplam 50 TRY yanıtı

Bu görünüm gerçek geliştirme route’unun sonucudur. Full screen düğmesiyle editörü büyütebilirsiniz. Hedef, HTTP kodu, içerik türü ve yanıt gövdesini birlikte kontrol edin.

4. Şema ve iş hatasını karşılaştırın

Running project hedefinde aşağıdaki girdileri sırayla gönderin:

GirdiBeklenen sonuçAçıklama
{"customerId":"C-100","quantity":2}200, toplam 50Sözleşme ve iş kuralı geçer.
{"customerId":"C-100","quantity":3}200, toplam 75Route gönderdiğiniz miktarla hesap yapar.
{"customerId":"C-100","quantity":0}400, minimum kuralıİstek sözleşmede reddedilir; iş mantığına geçmez.
{"customerId":"C-100"}400, required kuralıMiktar zorunludur.
{"customerId":"C-100","quantity":"2"}400, type kuralıJSON string ile sayı farklıdır.
{"customerId":"C-100","quantity":2,"debug":true}400, ek alan kuralıRequest modelinde additionalProperties: false vardır.
{"customerId":"C-100","quantity":21}422, ORDER_LIMITSözleşme geçer; route’taki iş kuralı reddeder.

400 yanıtında Request contract checks alanını inceleyin. Hata konumu ve kuralını okuyun; Open schema setting sunuluyorsa ilgili tanıma gitmek için kullanın. 422 örneğinde ise gövdedeki ORDER_LIMIT kodu route’un iş yanıtıdır. Her 4xx sonucunun şema hatası olduğunu varsaymayın.

Gerçek API isteğinde quantity 0 için HTTP 400 application/problem+json ve body /quantity minimum kuralı hatası

Görselde hata quantity alanına ve minimum kuralına bağlanır. Bu sonuç, request modelinin gerçek HTTP isteğinde uygulandığını gösterir. Zorunlu bir alan tamamen eksik olduğunda konum body / gibi üst nesneyi gösterebilir; bu durumda modelin Required alanlarını inceleyin.

5. Bir şema değişikliğinin etkisini görün

  1. Components → Schemas → OrderRequest içinde quantity alanının Minimum değerini 2 yapın ve Tab ile alandan çıkın.
  2. Save seçin. Bu işlem proje dosyasını değiştirir; çalışan API önceki kuralı kullanmaya devam eder. Reload öncesinde quantity: 1 hâlâ başarılı olabilir.
  3. Proje başlığından Reload yapın ve tamamlanmasını bekleyin.
  4. quantity: 1 gönderin: yeni kurala göre 400 beklenir. quantity: 2 tekrar başarılı olmalıdır.
  5. Örneğin sonraki adımlarıyla aynı durumda kalmak için Minimum değerini 1 yapıp Save → Reload uygulayın.

OrderRequest başka operation’larda da kullanılsaydı bu değişiklik onların isteklerini de etkilerdi. Ortak modelin kullanım yerlerini değişiklikten önce inceleyin.

6. Dış istemci erişimini hazırlayın

Çalışan route’u doğruladıktan sonra gerekiyorsa API erişimi ve güvenlik adımlarını izleyin. Ortam yöneticisinin hazırladığı transport ve credential/policy ile API access ayarını tamamlayın. Save → Reload sonrasında Publication durumunu ve kopyalanan operation adresini kontrol edin.

API key seçtiğiniz ve ilgili Secret hazır olduğu durumda örnek çağrı şöyledir. API_KEY değişkenini kendi güvenli ortamınızda hazırlayın; adresi Copy operation address değeriyle değiştirin:

curl --include \
  --request POST \
  --header "x-api-key: $API_KEY" \
  --header 'Content-Type: application/json' \
  --header 'Accept: */*' \
  --data '{"customerId":"C-100","quantity":2}' \
  https://lunex.example.com/help-orders-api/api/orders/preview

Geçerli anahtarla 200, eksik veya yanlış anahtarla erişim reddi bekleyin. Sonra geçerli anahtarla hatalı miktar göndererek şema kontrolünü ayrıca sınayın. Running project başarısı bu gateway denemelerinin yerine geçmez.

Kalıcı deployment için bütün gerekli dosyaları Commit and push → Build akışına alın. Deneme tamamlandığında Kubernetes ortamında Delete container ile örneğin geliştirme runtime’ını sonlandırabilirsiniz; kaydedilmiş proje dosyaları kalır. Dışarıya açılmış veya deployment’ı bulunan bir API’yi kapatmak için yayından kaldırma adımlarını izleyin.

Bir sonraki çalışmada üç işlemin aynı hata modelini kullanmasını deneyin. Orada buradaki küçük BusinessError modelini ortak Problem yapısına taşıyıp aynı JSON üretimini bir Direct route’ta toplayacaksınız.

Lunex’i kendi entegrasyonunuzla görün

Kılavuzda okuduklarınızı kendi sistemlerinizle deneyelim. Demo için bize yazın.