Giới thiệu API Composition và triển khai krakend api gateway

Xin chào các anh em, dạo này admin gsviec hơi lu bu quá và không có thời gian để viết bài, nhưng hôm nay mình sẽ chia sẽ cho các bạn về một chủ đề khá là hay đó là API Composition

Cụ thể là đứng với vai trò TA tư vấn cho các startup, mình gặp một trường hợp đặc biệt khi dự án này cần dạng thiết kế microservice Pattern: API Composition

Nếu bạn nào chưa hiểu thì có thể xem thêm trên đây https://stoplight.io/api-types/composite-api/. Hoặc trên đây https://microservices.io/patterns/data/api-composition.html

Nhưng bạn có thể hiểu ngắn gọn là bạn gộp tất cả các request vào chung một request và sau đó kết quả trả về là sẽ gộp lại các request riên lẽ đó, ví dụ thông thường cho một logic api website bán hàng, thứ tự các request

1- Create customer
2- Create order for customer
3- Add item to order
4- Add another item
5- Change order status

Bạn sẽ phải tốn 5 request từ phía frontend app gửi lên backend(server api) , trong khi đó với cách tiếp cận composite API bạn sẽ cần 1 request là có thể làm được điều đó

POST /composite
{
  "composite-request": [
    {
      "method": "POST",
      "path": "/customer",
      "ref": "newcustomer",
      "body": {"name": "Tony Stark"}
    },
    {
      "method": "POST",
      "path": "/order",
      "ref": "neworder",
      "body": {"customer": "@{newcustomer.id}"}
    },
    ...

  ]
}

trong ví dụ trên tôi đã tích hợp vào method tạo customer, sau đó link customer đó tạo order,..etc

Thì kết quả API sẽ trả về chứa các endpoint mà ta đã định nghĩa ở trên.

{
  "success": true,
  "composite-response": [
    {
      "ref": "newcustomer",
      "body": {"id": 123456}
      "success": true,
      "status": 201
    },
    {
      "ref": "neworder",
      "body": {"id": 234567}
      "success": true,
      "status": 201
    },
    ...
  ]
}

Vậy làm thế nào để thiết kế API Composition, chúng ta nên xử lý phía code hay phía infra(hệ thống). Cá nhân tôi thì thích giải quyết bài toán này ở phía infra hơn là phía code, tại sao thì các bạn liên hệ mình sẽ tư vấn 🙂

Tại sao nên infra

Khi bạn làm microservice thì api gateway đóng vai trò khá là quan trọng do đó, với lại bản thân chúng tôi có kinh nghiệm trong việc dùng các tool như kong, kubernetes, haproxy, etc…

Sau khi quyết định chọn kong gateway để giải quyết bài toán đó thì gặp ngay cái issue https://github.com/Kong/kong/issues/332, là vẫn chưa hỗ trợ tính năng này 🙁

May mắn là có anh em dev trong team giới thiệu thằng này krakend sau khi lên check thì thấy có vẻ xịn xò, và đặt biệt là nó hỗ trợ native cho việt thiết kế API Composition, see https://www.krakend.io/docs/endpoints/response-manipulation/

Triển khai lên kubernetes

Vì hiện tại chúng tôi đã dùng kubernetes để quản lý các services app nên sẽ cài đặt trên kubernetes, tất nhiên bạn có thể cài đặt lên VM-Base

Trước tiên chúng tôi sẽ tạo một fake-api để test,

kubectl run fake-api --image=gsviec/fake-api:latest --port=8080
kubectl expose pod fake-api --type=NodePort

Sau đó chúng ta sẽ deploy krakend thông qua kubectl

apiVersion: apps/v1
kind: Deployment
metadata:
  name: krakend-deployment
spec:
  selector:
    matchLabels:
      app: krakend
  replicas: 2
  template:
    metadata:
      labels:
        app: krakend
    spec:
      containers:
      - name: krakend
        image: gsviec/krakend
        ports:
        - containerPort: 8080
        imagePullPolicy: Always
        command: [ "/usr/bin/krakend" ]
        args: [ "run", "-d", "-c", "/etc/krakend/krakend.json", "-p", "8080" ]

---
apiVersion: v1
kind: Service
metadata:
  name: krakend
spec:
  type: NodePort
  ports:
  - name: http
    port: 8000
    targetPort: 8080
    protocol: TCP
  selector:
    app: krakend

---

piVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: backend-application-jwt
spec:
  rules:
  - host: krakend.gsviec.com
    http:
      paths:
      - path: /
        backend:
          serviceName: krakend
          servicePort: 8000

trong đó image dockerfile chúng tôi sữ dụng có dạng như sau:

FROM devopsfaith/krakend
COPY krakend.json /etc/krakend/krakend.json

và tập tin quan trọng nhất kradken.json

$ cat krakend.json 
{
    "version": 2,
    "name": "KrakenD on k8s",
    "cache_ttl": "3600s",
    "timeout": "3s",
    "host": [ "https://jsonplaceholder.typicode.com" ],
    "endpoints": [
        {
            "endpoint": "/debug",
            "backend": [
                {
                    "host": [ "http://krakend:8000" ],
                    "url_pattern": "/__debug/debug"
                }
            ]
        },
        {
            "endpoint": "/combination/{id}",
            "backend": [
                {
                    "url_pattern": "/posts?userId={id}",
                    "is_collection": true,
                    "mapping": { "collection": "posts" }
                },
                {
                    "url_pattern": "/users/{id}",
                    "mapping": { "email": "personal_email" }
                }
            ]
        },
        {
          "endpoint": "/splash",
          "backend": [
            {
              "host": [ "http://fake-api:8080" ],
              "url_pattern": "/shop/campaigns.json",
              "whitelist": [ "campaigns" ]
            },
            {
              "host": [ "http://fake-api:8080" ],
              "url_pattern": "/shop/products.json",
              "whitelist": [ "products" ]
            }
          ]
        }
    ]
}

Bạn có thể tìm hiểu krakend tại đây để hiểu thêm https://www.krakend.io/docs/backends/data-manipulation/

sau đó bạn truy cập http://krakend.gsviec.com/ hoặc tuỳ domain mà bạn định nghĩa trong phần ingress của tập tin values.yaml.

kiểm tra lại coi thử các pod chạy ok chưa:

[email protected]:~/kong/krakend-helm$ kubectl get pods
NAME                                                          READY   STATUS    RESTARTS   AGE
backend-application-c47b87584-kd2mf                           1/1     Running   0          25h
fake-api                                                      1/1     Running   0          5m34s
krakend-79c8b864fb-n6t6c                                      0/1     Running   3          93s
mysql-6d699d98c8-ddd55                                        2/2     Running   0          26h
nginx-ingress-ingress-nginx-controller-7b8856fb8b-xvrkz       1/1     Running   0          26h
nginx-ingress-ingress-nginx-defaultbackend-7d975b6f7c-6ghcj   1/1     Running   0          26h

Kiểm tra

curl -I  https://krakend.gsviec.com/combination/10
HTTP/1.1 200 OK
Cache-Control: public, max-age=3600
Content-Type: application/json; charset=utf-8
Date: Fri, 27 Nov 2020 05:14:35 GMT
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Krakend: Version 1.2.0
X-Krakend-Completed: true
X-Powered-By: DevOps-NFQ
Content-Length: 2784
Connection: keep-alive

