Ticker

6/recent/ticker-posts

GraphQL và Rest

    Như ở bài viết trước chúng ta đã hiểu được cơ bản về GraphQL là gì rồi. Ở bài viết này chúng ta cùng tìm hiểu những cái hay cái dở của GraphQL & Rest để có những góc nhìn tốt hơn, có những hiểu biết để đánh giá xem đâu là cái phù hợp để áp dụng, hay là áp dụng cả hai để tận dụng nhiều nhất điểm mạnh của chúng.

    Trước hết, về quan điểm cá nhân. Chúng ta cũng không nên quá ưu ái về một công nghệ nào đó, mỗi thứ đều có mạnh cái yếu của riêng nó; và công nghệ cụ thể nào đó nó cũng chỉ là thứ nhất thời, rồi sẽ lại sinh ra những công nghệ hay hơn, mạnh hơn, khắc phục được những điểm yếu của những công nghệ trước kia. Cái mà mỗi chúng ta cần, là phải là hiểu được nó, sử dụng một cách khéo léo để công nghệ đáp ứng vào các dự án thực tiễn.

Bài viết này sẽ đi theo vài gạch đầu dòng như sau:

1. Tổng quan về GraphQL & Rest

2. Nhìn nhận GraphQL & rest trong các vấn đề

3. GraphQL hay Rest?

[Đây hoàn toàn là ý kiến đánh giá chủ quan của cá nhân. Nếu các bạn có những góc nhìn khác, xin vui lòng chia sẻ nó]

1. Tổng quan về GraphQL & Rest

Rest:
    
Basic Rest

    Rest - viết tắt của "representational state transfer". Main concept của nó là Resource. Các resources như data, service hay object. Mỗi resource này sẽ có một URI riêng và sử dụng các standard HTTP Methods (GET, POST, PUT, DELETE và PATH), client sẽ request theo những URIs này để tương tác với dữ liệu.


GraphQL:

    GraphQL là một ngôn ngữ truy vấn ( "A query language" ) để làm việc với API. Nó cho phép client gửi các Query/Mutation/Subscription tới một URI duy nhất. 

graphQL


    Trong GraphQL, main concept của nó là "Entity Graph", là một tập hợp thông tin dạng biểu đồ. Các entity này được xác định bằng GraphQL Schema, đại diện cho các objects. Các đường nối giữa các nút trong biểu đồ đại diện cho mối quan hệ giữa các Entity. Điều này giúp chúng ta có thể lấy được dữ liệu theo các mối quan hệ của các Entity khi thực hiện truy vấn.


2. Nhìn nhận GraphQL & Rest trong các vấn đề

a. Popularity
    Nói về mức độ phổ biến thì rõ ràng là Rest nhỉnh hơn. Nó ra đời cách đây hàng chục năm, chúng ta đã sử dụng nó cho biết bao nhiêu dự án rồi. Tuy nhiên, GraphQL là được sinh ra từ cái lò gạch dát kim cương là - Facebook; và được công khai vào năm 2015. Tuy nó còn rất mới, những nó cũng đã có sự phát triển và được cộng động ủng hộ.

    Để thêm thông tin cho khách quan, cùng xem lại báo cáo về tình hình sử dụng API của SmartBear chúng những năm gần đây. 
    
    Theo "The State of API 2020 Report", thì cho tới năm 2020 vẫn chưa thấy có nhiều sự chiếm lĩnh của GraphQL. Nó chiếm 19% trong khi Rest đang nắm giữ tới 82%.

API 2020 Report

    Dù thế nào thì GraphQL vẫn còn mới. Nó cũng cần thời gian để có thể đạt được như Rest.

