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 🙂
Mục lục
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:
jenkins@nfq-tools-jenkins:~/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.