{"address":{"city":"Lebsackbury","geo":{"lat":"-38.2386","lng":"57.2232"},"street":"Kattie Turnpike","suite":"Suite 198","zipcode":"31428-2261"},"company":{"bs":"target end-to-end models","catchPhrase":"Centralized empowering task-force","name":"Hoeger LLC"},"id":10,"name":"Clementina DuBuque","personal_email":"[email protected]","phone":"024-648-3804","posts":[{"body":"libero voluptate eveniet aperiam sed\nsunt placeat suscipit molestias\nsimilique fugit nam natus\nexpedita consequatur consequatur dolores quia eos et placeat","id":91,"title":"aut amet sed","userId":10},{"body":"aut et excepturi dict

Debug

curl -i https://krakend.gsviec.com/debug
HTTP/1.1 200 OK
Cache-Control: public, max-age=3600
Content-Type: application/json; charset=utf-8
Date: Fri, 27 Nov 2020 05:15:11 GMT
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Krakend: Version 1.2.0
X-Krakend-Completed: true
X-Powered-By: DevOps-NFQ
Content-Length: 18
Connection: keep-alive

{"message":"pong"}

Cuối cùng là get tập hơn các kết quả trả từ api backend

curl -i https://krakend.gsviec.com/splash
HTTP/1.1 200 OK
Cache-Control: public, max-age=3600
Content-Type: application/json; charset=utf-8
Date: Fri, 27 Nov 2020 05:16:15 GMT
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Krakend: Version 1.2.0
X-Krakend-Completed: true
X-Powered-By: DevOps-NFQ
Content-Length: 2465
Connection: keep-alive


{
   "campaigns":[
      {
         "discounts":[
            {
               "discount":0.15,
               "id_product":1
            },
            {
               "discount":0.50,
               "id_product":2
            },
            {
               "discount":0.25,
               "id_product":3
            }
         ],
         "end_date":"2017/02/15",
         "id_campaign":1,
         "name":"Saint Calentine",
         "start_date":"2017/02/10"
      },
      {
         "discounts":[
            {
               "discount":0.2,
               "id_product":1
            },
            {
               "discount":0.1,
               "id_product":2
            },
            {
               "discount":0.1,
               "id_product":3
            }
         ],
         "end_date":"2017/09/15",
         "id_campaign":2,
         "name":"Summer break",
         "start_date":"2017/06/01"
      }
   ],
   "products":[
      {
         "body_html":"\u003cp\u003eIt's the small iPod with one very big idea: Carrying files like an animal. Now the world's most popular music player, available in 8PB models, lets you enjoy TV shows, movies, video podcasts, and more. The larger, brighter display means amazing picture quality. In six eye-catching colors, iPod Maño is stunning all around. And with models starting at just $149, little speaks volumes.\u003c/p\u003e",
         "created_at":"2017-03-16T13:03:15-04:00",
         "handle":"ipod-nano",
         "id":1,
         "image":{
            "created_at":"2017-03-16T13:03:15-04:00",
            "id":850703190,
            "position":1,
            "product_id":1,
            "src":"https://cdn.your-site.co/ipod-manyo.png",
            "updated_at":"2017-03-16T13:03:15-04:00"
         },
         "product_type":"Cult Products",
         "published_at":"2007-12-31T19:00:00-05:00",
         "published_scope":"web",
         "tags":"Emotive, Flash Memory, MP3, Music",
         "template_suffix":null,
         "title":"IPod Maño - 8PB",
         "updated_at":"2017-03-16T13:03:15-04:00",
         "vendor":"Apple"
      },
      {
         "body_html":"\u003cp\u003eMcBook Er surpasses its previous model by removing the thunderbolt 3 port and adding the ultrafast Stormybolt 1. Conversors from USB -\u003e Thunderbolt 3 -\u003e Stormybolt 1 are sold separately.\u003c/p\u003e",
         "created_at":"2017-03-16T13:03:15-04:00",
         "handle":"ipod-touch",
         "id":2,
         "image":null,
         "product_type":"Cult Products",
         "published_at":"2008-09-25T20:00:00-04:00",
         "published_scope":"global",
         "tags":"",
         "template_suffix":null,
         "title":"McBook Er?",
         "updated_at":"2017-03-16T13:03:15-04:00",
         "vendor":"Apple"
      },
      {
         "body_html":"\u003cp\u003eThe iPhone8 introduces improved voice recognition. Siri is replaced with Chari and introduces amazing capabilities such as the interpretation of commands like 'tira pa casa' (Maps to home) or 'vente pacá' (share your location).\u003c/p\u003e",
         "created_at":"2017-03-16T13:03:15-04:00",
         "handle":"iphone-8",
         "id":3,
         "image":null,
         "product_type":"Cult Products",
         "published_at":"2018-09-25T20:00:00-04:00",
         "published_scope":"global",
         "tags":"",
         "template_suffix":null,
         "title":"iPhone 8",
         "updated_at":"2019-03-16T13:03:15-04:00",
         "vendor":"Apple"
      }
   ]
}

Như bạn thấy kết quả nó trả về có chứa 2 endpoint service products, và campaigns, nếu như bạn dùng cách thông thường thì bạn sẽ cần gọi 2 requests đến 2 services đó.

Kết luận

Với việc dùng krakend cho api Composite chúng ta đã giải quyết được bài toán call một request nhưng gọi được nhiều service với nhau, mà không cần phải can thiệp vào phần code base

Trên đây tôi đã tóm tắt và đưa ra khái niệm cũng như  các dùng cơ bản api composite, với những ưu điểm trên thì khi dùng api composite ta sẽ cũng có những nhược điểm tôi sẽ giới thiệu bài viết sau.

Nói bạn nào cần tư vấn hỗ trợ thì hãy để bình luận bên dưới, hoặc gửi qua mail [email protected] để chúng tôi có thể tư vấn kỹ hơn.

Leave a Reply

Your email address will not be published. Required fields are marked *