b. Usability
    Về khả năng sử dụng, GraphQL và Rest có cách xử lý vấn đề khác nhau, khác hệ tư tưởng thì thật khó để mang chúng lên bàn cân được.
   
   Data fetching? GraphQL ra đời sau nên nó, nên phần nào nó đã khắc phục được những điểm mà Rest chưa làm thực sự tốt. Với cấu trúc linh động nó cho phép chủ động truy vấn dữ liệu ngay từ phía client, không thừa không thiếu dữ liệu. Nó là một giải pháp tuyệt vời để chúng ta có thể xây dựng API có thể thể phục vụ được nhiều clients với những nhu cầu khác nhau. Tuy nhiên, cũng phải đánh đổi nó với việc phải thực hiện GraphQL trên cả client và server.

    Rest thì đã có một thời gian dài để chứng minh về khả năng sử dụng của nó trong cộng đồng. Về việc xử lý dữ liệu động, chúng ta cũng đã làm trong hàng chục năm qua rồi. Nó cũng không phải là bài toán gì mới mẻ; việc tổ chức, xây dựng API phụ thuộc nhiều vào người thiết kế và phát triển. Có rất nhiều cách để xử lý được các bài toán data fetching ở Rest, tuy nhiên chưa có được một cái gì đó được coi là chuẩn chỉ như cách mà GraphQL đã làm.

    Nếu ai đó nói rằng GraphQL dễ phát triển song song hơn cho đội front-end và back-end, thì chắc cũng phải xem xét lại góc nhìn một chút và có thể tham khảo thêm ở bài viết về OpenAPI Specification/Swagger UI. Chúng ta hoàn toàn có thể lên những thiết kế cho Rest bằng những mock server, rồi sử dụng OpenAPI Specification để việc phát triển giữa front-end và back-end trở nên dễ dàng hơn rất nhiều.

    Versioning? Với Rest chúng ta cũng quen với việc sử dụng version khác nhau để đáp ứng được việc tương thích của nhiều client applications. Cách thông thường hay được sử dụng để build ra nhiều version khác nhau trên Laravel là đặt thêm prefix, hay cách thêm vào những parameters để phân biệt version khi tương tác với Rest API. GraphQL có vậy không? Chúng ta cùng xemngay trên trang hướng dẫn của GraphQL :

Versioning
While there's nothing that prevents a GraphQL service from being versioned just like any other REST API, GraphQL takes a strong opinion on avoiding versioning by providing the tools for the continuous evolution of a GraphQL schema.

Why do most APIs version? When there's limited control over the data that's returned from an API endpoint, any change can be considered a breaking change, and breaking changes require a new version. If adding new features to an API requires a new version, then a tradeoff emerges between releasing often and having many incremental versions versus the understandability and maintainability of the API.

In contrast, GraphQL only returns the data that's explicitly requested, so new capabilities can be added via new types and new fields on those types without creating a breaking change. This has led to a common practice of always avoiding breaking changes and serving a versionless API.

    Ý kiến của GraphQL ở đây là: Với ngôn ngữ truy vấn của GraphQL đủ linh hoạt để cho phép những client application cũ bỏ qua được các tính năng mới, dữ liệu mới được thêm vào mà không bị phá vỡ bởi các thay đổi - nghĩa là không cần tới version. Đồng thời họ cũng có nói rằng nếu muốn lập version cho GraphQL thì nó cũng giống như Rest API vậy thôi. 

    Khi tiếp cận một vấn đề mới, một công nghệ mới. Có lẽ cũng phải bỏ đi những quan kiến, thành kiến cũ để đánh giá vấn đề đúng đăn hơn.  Chúng ta cũng đã gặp những câu chuyện so sánh SQL với NoSQL, các frameworks khác nhau hay nhiều ngôn ngữ.

    Upload file? GraphQL bị phàn nàn nhiều nhất về vấn đề không hỗ trợ upload file. Cũng cần lưu ý vấn đề này khi phát triển những hệ thống APIs có chức năng upload file, API Rest có lẽ sẽ là lựa chọn tốt hơn cho vấn đề này. 

    Tuy nhiên, để khắc phục việc GraphQL không hỗ trợ, vẫn có thể sử dụng một thư viện bên thứ ba là GraphQL-Upload hoặc tự kiểm soát bằng việc sử dụng Base64 encode/decode để xử lý file.

c. Performance 
    Over-Fetching/Under-Fetching? Đây cũng là một vấn đề mà gây ra tranh cãi rất nhiều khi so sánh GraphQL và Rest. Cũng nhiều người đưa ra quan điểm không tốt với Rest về việc Over-Fetching/Under-Fetching (trả thừa/trả thiếu dữ liệu).

    Các API Rest thường được thiết kế với cấu trúc cứng với nhiều URIs để trả về dữ liệu, cũng có khi phải thực hiện nhiều requests mới có thể lấy được những dữ liệu liên quan cần thiết. Những vấn đề này cũng làm tăng thời gian để server có thể trả về đủ các dữ liệu cần. Ngược lại, GraphQL thì sử dụng truy vấn linh hoạt cho phép client lấy những gì nó muốn trong một lần request API.

