MultiValue Tools

 View Only

 Mvis Raise http error from sub routine

Atul kakade's profile image
Atul kakade posted 03-04-2023 17:58

we mainly use mvis with a subroutine, see definition below.  currently, if the input JSON has the wrong input data element we return a JSON array with error string. however, when use this the HTTP return code is always 200. this means other systems have to look for error strings in response. is there a way to raise the HTTP error code to something else other than 200  to something like an error code of 400 to indicate an error occurred? 

Mike Rajkowski's profile image
ROCKETEER Mike Rajkowski

Atul,

You can accomplish what you are trying to do with Vanity URL's.  I am in the process of creating a blog post, but since you asked, I will post it here in the forum first:

Unlock your MultiValue business logic with RESTful APIs

Over the years your MultiValue application has evolved to include additional business logic, enhancing the value of your solution.  To participate in the API Economy (the controlled exchange of digital data and services through APIs), it is important to unlock this value and expose it to modern solutions, so you can do more with MultiValue.

Rocket provides the MultiValue Integration Server (MVIS) so you can create RESTful web services that provide access to your business logic via access to the MultiValue subroutines.  In this how-to document, I will show how to create, or refactor an existing subroutine and utilize the vanity URL feature of MVIS to create a better endpoint. This how to doc covers two reasons to use a vanity URL; one is to deal with the status and the other is to deal with the method.

By default, when you create a subroutine resource in MVIS, it will allow you to use the POST, PUT, DELETE and PATCH methods when accessing the endpoint. There are good reasons to limit the methods used when calling the subroutine to avoid confusion.

MVIS returns a successful status as long as the subroutine completes and returns from the server. The RESTful API returns a status of 200.  Note that the 200 is the message that denotes success. There are times where the developer would want MVIS to return a status other than success for the subroutine.

To handle both situations, we look to vanity URLs as a solution.

To show how this is done we will go through the following steps:

  1. Identify the business logic needed in the subroutine
  2. Create the subroutine to return the response and status
  3. Define the REST API in MVIS

 Identify the business logic needed in the Subroutine

Whether you have your business logic already in a subroutine, or need to create a new server-side subroutine, there are aspects of the initial subroutine that may not be suited for a web API.

In the following example, this simple subroutine gets the credit limit from the CUST.SAMPLE file.

SUBROUTINE CHECK_CREDIT_LIMIT( CREDIT_LIMIT, CUST_NUMBER )

*******************************************************************************

*       Program CHECK_CREDIT_LIMIT

*       Copyright (C) 2022

*******************************************************************************

* Note:  In this example the attribute 15 of the CUST.SAMPLE file, contains

*        the CREDIT.LIMIT and we are just reading that one attribute.

*

*        Your solution should have more business logic than this

*        example.

*******************************************************************************

EQUATE CREDIT.LIMIT TO 15

OPEN 'CUST.SAMPLE' TO FN.CUST THEN

    READV CUST.CREDIT.LIMIT FROM FN.CUST,CUST_NUMBER, CREDIT.LIMIT ELSE CUST.CREDIT.LIMIT = 0

    IF NOT(NUM(CUST.CREDIT.LIMIT)) THEN CUST.CREDIT.LIMIT = 0

END ELSE CUST.CREDIT.LIMIT = 0

CREDIT_LIMIT = OCONV(CUST.CREDIT.LIMIT, "MR2")

RETURN

In this over simplified example, we see the retrieval of specific information from the MultiValue database.  While the same information can be retrieved from a data resource using MVIS, there is a benefit with the subroutine since it only provides a way to retrieve the information, and not the rest of the CRUD operations that exist with the data resource.

After setting up the subroutine in MVIS, the following endpoints are created:


Note that in our example, even though the subroutine only returns the data, MVIS creates POST, PUT, DELETE and PATCH methods. To define a RESTful GET method, we will need to create a vanity URL.

Here’s how to add the definition of the vanity URL to the endpoints.yaml file:

- display-name: check-credit-limit

  method: GET

  path: /hr/check-status-limit/{customerNumber}

  db-operation:

    mvis-account: ACCUTERM

    call:

      subroutine: CHECK_CREDIT_LIMIT

      params:

      - name: response

        position: 1

        type: json

        binding: response-body

        param-direction: OUT

      - name: customerNumber

        position: 2

        type: string

        binding: path-param

        param-direction: IN

