From d22d639b0c1ca3cf48baef7f35545c77d58d1b0b Mon Sep 17 00:00:00 2001 From: bbrtj Date: Sat, 6 Jul 2024 12:28:56 +0200 Subject: [PATCH] Document Whelk::Wrapper --- Changes | 1 + lib/Whelk/Exception.pm | 3 +- lib/Whelk/Wrapper.pm | 141 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index 5f2fe79..d93dc1f 100644 --- a/Changes +++ b/Changes @@ -1,6 +1,7 @@ Revision history for Whelk {{$NEXT}} + - Added documentation for Whelk::Wrapper 0.04 - 2024-07-06 - Default and example values are now validated before they are put into OpenAPI document diff --git a/lib/Whelk/Exception.pm b/lib/Whelk/Exception.pm index f8b1622..a6240ea 100644 --- a/lib/Whelk/Exception.pm +++ b/lib/Whelk/Exception.pm @@ -26,7 +26,8 @@ Whelk::Exception - Exceptions for your API # no log will be created, but the hint will be returned in the API response Whelk::Exception->throw(403, hint => 'Access denied, not authorized'); - # fatal API error, will not return an API error page but rather regular text / html error page + # fatal API error, will not return an API error page but rather regular + # text / html error page Kelp::Exception->throw(500, body => 'Something went very, very wrong'); =head1 DESCRIPTION diff --git a/lib/Whelk/Wrapper.pm b/lib/Whelk/Wrapper.pm index 25f5525..e869ab9 100644 --- a/lib/Whelk/Wrapper.pm +++ b/lib/Whelk/Wrapper.pm @@ -257,3 +257,144 @@ sub build_response_schemas 1; +__END__ + +=pod + +=head1 NAME + +Whelk::Wrapper - Base class for wrappers + +=head1 SYNOPSIS + + package Whelk::Wrapper::MyWrapper; + + use Kelp::Base 'Whelk::Wrapper'; + + # at the very least, there three methods must be implemented + + sub wrap_server_error + { + my ($self, $error) = @_; + + ...; + } + + sub wrap_success + { + my ($self, $data) = @_; + + ...; + } + + sub build_response_schemas + { + my ($self, $endpoint) = @_; + + ...; + } + +=head1 DESCRIPTION + +Whelk::Wrapper is a base class for wrappers. Wrappers job is to wrap the +endpoint handler in necessary logic: validating request and response data, +adding extra data to responses and error handling. Wrappers do not handle +encoding requests and responses (for example with C), that's a job for +L. + +In addition, wrapper decides how to treat failures. It defines schemas for +errors with status classes 400 and 500 and uses those instead of response +schema defined for the endpoint in case an error occurs. + +Whelk implements two basic wrappers which can be used out of the box: +L (the default) and L. They +are very similar and differ in how they wrap the response data - C +wrapper introduces an extra boolean C field to every response. + +It should be pretty easy to subclass a wrapper if needed. Take a look at the +built in subclasses and at the code of this class to get the basic idea. + +=head1 METHODS + +The only wrapper method called from outside is C. All the other methods +are helpers which make it easier to adjust the behavior without rewriting it +from scratch. + +The base C class does not implement C, +C and C methods - they have to be +implemented in a subclass. + +=head2 wrap + + my $wrapped_sub = $wrapper->wrap($sub); + +Takes a reference to a subroutine and returns a reference to another +subroutine. The returned subroutine is an outer code to be called by Kelp as +route handler. It does all the Whelk-specific behavior and calls the inner +subroutine to get the actual result of the API call. + +=head2 wrap_response + + my $response = $wrapper->wrap_response($response, $http_code); + +This method is used to wrap C<$response> returned by Kelp route handler. The +default implementation takes a look at the C<$http_code> and fires one of +C (for codes 2XX), C (for codes 5XX) or +C (for codes 4XX). The wrapped response must be matching the +respone schema defined in L or else an exception will +be thrown. + +=head2 build_response_schemas + + $wrapper->build_response_schemas($endpoint) + +Takes an object of L class and should set C +field of that object. That field must contain a hash reference where each key +will be response code and each value will be a schema built using +L. Regular success schema should nest the value of C<< +$endpoint->response >> schema inside of it. + +The status codes need not to be exact. By default, only their class is +important (C<200>, C<400> or C<500>). The exact semantics of that mapping is +defined in another method, L. + +If the schema from C<< $endpoint->response >> is empty via C<< +$endpoint->response->empty >> then it must be added to C as +is to correctly be mapped to C<204 No Body> HTTP status. + +=head2 inhale_request + +This is a helper method which validates the request. It may be overridden for +extra behavior. + +To ensure C method works, it must set C<< +$app->req->stash->{request} >> after validating and cleaning the request body. + +=head2 execute + +This is a helper method which runs the actual route handler in a try/catch +block. It may be overridden for extra behavior. + +=head2 prepare_response + +This is a helper method which prepares a response to be passed to +L. It may be overridden for extra behavior. + +=head2 exhale_response + +This is a helper method which validates and returns a response. It may be +overridden for extra behavior. + +=head2 map_code_to_schema + +This is a helper method which decides which key from C of the +endpoint to use based on HTTP code of the response. It may be overridden for +extra behavior. + +=head2 on_error + +This is a helper method which decides what to do when an unexpected error +occurs. By default, it creates an application log and modifies the result +message to return a stock HTTP message like C. It may be +overridden for extra behavior. +