Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Ruby

Thành thạo Exception Handling trong Grape: Custom Errors, Best Practices & AppSignal Integration

Grape là một Ruby framework phổ biến để xây dựng RESTful APIs. Exception handling đóng vai trò quan trọng trong việc đảm bảo stability và reliability của bất kỳ ứng dụng nào, bao gồm cả những cái làm với Grape.

Bài viết này sẽ khám phá cơ bản của Grape exception handling, bao gồm customizing exceptions. Chúng ta cũng sẽ chạm đến một số best practices, và cách tích hợp app của bạn với AppSignal để enhanced error monitoring và management.

Hãy bắt đầu!

Cơ bản của Grape Exception Handling

Trong tutorial này, chúng ta sẽ xem cách handle exceptions trong Grape API được xây dựng trong Rails. Tôi đã tạo một demo job board API cho việc này, và bạn có thể xem source code trên GitHub.

Raising an Exception

Bạn có thể raise một exception trong Grape bằng cách dùng error!. Ví dụ, trong job API được đề cập ở trên, chúng ta có route show trả về một job dựa trên ID. Chúng ta có thể trả về lỗi 404 khi record không có sẵn, như sau:


Khi bạn raise một exception, bạn sẽ muốn handle nó theo cách "unique" — bạn rất có thể sẽ không muốn gửi raised exception cho users của mình.

Trong Ruby, chúng ta có cơ chế mặc định cho exception handling. Nó hoạt động bằng cách wrap code có thể raise exception trong block begin. Block rescue được dùng để handle exception đã được raise.


Vậy đây là trông như thế nào trong một scenario điển hình:


Phương thức rescue_from

Khi bạn raise exceptions, hoặc chúng xảy ra mà không có sự tham gia trực tiếp của bạn, bạn sẽ muốn handle chúng đúng cách. Mặc định, Grape cung cấp phương thức rescue_from. Điều này cho phép bạn chỉ định một block code được thực thi khi defined exceptions được raise.

Vì vậy, để "rescue" hoặc handle lỗi 404 chúng ta raise trước đó trước bất kỳ cái nào khác nảy sinh trong resource jobs, chúng ta có thể dùng phương thức rescue_from. Phương thức được thêm phía trên resource jobs.


Chúng ta cũng có thể chỉ định content type được dùng:


Cách handle exception này quá generic — chúng ta rescue mọi dạng exception và trả về error với status code 404. Điều đó misleading nếu API users mong đợi nhận status code 400.

Chúng ta có thể thay vào đó chỉ định exception chúng ta muốn handle:


Khi chúng ta gặp lỗi ActiveRecord::RecordNotFound, chúng ta sẽ trả về error message với status code 404. Ngược lại, chúng ta sẽ trả về error message với status code 500.

Điều này cho thấy chúng ta có thể cải thiện những gì chúng ta hiện có, nhưng nếu chúng ta muốn một error handler rescue từ tất cả errors? Đó là lúc customizing exceptions xuất hiện.

Tùy chỉnh Exceptions trong Grape cho Ruby

Tùy thuộc vào loại error gặp phải, error handler này nên có thể trả về error message cùng với status code chính xác.

Trước hết, tạo file tên exceptions_handler. Sau đó, chúng ta sẽ di chuyển exception handlers hiện tại vào file đó:


Module ExceptionHandler của chúng ta dùng ActiveSupport::Concern, cho phép truy cập các chức năng như included và class_methods. Trong snippet trên, chúng ta có error handlers trong block included, nên ở đâu module này được include, chúng sẽ có sẵn như đã định nghĩa.

Chúng ta có thể tiến hành xóa error handler từ các file chúng ta đã có trước đó. Sau đó chúng ta có thể include module ExceptionsHandler trong file entry API của chúng ta — api.rb:


Hãy tạo một base error class cho các errors của chúng ta. Class này sẽ chịu trách nhiệm trả về error response.


Class chấp nhận hai keyword parameters: một string message và một status. Nếu không có cái nào được truyền, chúng ta sẽ dùng default.

Trong phương thức body, chúng ta trả về một Rack response. Mặc định, handler rescue_from phải trả về object Rack::Response, gọi error!, hoặc raise một exception.

Chúng ta có thể tiến hành dùng nó trong ExceptionsHandler:


Khi chúng ta gọi endpoint /error, chúng ta sẽ thấy oops được trả về như response. Tại thời điểm này, chúng ta có thể tạo class cho lỗi NotFound.


Class NotFound chỉ chấp nhận message. Vì nó kế thừa từ BaseError, chúng ta không cần trả về Rack::Response lại. Chúng ta có thể tiến hành dùng nó trong ExceptionsHandler như sau:


Bây giờ, nếu chúng ta cố gắng raise một error thủ công như này:


Điều này sẽ hoạt động tốt, nhưng status code sẽ là 500, vì nó trả về response trong class BaseError (vì class BaseError handle error). Để fix đó, chúng ta sẽ cần modify ExceptionHandler để explicitly dùng class NotFound để handle error thay thế.

Vì vậy, bất cứ khi nào error tương ứng với ActiveRecord::RecordNotFound và V1::Exceptions::NotFound được gặp, dùng Exceptions::NotFound. Ngược lại, dùng Exceptions::BaseError.


Bạn thấy rằng chúng ta sẽ cần các block rescue_from specific khi tạo thêm error classes. Chúng ta có thể cải thiện điều này bằng cách dùng case statements:


Et voilà!

Best Practices và Tips

Mặc dù có hàng tá best practices bạn có thể employ cho exception handling, đây là một vài quick tips để follow:

  1. Group related exceptions: Như chúng ta thấy trong code ở trên, grouping related exceptions cho phép chúng ta có maintainable code. Khi số lượng exceptions chúng ta muốn handle tăng lên, chúng ta có thể thêm chúng vào list của chúng ta.
  2. Sử dụng helpers như error! để nhanh chóng raise exceptions. Điều này đơn giản hóa exception handling của bạn.
  3. Tận dụng exception monitoring tools như AppSignal.

AppSignal Integration: Grape cho Ruby

AppSignal giúp bạn monitor và track errors trong applications của bạn. Integrating AppSignal với Grape API của bạn gives you valuable insights vào exceptions. Hướng dẫn này chỉ cho bạn cách integrate AppSignal với Grape API. Bất cứ khi nào error xảy ra trong API của bạn, bạn sẽ thấy nó trong AppSignal dashboard, như thế này:

Thành thạo Exception Handling trong Grape: Custom Errors, Best Practices & AppSignal Integration

Kết thúc

Exception handling là khía cạnh quan trọng của việc phát triển robust APIs. Trong tutorial này, chúng ta đã thấy cách properly handle exceptions trong Grape API. Chúng ta cũng nhìn nhanh qua một số best practices và AppSignal's integration cho Grape.

Exception handling là một quá trình liên tục — cái bạn sẽ cần cải thiện liên tục.

Happy coding!

P.S. Nếu bạn muốn đọc các bài Ruby Magic ngay khi chúng ra mắt, hãy subscribe newsletter Ruby Magic của chúng tôi và không bao giờ bỏ lỡ bất kỳ bài viết nào!

P.P.S. Bạn có biết AppSignal cung cấp Active Record integration? Tìm hiểu thêm.

Thành thạo Exception Handling trong Grape: Custom Errors, Best Practices & AppSignal Integration

Kingsley Chijioke