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:
- Identify the business logic needed in the subroutine
- Create the subroutine to return the response and status
- 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:
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