Now we have a RESTful GET service that will return the Credit Limit for a specific customer; the only problem is that as long as the subroutine executes, it will return a status 200.  This is not desirable for instances when the customer is not found, or if there are issues with the file.  In these cases, we want the service to return the proper error.   For our subroutines we can have client-side errors ( 400 Series) or server-side errors 500 Series:

For a complete list of errors please see:

Rest API Response Codes And Types Of Rest Requests

For our example we will be using:

·       400 – Bad Request

·       404 – Not Found

·       500 – Internal Server Error

To show the difference from our original example, let’s create a new subroutine based on the original.  We will need to add a parameter to handle the status.

SUBROUTINE CHECK_CREDIT_LIMIT_API( CREDIT_LIMIT, CUST_NUMBER, RTN_STATUS )

*******************************************************************************

*       Program CHECK_CREDIT_LIMIT

*       Copyright (C) 2022

*******************************************************************************

$INCLUDE UIEX UIEX.CUST.REC

**************************************************************************

OPEN 'CUST.SAMPLE' TO FN.CUST ELSE

  PRINT 'NO CUST.SAMPLE FILE'

  RTN_STATUS = 500

  RETURN

END

** Check that the ID is a number

IF NOT(NUM(CUST_NUMBER)) THEN

   RTN_STATUS = 400

   RETURN

END

MATREAD CUST.REC FROM FN.CUST,CUST_NUMBER THEN

  IF CUST.CREDIT.LIMIT = "" THEN

    CUST.CREDIT.LIMIT = 0

  END ELSE

    CREDIT_LIMIT = OCONV(CUST.CREDIT.LIMIT, "MR2")

  END

END ELSE

  CUST.CREDIT.LIMIT = 0

  RTN_STATUS = 404

END

RETURN

In our new example we added the status as a parameter in the subroutine, and added the logic to set it to 400, 404 or 500, based on the error type.

To add the status to the endpoint, we need to alter the endpoints.yaml file

- display-name: check-credit-limit

  method: GET

  path: /hr/check-status-limit/{customerNumber}

  db-operation:

    mvis-account: ACCUTERM

    call:

      subroutine: CHECK_CREDIT_LIMIT_API

      params:

      - name: response

        position: 1

        type: json

        binding: response-body

        param-direction: OUT

      - name: customerNumber

        position: 2

        type: string

        binding: path-param

        param-direction: IN

      - name: status

        position: 3

        type: string

        binding: status

The status parameter now has its binding set to ‘status’, so if there is a setting returned on that parameter, it will set the status in the REST response header.

i.e. Good Subroutine call ( no Errors )

C:\Users\mrajkowski>curl -v -X GET "http://localhost:7171/hr/check-status-limit/1119"

Note: Unnecessary use of -X or --request, GET is already inferred.

*   Trying 127.0.0.1:7171...

* Connected to localhost (127.0.0.1) port 7171 (#0)

> GET /hr/check-status-limit/1119 HTTP/1.1

> Host: localhost:7171

> User-Agent: curl/7.83.1

> Accept: */*

>

* Mark bundle as not supporting multiuse

< HTTP/1.1 200 OK

< Date: Fri, 20 Jan 2023 21:04:04 GMT

< Content-Type: application/json

< Content-Length: 20

< Server: Jetty(9.4.25.v20191220)

<

{"response":15000.0}* Connection #0 to host localhost left intact

Bad Subroutine Call ( The item does not exist )

 

C:\Users\mrajkowski>curl -v -X GET "http://localhost:7171/hr/check-status-limit/badId"

Note: Unnecessary use of -X or --request, GET is already inferred.

*   Trying 127.0.0.1:7171...

* Connected to localhost (127.0.0.1) port 7171 (#0)

> GET /hr/check-status-limit/badId HTTP/1.1

> Host: localhost:7171

> User-Agent: curl/7.83.1

> Accept: */*

>

* Mark bundle as not supporting multiuse

< HTTP/1.1 400 Bad Request

< Date: Fri, 20 Jan 2023 21:09:50 GMT

< Content-Type: application/json

< Content-Length: 17

< Server: Jetty(9.4.25.v20191220)

<

{"response":null}* Connection #0 to host localhost left intact