=> Nhưng để một thiết kế API Rest chưa được tốt để so sánh với tính năng vốn dĩ là mục đích sinh ra của GraphQL thì cũng chưa được công bằng.  Việc thiết kế những API linh động, hợp lý cần nhiều kinh nghiệm, cách tổ chức của người phát triển.

    Caching? Ở mặt này thì có vẻ như Rest chiếm ưu thế hơn. API Rest tận dụng được cơ chế lưu vào bộ nhớ đệm của HTTP để trả về các request đã lưu vào cache nhanh hơn. Mặc định thì GraphQL chưa tự động làm được điều này. Chúng ta phải tự xử lý nó, hoặc sử dụng những thư viện bên thứ ba như ApoloClient hay Relay ... để thực hiện cache ngay trên client.

    Unpredictable Execution? Dựa trên biểu đồ quan hệ của các Entity ( Entity Graph) đã rất thuận tiện để lấy ra những dữ liệu cần thiết từ nhiều objects có quan hệ với nhau. Đây là điểm mạnh của GraphQL nhưng nó cũng mang đến những bất lợi trong những bài toán cụ thể. Ngay cả với một cấu trúc API Rest thiết kế không tốt thì cũng đều gặp gặp phải những vấn đề về Query In Indefinite Depth. Điều này cũng đã bắt gặp ở rất nhiều trường hợp khi lấy dữ liệu phức tạp sử dụng Eloquent relation trên Laravel, đó là N+1 query:

owner(id: '6626') {
  id
  name
  item {
    id
    title
    order {
      order_id
      date
      user {
        id
        city
      }
    }
  }
}

    Khi xây dựng những API cần tối ưu rất cẩn thận về hiệu năng thì với GraphQL sẽ khó tối ưu được truy vấn lồng dữ liệu thế này.Ngay cả với, API Rest thì cũng phải có sự tính toán và xử lý một cách khéo léo.

    Index? Một vấn đề nữa chúng ta gặp phải đó là indexTrong những trường hợp cần những truy vấn phức tạp, có những phép tính tổng hợp và các cần các index đặc biệt. Sự thiết kế có vẻ cứng nhắc của API Rest hay sự linh động trong truy vấn dữ liệu của GraphQL sẽ tốt hơn? Cái này cũng sẽ cần lưu ý khi lựa chọn Rest hay GraphQL để giải quyết các bài toán cần có hiệu năng cao. 

    Error Handling? Với API Rest thì đã quen với việc sử dụng HTTP status code rồi. Ở GraphQL thì lại luôn trả về HTTP status code là 200, mặc dù query có thành công hay bị lỗi. Khi query GraphQL thì với các error message và stacktrace cũng ta cũng khó khăn trong việc error handling. Để khắc phục những điều này, ở phía client có thể sử dụng thư viện bên thứ ba như apolo-client hay relay ..

d. Security
    Cũng có nhiều quan điểm cho rằng Rest được đánh giá cao hơn trong vấn đề này.  Ví dụ, chúng ta có thể tăng cường độ bảo mật cho API Rest bằng cách triển khai các phương pháp xác thực API như HTTP authentication, hay gửi các sensitive data được gửi trong HTTP headers như sử dụng JWT, ApiKey hay cơ chế của Oauth 2. GraphQL mặc dù cũng hỗ trợ xác thực dữ liệu, nhưng vẫn phải tự mình áp dụng các biện pháp xác thực. Cơ bản thì nó không thể hoàn thiện, chỉn chu được như Rest.
    
    Việc sử dụng các common Schema và để lộ các cấu trúc dữ liệu nội bộ của GraphQL cũng gia tăng thêm các nguy cơ hệ thống bị tấn công Denial-of-Service (DoS).

3.  GraphQL hay Rest?

    Câu hỏi này vô cùng chủ quan, nó phụ thuộc lớn vào yêu cầu dự án của chúng ta.

    Với sự mới mẻ, linh động của GraphQL, khá phù hợp để phát triển các hệ thống kiểu JAMstack. Các hệ thống API mở với nhiều clients có những yêu cầu dữ liệu khác nhau. Các hệ thống triển khai trên nhiều nền tảng web, app, các thiết bị IOT..
    
    Rest lại thuận lợi hơn trong GraphQL trong những dự án kiểu MicroServices, hay những dự án cần phát triển rất nhanh, rất đơn giản. Sẽ không bị mất nhiều thời gian để thiết kế các Schemas trước.
    
    Với các dự án cần ghi nhiều, hay cần xử lý upload file, những bài toán cần tính toán hiệu năng cao, nhiều dữ liệu phức tạp thì việc sử dụng Rest cũng khiến chúng ta đỡ vất vả hơn.
    
    Nếu đang xây dựng một hệ thống APIs mà nó chỉ để sử dụng trong chính ứng dụng của chúng ta, hoặc các trường hợp người sử dụng hạn chế, hãy cứ gắn bó với Rest truyền thống. 

GraphQL và Rest là những công cụ khác nhau cho những công việc khác nhau. Nếu một ngày đẹp trời thích kết hợp cả hai thứ nay trong một hệ thống thì cũng là một điều tuyệt vời.

Have you a nice day! 

Post a Comment

0 Comments