API Gateway - TheOpenCloudEngine/uEngine-cloud GitHub Wiki

REST Link μ£Όμ†Œμ˜ 톡합과 λ³΄μ•ˆμ„ μœ„ν•œ API proxy

μ•žμ„œ μ˜ˆμ œμ—μ„œ λ‹€μ–‘ν•œ λ§ˆμ΄ν¬λ‘œμ„œλΉ„μŠ€λ“€μ΄ 각자의 μ£Όμ†Œλ‘œ linkκ°€ λ§Œλ“€μ–΄μ§€κ²Œ λœλ‹€. μ΄λŠ” μ—¬λŸ¬λΆ„μ˜ ν΄λΌμ΄μ–ΈνŠΈ μ½”λ“œμ—μ„œ 직접적인 μ£Όμ†Œμ˜ κΈ°μž…μ„ μ§€μ–‘ν•˜κ³  link μ—μ„œ 주어진 μ£Όμ†Œλ₯Ό ajax 둜 νƒμƒ‰ν•˜λ„λ‘ κ΅¬ν˜„ν•˜λ―€λ‘œμ„œ ν”„λ‘ νŠΈμ—”λ“œμ™€ λ°±μ—”λ“œ κ°„μ˜ 간섭을 μ΅œμ†Œν™” ν•΄μ€€λ‹€.
이에 따라 μ–Όλ§ˆλ“ μ§€ 주어진 μ£Όμ†Œμ˜ host κ°€ λ°”λ€Œλ”λΌλ„ μ›ΉλΈŒλΌμš°μ €λŠ” μ•Œμ•„μ„œ μ—¬λŸ¬κ°œμ˜ λ°±μ—”λ“œ λ§ˆμ΄ν¬λ‘œμ„œλΉ„μŠ€λ“€μ„ μ•Œμ•„μ„œ λ°©λ¬Έν•  것이닀. ν•˜μ§€λ§Œ, μ—¬λŸ¬κ°œμ˜ λ°±μ—”λ“œλ₯Ό μ›ΉλΈŒλΌμš°μ €κ°€ μ ‘μ†ν•˜λŠ”λ°λŠ” λΉ„μš©μ΄ λ”°λΌμ˜¨λ‹€. 각 λ°±μ—”λ“œμ™€ Cross Resource Sharing을 ν•˜κΈ° μœ„ν•΄μ„œ λ°±μ—”λ“œ κ°μžμ™€ 관계λ₯Ό λ§Ίμ–΄μ•Ό ν•œλ‹€. λ¬Όλ‘ , μ™„μ „ λ³„κ°œμ˜ λ°±μ—”λ“œλ“€μ„ 톡합할 λ•ŒλŠ” ν”Όν•  수 μ—†λŠ” λΉ„μš©μ΄μ§€λ§Œ ν•˜λ‚˜μ˜ ν†΅ν•©λœ μ„œλΉ„μŠ€λ‚΄μ— μ„ΈλΆ€ 마이크둜 μ„œλΉ„μŠ€ λ§ˆλ‹€ λ°±μ—”λ“œ μ£Όμ†Œλ₯Ό λ‹€λ₯΄κ²Œ κ΄€λ¦¬ν•˜κΈ°λŠ” μ–΄λ ΅λ‹€. λ˜ν•œ λ§ˆμ΄ν¬λ‘œμ„œλΉ„μŠ€λ“€μ„ μ™ΈλΆ€ μ›ΉλΈŒλΌμš°μ € μˆ˜μ€€μ—μ„œ μ§μ ‘μ μœΌλ‘œ ν˜ΈμΆœν•˜κ²Œ ν•˜λŠ” 것은 λ³΄μ•ˆμƒμœΌλ‘œ μœ„ν˜‘μ΄λ‹€. μ΄λŸ¬ν•œ 문제λ₯Ό ν•œλ²ˆμ— μ²˜λ¦¬ν•˜κΈ° μœ„ν•΄μ„œ API proxy λ₯Ό μ‚¬μš©ν•œλ‹€.

  1. API Gateway Instance 의 생성 Order μ„œλΉ„μŠ€μ™€ Customer μ„œλΉ„μŠ€λ₯Ό λ¬Άμ–΄μ„œ ν•˜λ‚˜μ˜ host μ£Όμ†Œμ—μ„œ μ‚¬μš©ν•  수 μžˆλ„λ‘ ν•΄μ£ΌλŠ” μΈ‘λ©΄μ—μ„œ API Gateway λŠ” μΌμ’…μ˜ Composite Service 라 ν•  수 μžˆλ‹€. OCE μ—μ„œλŠ” API Gateway λ˜ν•œ μΌμ’…μ˜ Spring Boot 기반 마이크둜 μ„œλΉ„μŠ€λ‘œ 바라본닀. λ”°λΌμ„œ API Gateway λ₯Ό μƒμ„±ν•˜κ³ μž ν• λ•ŒλŠ” 기쑴의 App μΆ”κ°€ν•˜λŠ” 방식과 λ™μΌν•˜κ²Œ Apps λ©”λ‰΄μ˜ App μΆ”κ°€ λ²„νŠΌμ„ ν΄λ¦­ν•˜κ³  Zuul API Gateway μœ ν˜•μ„ 선택해주면 λœλ‹€:

image

Zuul API 의 μ„€μ •μ—μ„œ λ‹€μŒ router 섀정을 ν•΄μ€€λ‹€:

  • 앱이름: e-shop-api
  • μ™ΈλΆ€ 접속 μ£Όμ†Œ(ν”„λ‘œλ•μ…˜): e-shop-api.pas-mini.io

μ„œλΉ„μŠ€κ°€ μƒμ„±λ˜κ³  μžλ™μœΌλ‘œ κΈ°λ™λ˜λŠ” λ™μ•ˆ, λŸ°νƒ€μž„ 및 ν™˜κ²½ > Zuul ν™˜κ²½ μ„€μ •μ—μ„œ λ‹€μŒμ˜ 섀정을 μž…λ ₯ν•œλ‹€:

zuul:
  ignored-headers: Access-Control-Allow-Credentials, Access-Control-Allow-Origin
  addProxyHeaders: true
  routes:
    order:
      path: /orders/**
      serviceId: order-service
      stripPrefix: false
    customer:
      path: /customers/**
      serviceId: customer-service
      stripPrefix: false

이 μ„€μ •μœΌλ‘œ Zuul server 둜 λ“€μ–΄μ˜€λŠ” orders/** μ΄ν•˜μ˜ URI λ¦¬ν€˜μŠ€νŠΈλŠ” order-service 둜, customers/** μ΄ν•˜μ˜ URI μš”μ²­μ€ customer-service 둜 ν¬μ›Œλ“œν•˜κ²Œ λœλ‹€.

섀정을 λ§ˆμΉœν›„, μ €μž₯λ²„νŠΌμ„ 클릭해주고, μƒλ‹¨μ˜ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μž¬κΈ°λ™ λ²„νŠΌ (λ¦¬ν”„λž˜μ‹œ λ²„νŠΌ)을 ν΄λ¦­ν•˜λ©΄ λ°˜μ˜λœλ‹€. [주의] μ΄λ•Œ order-service 와 customer-service λŠ” μ†ŒμŠ€μ½”λ“œλ₯Ό 컀밋해주어 미리 개발기 μ„œλ²„μƒμ— μ„œλΉ„μŠ€κ°€ μ˜¬λΌμ™€ μžˆλ„λ‘ μžˆλ„λ‘ ν•΄μ€€λ‹€.

  1. 마이크둜 μ„œλΉ„μŠ€λ“€μ˜ host μ£Όμ†Œ 톡일 이제 ν•΄λ‹Ή μ„œλΉ„μŠ€λ‘œ host μ£Όμ†Œκ°€ ν†΅μΌλ˜μ—ˆμœΌλ‹ˆ, 이λ₯Ό 기반으둜 μ£Όλ¬Έ λ¦¬ν€˜μŠ€νŠΈλ₯Ό λ³΄λ‚΄λ³΄μž:
http http://e-shop-api-dev.pas-min.io/customers firstName="jinyoung"
$ http http://e-shop-api-dev.pas-min.io/orders customer="http://e-shop-api-dev.pas-min.io/customers/1" qty=5

{
    "_links": {
        "customer": {
            "href": "http://172.31.7.160:27223/customers/1"
        }, 
        "item": {
            "href": "http://e-shop-api-dev.pas-mini.io/orders/3/item"
        }, 
        "order": {
            "href": "http://e-shop-api-dev.pas-mini.io/orders/3"
        }, 
        "self": {
            "href": "http://e-shop-api-dev.pas-mini.io/orders/3"
        }
    }, 
    "customer": {
        "firstName": null, 
        "lastName": null
    }, 
    "customerId": 1, 
    "qty": 5
}

λ‘κ°œμ˜ 객체가 λ¦΄λ¦¬μ΄μ…˜μœΌλ‘œ 잘 μ—°κ²° λ˜μ—ˆλ‹€. 그런데 μ—°κ²°λœ μ£Όμ†Œλ₯Ό 보면 λ‚΄λΆ€ μ£Όμ†Œλ‘œ μ—°κ²°λ˜μ—ˆκΈ° λ•Œλ¬Έμ— (λ§ˆμ΄ν¬λ‘œμ„œλΉ„μŠ€κ°„μ˜ ν†΅μ‹ μ—μ„œλŠ” λ¬Έμ œκ°€ λ˜μ§€ μ•ŠμœΌλ‚˜, μ™ΈλΆ€ ν΄λΌμ΄μ–ΈνŠΈ, 특히 ν”„λ‘ νŠΈμ—”λ“œμ—μ„œ 연결될 λ•ŒλŠ” 접근이 λΆˆκ°€ν•˜λ‹€) 이λ₯Ό λΌμš°ν„° μ£Όμ†ŒμΈ "ttp://e-shop-api-dev.pas-mini.io/customers/1" 둜 μ—°κ²°λ˜λ©΄ μ’‹κ² λ‹€.

이 μž‘μ—…μ€ 생각보닀 κ°„λ‹¨ν•˜λ‹€. @RestAssociation μ˜΅μ…˜ κ°’ 쀑 serviceId λ₯Ό "self"둜 μ£Όλ©΄ 호좜된 URI 에 μ—°κ²°ν•˜μ—¬ λ‹€λ₯Έ 마이크둜 μ„œλΉ„μŠ€ 일지라도 같은 host μ£Όμ†Œλ‘œ link λ₯Ό λ§Œλ“ λ‹€:

    @RestAssociation(serviceId = "self", path="/customers/{customerId}", joinColumn = "customerId")

μ΄λ ‡κ²Œ ν•΄μ„œ μ»€λ°‹ν•œ ν›„, λ³€κ²½λœ μ„œλΉ„μŠ€λ‘œ ν˜ΈμΆœν•˜λ©΄ λ‹€μŒκ³Ό 같이 λ™μΌν•œ 호슀트λͺ…을 μœ μ§€ν•œ μ±„λ‘œ link듀이 μƒμ„±λ˜κ³  μ™ΈλΆ€μ ‘μ†ν•œ ν΄λΌμ΄μ–ΈνŠΈμ—μ„œλ„ λ¦¬μ†ŒμŠ€λ“€μ„ ν•˜λ‚˜μ˜ ν˜ΈμŠ€νŠΈλ‚΄μ—μ„œ 탐색가λŠ₯ν•˜λ‹€:


{
    "_links": {
        "customer": {
            "href": "http://e-shop-api-dev.pas-mini.io/customers/1"
        }, 
        "item": {
            "href": "http://e-shop-api-dev.pas-mini.io/orders/3/item"
        }, 
        "order": {
            "href": "http://e-shop-api-dev.pas-mini.io/orders/3"
        }, 
        "self": {
            "href": "http://e-shop-api-dev.pas-mini.io/orders/3"
        }
    }, 
    "customer": {
        "firstName": null, 
        "lastName": null
    }, 
    "customerId": 1, 
    "qty": 5
}