This blog shows how the Client Proxy (CP) can be used to consume any public REST service. The features used in this blog will be available from ABAP Platform 2022 and the corresponding SP’s in SAP Note: 2512479.
For our example, the PetStore-V3 REST API from swagger has been used. Since it is based on the Open API 3.0 standard and has no authorization headers, so the setup is easy. We will use public HTTP endpoints of the service to perform typical CRUD ( Create, Retrieve, Update, Delete ) operations. Although any public REST service can be consumed via CP, it is really helpful if it is based on Open API 3.0 because then the field mapping from JSON to ABAP is easy to infer.
Analyzing the Service
Before we can consume the service we should perform the following analytical tasks to better understand the service we are going to consume and also the corresponding CP coding:
- Identifying Entities
- Identifying Endpoints
In our case, we do this via postman but you can use any method of preference.
Please note that this step is entirely optional but highly recommended, if you want to skip this section go directly to “Consuming Service via CP” heading
Importing the service definition in Postman
Download the Open API 3.0 definition for the service and do the following:
- Go to Workspaces->My Workspace (Or any other in your Postman).
- Click on APIs.
- Click on Import button and open the JSON file downloaded above.
- A pop will appear as shown below, confirm that the information for Name and Format is as shown here and then click the Import button.
Identifying Entities
- Expand the newly added entry “Swagger Petstore – OpenAPI 3.0″ in the navigation sub-tree on the left hand-side, then click on draft and then the Definition Tab as highlighted below.
- Here you can see all components, paths and other information for the service. For our purpose, we are going to consume the Pet component only.
- Take note of the JSON structure of this object and get an understanding for all fields names, types and nesting. For example: the Tag and Category components are contained within the Pet.
Identifying Endpoints
To view and call all the API HTTP endpoints, first set the environment variable correctly.
1. Click on draft -> Swagger Petstore – OpenAPI -> Variables and set the baseURL to https://petstore3.swagger.io/api/v3.
2. Navigate to Collections in left-most Navigation pane and click on the PetStore collection. All API endpoints should now be working.
For this example we will use the highlighted requests only, take a note of these as we will refer to them often throughout the tutorial. They have been listed here again for convenience:
- Find pet by id
- Update a pet in the store
- Update an existing Pet
- Add a new pet to pet store
- Delete a pet
Now that we have analyzed the service and decided what we want to consume, we can start our work in ABAP!
Consuming Service via CP
Following classes must be defined for consuming the service:
- The interface for structure types and constants
- The client proxy model
- The client to consume the service
Each of these is described in detail in the sections below. Just copy the code snippets in order and by the end you will have all three classes. All blocks of code have been explained thoroughly.
Note: when copying the code in this blog replace the suffix ZAF_ with your own one
Interface for structure types and constants
Create a new interface and give it a suitable name e.g. “zaf_if_petstore_types“.
To facilitate our other classes and for cleanliness, we will group together constants and structure types in this interface. Copy the ABAP code below in your interface class.
Structure types
The PET structure with all its underlying entities and fields has to be defined as shown. Since it contains the TAG and CATEGORY entities they have to be defined before.
ABAP definition
TYPES:
BEGIN OF tys_category,
id TYPE i,
name TYPE string,
END OF tys_category,
BEGIN OF tys_tag,
id TYPE i,
name TYPE string,
END OF tys_tag,
BEGIN OF tys_pet,
id TYPE i,
name TYPE string,
category TYPE tys_category,
photo_urls TYPE STANDARD TABLE OF string WITH DEFAULT KEY,
tags TYPE STANDARD TABLE OF tys_tag WITH DEFAULT KEY,
status TYPE string,
END OF tys_pet.
The definition is based on the JSON structure of the entity. Looking at the XML response of a get request, we get an idea of teh structure. A more precise way is to check the Open API 3.0 schema definition via Postman
XML response of a get request (DO NOT COPY!)
<Pet>
<category>
<id>0</id>
<name>Pug</name>
</category>
<id>3</id>
<name>doggie</name>
<photoUrls>
<photoUrl>axyz.in</photoUrl>
<photoUrl>axyz.in</photoUrl>
<photoUrl>axyz.in</photoUrl>
</photoUrls>
<status>available</status>
<tags>
<tag>
<id>22</id>
<name>dog</name>
</tag>
</tags>
</Pet>
Constants
Next we define resource names and paths for each endpoint that we want to consume. So for all five endpoints identified previously, we have to define a resource path/name.
For instance:
To call the API endpoint: /pet/4
the resource path /pet{id} has to be defined, where {id} is the placeholder for id parameter.
Similarly, we do this for all the other endpoints as well.
Therefore the following constants have to be defined:
- gcs_resourcse_paths, which contains the entire path with placeholders for parameters.
- gcs_resource_names is simply a name we use internally, you can choose whatever you want
Copy and paste this code in your interface class to define the constants
BEGIN OF gcs_resource_names,
pets TYPE /iwbep/if_v4_rest_types=>ty_internal_name VALUE `PETS`,
pet_id TYPE /iwbep/if_v4_rest_types=>ty_internal_name VALUE `PET_ID`,
pet_id_name_status TYPE /iwbep/if_v4_rest_types=>ty_internal_name VALUE `PET_ID_NAME_STATUS`,
END OF gcs_resource_names,
BEGIN OF gcs_resource_paths,
pets TYPE string VALUE `/pet`,
pet_id TYPE string VALUE `/pet/{id}`,
pet_id_name_status TYPE string VALUE `/pet/{id}?name={name}&status={status}`,
END OF gcs_resource_paths.
Now the interface class is complete, next the Client Proxy Model has to be defined.
Defining the Client Proxy Model.
The Client Proxy Model performs these tasks:
- Defines the structure for entities to be consumed using ABAP structures
- Defines resources for each http endpoint.
- Define one or more operations on each resource.
Create a new class e.g. zaf_cl_rest_petstore_model and copy paste the code snippets in this section one-by-one, in order.
Class Definition
- The public method /iwbep/if_v4_mp_basic_rest~define is an interface method which must be implemented by every consumption model class.
- define_pet defines our resource to be consumed and takes as input the model object
- All models must inherit the /iwbep/cl_v4_abs_model_prov base class.
CLASS zaf_cl_rest_petstore_model DEFINITION
PUBLIC
INHERITING FROM /iwbep/cl_v4_abs_model_prov
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
METHODS /iwbep/if_v4_mp_basic_rest~define REDEFINITION.
PRIVATE SECTION.
"! <p class="shorttext synchronized" lang="en">Define the structure type and resources for Pet</p>
"!
"! @parameter io_model | <p class="shorttext synchronized" lang="en">Proxy model</p>
"! @raising /iwbep/cx_gateway | <p class="shorttext synchronized" lang="en">Gateway exception</p>
METHODS define_pet
IMPORTING
io_model TYPE REF TO /iwbep/if_v4_rest_model
RAISING
/iwbep/cx_gateway .
ENDCLASS.
Class Implementation
Both methods are implemented using the code in snippets below. Just copy and paste the code snippets and everything should work. Important points are explained for each snippet
Method /iwbep/if_v4_mp_basic_rest~define .
This method just calls the inner method and passes the io_model parameter.
CLASS zaf_cl_rest_petstore_model IMPLEMENTATION.
METHOD /iwbep/if_v4_mp_basic_rest~define.
define_pet( CAST /iwbep/if_v4_rest_model( io_model ) ).
ENDMETHOD.
Method define_pet.
The main method where we define the structure types, resources and operations that can be performed on the service.
Data Declaration
- Each of the three entities to be consumed need an ABAP structure for structure definition.
METHOD define_pet.
DATA:
ls_data_container_pet TYPE zaf_if_petstore_types=>tys_pet,
ls_data_container_tag TYPE zaf_if_petstore_types=>tys_tag,
ls_data_container_category TYPE zaf_if_petstore_types=>tys_category,
lo_structured_type TYPE REF TO /iwbep/if_v4_rest_struc_type,
lo_resource TYPE REF TO /iwbep/if_v4_rest_resource,
lo_operation TYPE REF TO /iwbep/if_v4_rest_operation.
Defining Structures
- The nested structure types Tag and Category must be defined first, followed by Pet
- All primitive property names must be lowercase to match the JSON field names.
- Since the Pet structure contains Tag and Category, they must be added as properties to the Pet Type
*Define Category
lo_structured_type = io_model->create_struct_type_by_struct(
iv_name = zaf_if_petstore_types=>gcs_internal_struct_type_names-category
is_structure = ls_data_container_category
iv_do_gen_prim_props = abap_true ).
lo_structured_type->camelcase_lower_prim_prp_names( ).
*Define Tag
lo_structured_type = io_model->create_struct_type_by_struct(
iv_name = zaf_if_petstore_types=>gcs_internal_struct_type_names-tag
is_structure = ls_data_container_tag
iv_do_gen_prim_props = abap_true ).
lo_structured_type->camelcase_lower_prim_prp_names( ).
*Define Pet
lo_structured_type = io_model->create_struct_type_by_struct(
iv_name = zaf_if_petstore_types=>gcs_internal_struct_type_names-pet
is_structure = ls_data_container_pet
iv_do_gen_prim_props = abap_true
iv_do_gen_prim_prop_colls = abap_true ).
lo_structured_type->camelcase_lower_prim_prp_names( ).
lo_structured_type->create_structured_property( 'CATEGORY'
)->set_external_name( 'category'
)->set_structured_type( zaf_if_petstore_types=>gcs_internal_struct_type_names-category ).
lo_structured_type->create_structured_property( 'TAGS'
)->set_external_name( 'tags'
)->set_structured_type( zaf_if_petstore_types=>gcs_internal_struct_type_names-tag )->set_is_collection( ).
Defining Resources and Operations
- Resources are defined for each unique http endpoint/path.
- The import parameters for the method create_resource are filled using the corresponding constants defined in the interface.
- For parameters inside the path template, a structure type must also be defined using set_path_params_struct_type. Example
Given this path template: /pet/{id}
the structured type must contain one primitive property (e.g. with the name ID), that has the external name id, in our case this is simply the pet structure type. - Operations are defined on a resource using an HTTP verb, and can further have a request/response body
- The response body and the request body can also be provided a structure type depending on the type of operation being performed. Example
GET /pet/{id} has a response body with type PET but no request body
POST /pet has a response and request body with type PET. - For certain unique operations such as delete in this case, an operation may not have a structure type for a request body and response body both.
- For delete, the response is simple JSON “pet_deleted”, which doesn’t correspond to any type.
lo_resource = io_model->create_resource( iv_name = zaf_if_petstore_types=>gcs_resource_names-pet_id
iv_path_template = zaf_if_petstore_types=>gcs_resource_paths-pet_id ).
lo_resource->set_path_params_struct_type( zaf_if_petstore_types=>gcs_internal_struct_type_names-pet
)->create_operation( /iwbep/if_v4_rest_types=>gcs_http_method-get
)->create_response_body(
)->set_structured_type( zaf_if_petstore_types=>gcs_internal_struct_type_names-pet ).
*Delete
lo_resource->set_path_params_struct_type( zaf_if_petstore_types=>gcs_internal_struct_type_names-pet
)->create_operation( /iwbep/if_v4_rest_types=>gcs_http_method-delete
)->create_response_body( ).
*Update Status and Name
io_model->create_resource( iv_name = zaf_if_petstore_types=>gcs_resource_names-pet_id_name_status
iv_path_template = zaf_if_petstore_types=>gcs_resource_paths-pet_id_name_status
)->set_path_params_struct_type( zaf_if_petstore_types=>gcs_internal_struct_type_names-pet
)->create_operation( /iwbep/if_v4_rest_types=>gcs_http_method-post
)->create_response_body(
)->set_structured_type( zaf_if_petstore_types=>gcs_internal_struct_type_names-pet ).
lo_resource = io_model->create_resource( iv_name = zaf_if_petstore_types=>gcs_resource_names-pets
iv_path_template = zaf_if_petstore_types=>gcs_resource_paths-pets ).
*Create
lo_operation = lo_resource->create_operation( /iwbep/if_v4_rest_types=>gcs_http_method-post ).
lo_operation->create_request_body(
)->set_structured_type( zaf_if_petstore_types=>gcs_internal_struct_type_names-pet ).
lo_operation->create_response_body(
)->set_structured_type( zaf_if_petstore_types=>gcs_internal_struct_type_names-pet ).
*Update with put
lo_operation = lo_resource->create_operation( /iwbep/if_v4_rest_types=>gcs_http_method-put ).
lo_operation->create_request_body(
)->set_structured_type( zaf_if_petstore_types=>gcs_internal_struct_type_names-pet ).
lo_operation->create_response_body(
)->set_structured_type( zaf_if_petstore_types=>gcs_internal_struct_type_names-pet ).
END METHOD.
END CLASS.
This concludes our model class, next we will define the client which will be used to execute the model operations.
Defining the client to consume the service
Create a new class in the same package as the model and give it a suitable name e.g. zaf_cl_rest_petstore_client.
Just like in the previous section, keep copying the code snippets in order of appearance. Each snippet is accompanied by a description of main concepts.
Class Definition.
The class has overall five methods, each corresponding to an operation on the API. In the Analysis section we identified five operations that we want to perform using CP, you can check them out again for reference.
For each of these operations, we will define a method, there’s also method for instantiating the client proxy object. The code snippet below defines all these methods for you. The comments also explain the purpose in detail.
CLASS zaf_cl_rest_petstore_client DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
METHODS CONSTRUCTOR raising /iwbep/cx_gateway.
"! <p class="shorttext synchronized" lang="en">Create a Pet</p>
"! @parameter is_pet | <p class="shorttext synchronized" lang="en">typed structure containing create data</p>
"! @parameter rs_pet | <p class="shorttext synchronized" lang="en">typed structure containing response data from server </p>
"! @raising /iwbep/cx_gateway | <p class="shorttext synchronized" lang="en"></p>
METHODS pet_create
IMPORTING
is_pet TYPE zaf_if_petstore_types=>tys_pet
RETURNING
VALUE(rs_pet) TYPE zaf_if_petstore_types=>tys_pet
RAISING
/iwbep/cx_gateway.
"! <p class="shorttext synchronized" lang="en">Delete a Pet with supplied id</p>
"! This method does not return a json response body which can be serialized in to abap structure, so the http code is returned.
"! @parameter iv_id | <p class="shorttext synchronized" lang="en"></p>
"! @parameter rv_http_status_code | <p class="shorttext synchronized" lang="en"></p>
"! @raising /iwbep/cx_gateway | <p class="shorttext synchronized" lang="en"></p>
METHODS pet_delete
IMPORTING
iv_id TYPE i
RETURNING
VALUE(rv_http_status_code) TYPE i
RAISING
/iwbep/cx_gateway.
"! <p class="shorttext synchronized" lang="en">Get a pet with supplied id</p>
"!
"! @parameter iv_id | <p class="shorttext synchronized" lang="en">The id of the pet</p>
"! @parameter rs_pet | <p class="shorttext synchronized" lang="en">Returned pet as ABAP structure, complete with deep fields.</p>
"! @raising /iwbep/cx_gateway | <p class="shorttext synchronized" lang="en"></p>
METHODS pet_read_by_id
IMPORTING
iv_id TYPE i
RETURNING
VALUE(rs_pet) TYPE zaf_if_petstore_types=>tys_pet
RAISING
/iwbep/cx_gateway.
"! <p class="shorttext synchronized" lang="en">Update a pet using PUT</p>
"! @parameter is_pet | <p class="shorttext synchronized" lang="en">typed structure containing update data</p>
"! @parameter rs_pet | <p class="shorttext synchronized" lang="en">typed structure containing response data from server </p>
"! @raising /iwbep/cx_gateway | <p class="shorttext synchronized" lang="en"></p>
METHODS pet_update
IMPORTING
is_pet TYPE zaf_if_petstore_types=>tys_pet
RETURNING
VALUE(rs_pet) TYPE zaf_if_petstore_types=>tys_pet
RAISING
/iwbep/cx_gateway.
"! <p class="shorttext synchronized" lang="en">Update the name and status of the pet having the supplied ID</p>
"! The variables to be updated are sent as query parameters. The request type is POST
"! @parameter iv_id | <p class="shorttext synchronized" lang="en">ID of the pet that is to be updated.</p>
"! @parameter iv_name | <p class="shorttext synchronized" lang="en">new name for the pet</p>
"! @parameter iv_status | <p class="shorttext synchronized" lang="en">new status for the pet</p>
"! @parameter rs_pet | <p class="shorttext synchronized" lang="en">Updated pet </p>
"! @raising /iwbep/cx_gateway | <p class="shorttext synchronized" lang="en"></p>
METHODS pet_update_name_and_status
IMPORTING
iv_id TYPE i
iv_name TYPE zaf_if_petstore_types=>tys_pet-name
iv_status TYPE zaf_if_petstore_types=>tys_pet-status
RETURNING
VALUE(rs_pet) TYPE zaf_if_petstore_types=>tys_pet
RAISING
/iwbep/cx_gateway.
PRIVATE SECTION.
DATA: mo_client_proxy TYPE REF TO /iwbep/if_cp_client_proxy_rest,
mo_http_client TYPE REF TO if_http_client.
METHODS create_client_proxy
RETURNING
VALUE(ro_client_proxy) TYPE REF TO /iwbep/if_cp_client_proxy_rest
RAISING
/iwbep/cx_gateway.
ENDCLASS.
Class Implementation
The implementation of each method is very similar. Using method chaining, we add the necessary information to carry out each request and also provide the payload data if required. For some methods we also receive the response data typed as PET object. The code in these sections should be self-explanatory, in case of questions just write a comment.
First add the implementation class header, followed by all the method definitions.
CLASS zaf_cl_rest_petstore_client IMPLEMENTATION.
Methods
Constructor
METHOD constructor.
mo_client_proxy = create_client_proxy( ).
ENDMETHOD.
Pet_create
METHOD pet_create.
*https://petstore3.swagger.io/api/v3/pet POST
mo_client_proxy->create_resource( zaf_if_petstore_types=>gcs_resource_names-pets
)->create_request( /iwbep/if_v4_rest_types=>gcs_http_method-post
)->set_body_data( is_pet
)->execute(
)->get_body_data( IMPORTING ea_body_data = rs_pet ).
ENDMETHOD.
Pet_delete
METHOD pet_delete.
*https://petstore3.swagger.io/api/v3/pet DELETE
DATA ls_key TYPE zaf_if_petstore_types=>tys_pet.
rv_http_status_code = mo_client_proxy->create_resource( zaf_if_petstore_types=>gcs_resource_names pet_id
)->set_path_template_parameters( ls_key
)->create_request( /iwbep/if_v4_rest_types=>gcs_http_method-delete
)->execute( )->get_http_status_code( ).
ENDMETHOD.
Pet_read_by_id
METHOD pet_read_by_id.
*https://petstore3.swagger.io/api/v3/pet/{id} GET
mo_client_proxy->create_resource( zaf_if_petstore_types=>gcs_resource_names-pet_id
)->set_path_template_parameters( VALUE zaf_if_petstore_types=>tys_pet( id = iv_id )
)->create_request( /iwbep/if_v4_rest_types=>gcs_http_method-get
)->execute(
)->get_body_data( IMPORTING ea_body_data = rs_pet ).
ENDMETHOD.
Pet_update
METHOD pet_update.
*https://petstore3.swagger.io/api/v3/pet PUT
mo_client_proxy->create_resource( zaf_if_petstore_types=>gcs_resource_names-pets
)->create_request( /iwbep/if_v4_rest_types=>gcs_http_method-put
)->set_body_data( is_pet
)->execute(
)->get_body_data( IMPORTING ea_body_data = rs_pet ).
ENDMETHOD.
Pet_update_name_and_status
METHOD pet_update_name_and_status.
*https://petstore3.swagger.io/api/v3/pet/{id}?name={name}&status={status} POST
mo_client_proxy->create_resource( zaf_if_petstore_types=>gcs_resource_names-pet_id_name_status
)->set_path_template_parameters(
VALUE zaf_if_petstore_types=>tys_pet(
id = iv_id
name = iv_name
status = iv_status )
)->create_request( /iwbep/if_v4_rest_types=>gcs_http_method-post
)->execute(
)->get_body_data( IMPORTING ea_body_data = rs_pet ).
ENDMETHOD.
Create_client_proxy
METHOD create_client_proxy.
DATA:
ls_proxy_model_key TYPE /iwbep/if_cp_registry_types=>ty_s_proxy_model_key,
lv_error_text TYPE string.
cl_http_client=>create_by_url(
EXPORTING
url = 'https://petstore3.swagger.io'
IMPORTING
client = mo_http_client
EXCEPTIONS
argument_not_found = 1
plugin_not_active = 2
internal_error = 3
pse_not_found = 4
pse_not_distrib = 5
pse_errors = 6
OTHERS = 7 ).
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 INTO lv_error_text.
RAISE EXCEPTION TYPE lx_rest_json_pl
EXPORTING
iv_error_text = lv_error_text.
ENDIF.
"Proxy model defined in ZAF_CL_REST_PETSTORE_MODEL
ls_proxy_model_key = VALUE #( repository_id = /iwbep/if_cp_registry_types=>gcs_repository_id-default
proxy_model_id = 'ZAF_REST_PETSTORE'
proxy_model_version = 0003 ).
ro_client_proxy ?= /iwbep/cl_cp_client_proxy=>create_rest_remote_proxy(
is_proxy_model_key = ls_proxy_model_key
io_http_client = mo_http_client
iv_do_fetch_csrf_token = abap_false
iv_relative_service_root = '/api/v3').
ENDMETHOD.
Now that we have created both the Model and Client, we have to register the client proxy and setup the SSL certificate for the remote service.
Register Client Proxy
Before we can use our proxy model, it must be registered. Perform the following steps to register it:
- Open the Transaction /IWBEP/CP_ADMIN
- Click on Create and enter the details as shown below
Proxy Model ID | *You can choose any value e.g ZAF_REST_PETSTORE |
Version | 1 |
Model Provider Class | *Enter name of your proxy model class |
Description | *Enter any description |
Package | $TMP |
After successfully completing these steps your proxy model should appear in the list of models in the transaction.
Adding SSL certificate for the remote service
The SSL certificate for the remote service https://petstore3.swagger.io/ has to be added in the ABAP system before it can be accessed.
Executing the Client Class Methods
Congratulations if you have come this far! Now the last step is to use our Client and Proxy Model classes to create unit tests which actually consume the service. The unit test class has one method which performs all CRUD operations and then compares actual vs expected data for each operation.
Copy this code in the unit class:
CLASS zaf_cl_petstore_test DEFINITION DEFERRED.
class zaf_cl_rest_petstore_client definition local friends
zaf_cl_petstore_test.
CLASS zaf_cl_petstore_test DEFINITION
FINAL
FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.
PUBLIC SECTION.
METHODS:
pet_operations FOR TESTING RAISING /iwbep/cx_gateway.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO zaf_cl_rest_petstore_client.
METHODS: setup RAISING /iwbep/cx_gateway.
ENDCLASS.
CLASS zaf_cl_petstore_test IMPLEMENTATION.
METHOD pet_operations.
DATA:
ls_payload TYPE zaf_if_petstore_types=>tys_pet,
ls_response_exp TYPE zaf_if_petstore_types=>tys_pet,
ls_response_act TYPE zaf_if_petstore_types=>tys_pet,
ls_category TYPE zaf_if_petstore_types=>tys_category,
lv_http_status_code TYPE string,
lv_id TYPE i,
lx_gateway TYPE REF TO /iwbep/cx_gateway.
*CREATE
ls_category = VALUE #(
id = 20
name = 'Persian' ).
ls_payload = VALUE #(
id = 34
name = 'Cat'
status = 'Brand New'
category = ls_category
photo_urls = VALUE #( ( |url_1| ) ) ).
ls_response_exp = ls_payload.
ls_response_act = mo_cut->pet_create( ls_payload ).
"Then the expected pet data should be returned.
cl_abap_unit_assert=>assert_equals( exp = ls_response_exp
act = ls_response_act ).
CLEAR ls_response_act.
*READ BY ID
"When we make a get request for a pet with this id.
lv_id = 34.
ls_response_act = mo_cut->pet_read_by_id( lv_id ).
"Then the expected pet data should be returned.
cl_abap_unit_assert=>assert_equals( exp = ls_response_exp
act = ls_response_act ).
CLEAR ls_response_act.
*UPDATE NAME AND STATUS
ls_response_act = mo_cut->pet_update_name_and_status(
iv_id = 34
iv_name = 'new_name'
iv_status = 'new_status' ).
ls_response_exp-name = 'new_name'.
ls_response_exp-status = 'new_status'.
cl_abap_unit_assert=>assert_equals( exp = ls_response_exp
act = ls_response_act ).
*UPDATE
ls_payload-name = 'Schrodingers Cat'.
ls_payload-status = 'Dead and Alive'.
ls_payload-category = VALUE #(
id = 21
name = 'Mystery Kitty' ).
ls_response_exp = ls_payload.
ls_response_act = mo_cut->pet_update( ls_payload ).
cl_abap_unit_assert=>assert_equals( exp = ls_response_exp
act = ls_response_act ).
*DELETE
lv_http_status_code = mo_cut->pet_delete( 4 ).
"the expected pet data should be returned.
cl_abap_unit_assert=>assert_equals( exp = 200
act = lv_http_status_code ).
ENDMETHOD.
METHOD setup.
mo_cut = NEW zaf_cl_rest_petstore_client( ).
ENDMETHOD.
ENDCLASS.
Once everything is set-up you can execute the unit tests and they should be green!