Forum Discussion

MeT's avatar
MeT
Occasional Contributor
7 years ago

ServiceV Pro: Default response unexpectedly replacing the scripted one

First thing first: I'm new to the ServiceV product, just got it few days ago.

 

I'm creating a virt api where the following path is being used:

/api/aicm/v1/subject/{subject_nr}/mandate/{creditor_id}

where subject_nr and creditor_id represent the required TEMPLATE parameters.

 

Beside the main success scenario (GET: -> HTTP 200 OK), where both arguments are made available in the URI, I'm trying to handle the following alternative scenarios in my virt api:

a) GET: {subject_nr} is empty -> HTTP 400 Bad Request
b) GET: {creditor_id} is empty -> HTTP 400 Bad Request
c) GET: both {subject_nr} and {creditor_id} are empty -> HTTP 400 Bad Request

The test paths associated with the four scenarios (1 main + 3 alts) are:

1. HTTP 200: /urds/wrd/api/aicm/v1/subject/0303200001/mandate/AB51TST405365330000
2. HTTP 400: /urds/wrd/api/aicm/v1/subject//mandate/AB51TST405365330000
3. HTTP 400: /urds/wrd/api/aicm/v1/subject/0303200001/mandate/
4. HTTP 400: /urds/wrd/api/aicm/v1/subject//mandate/

 I use the "Dispatch Strategy: Script" with default response returning HTTP 404 Not Found, and the following validation script to check the path arguments and return the appropriate response:

 

assert log
log.info("Executing dispatch script...")

assert requestContext
def props = requestContext.getProperties()
assert props
log.info("Request arguments: ${props}")

def subNr = props["subject_nr"]
def credId = props["creditor_id"]

if (subNr.empty || credId.empty) {
	// return HTTP 400
	return "GET 400 Bad Request"
}

log.info("subject_nr: ${subNr}")
log.info("creditor_id: ${credId}")

def isSubNrMatching = subNr ==~ /^\d{10}$/
log.info("subject_nr RegEx match is: ${isSubNrMatching}")
def isCredIdMatching = credId ==~ /^(ab|AB)(\d{2})([a-zA-Z]{3})(\d{8})(0{4})$/
log.info("creditor_id RegEx match is: ${isCredIdMatching}")
def areReqArgsValidated = isSubNrMatching && isCredIdMatching

if (!areReqArgsValidated) {
	// return HTTP 400
	return "GET 400 Bad Request"
}

log.info("Request arguments validated: ${areReqArgsValidated}")

// return HTTP 200
return "GET 200 OK"

Now, the problem is:

Main success scenario and alternative scenario a) work just fine (meaning: in both cases I get the expected response dispatched by the script).

With the remaining scenarios b) and c), a response with HTTP status code 404 is dispatched instead of the scripted one (400). This response is apparently not the default 404 response I created and selected in the "Default Response" drop-down list (which features a JSON payload in the body), for its body is empty.

Additionally, no log output shows up in the script (or error) log tab, showing clearly that the dispatch strategy script is not executed.

 

Any clue about why is this happening? Am I missing something fundamental, due to my lack of product knowledge?

  • Ok, I finally have come to a working way of dealing with scenarios where a TEMPLATE argument at the end of the path is expected but not provided (as in the following paths):

     5. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject/0303200001/mandate// <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT
     6. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject/0303200001/mandate/  <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT
     7. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject/0303200001/mandate   <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT
     8. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject//mandate// <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT
     9. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject/mandate//  <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT
    10. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject/mandate/   <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT
    11. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject/mandate    <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT

    To be able to dispatch your own custom response, and avoid the default 404 ServiceV (bodyless) response, you'll have first to create a separate resource for the path you wish to mock, in my case:

    /urds/wrd/api/aicm/v1/subject/mandate

    Then, in your script, you'll be checking the path and react accordingly:

    def path = mockRequest.getPath()
    log.info("HTTP request path: ${path}")
    if (path.endsWith("mandate") || path.endsWith("mandate/") || path.endsWith("mandate//")) {
    	log.info("mandate TEMPLATE argument: missing")
    	// return the name of the response you want to dispatch
    	//----------------------------------------------------------------------------------------------
    	return = "GET 400 Missing mandate ID"
    }

    Hope this will help you eventually! :smileyhappy:

  • MeT's avatar
    MeT
    Occasional Contributor

    For completeness' sake, this is the full list of paths I've been testing the behavior so far, with their associated test results:

     1. Expected: Custom HTTP 200: /urds/wrd/api/aicm/v1/subject/0303200001/mandate/AB51TST405365330000/ <<< Custom 200 OK 
     2. Expected: Custom HTTP 200: /urds/wrd/api/aicm/v1/subject/0303200001/mandate/AB51TST405365330000  <<< Custom 200 OK 
     3. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject//mandate/AB51TST405365330000 <<< Custom 400 Bad Request
     4. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject/mandate/AB51TST405365330000  <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT
     5. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject/0303200001/mandate// <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT
     6. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject/0303200001/mandate/  <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT
     7. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject/0303200001/mandate   <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT
     8. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject//mandate// <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT
     9. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject/mandate//  <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT
    10. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject/mandate/   <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT
    11. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject/mandate    <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT

    • MeT's avatar
      MeT
      Occasional Contributor

      Ok, I finally have come to a working way of dealing with scenarios where a TEMPLATE argument at the end of the path is expected but not provided (as in the following paths):

       5. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject/0303200001/mandate// <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT
       6. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject/0303200001/mandate/  <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT
       7. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject/0303200001/mandate   <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT
       8. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject//mandate// <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT
       9. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject/mandate//  <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT
      10. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject/mandate/   <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT
      11. Expected: Custom HTTP 400: /urds/wrd/api/aicm/v1/subject/mandate    <<< ServiceV 404 Not Found own bodyless response: INCONSISTENT

      To be able to dispatch your own custom response, and avoid the default 404 ServiceV (bodyless) response, you'll have first to create a separate resource for the path you wish to mock, in my case:

      /urds/wrd/api/aicm/v1/subject/mandate

      Then, in your script, you'll be checking the path and react accordingly:

      def path = mockRequest.getPath()
      log.info("HTTP request path: ${path}")
      if (path.endsWith("mandate") || path.endsWith("mandate/") || path.endsWith("mandate//")) {
      	log.info("mandate TEMPLATE argument: missing")
      	// return the name of the response you want to dispatch
      	//----------------------------------------------------------------------------------------------
      	return = "GET 400 Missing mandate ID"
      }

      Hope this will help you eventually! :smileyhappy:

      • AlexKaras's avatar
        AlexKaras
        Champion Level 3

        MeT:

         

        Hi,

         

        Thank you a lot for the update. I did not try it yet, but certainly will do. :)

        Initially, your solution seemed to me to be a kind of workaround and I was going to suggest to create either an issue or feature request.

        However, after some consideration, I am already less confident and tend to consider your solution as a valid and correct approach. I did not check what standard says about duplicated slashes within and at the end of address, but from what I remember, browsers usually ignore duplicated slashes and navigate to the same resource.

        For example, https://support.smartbear.com////versions/// navigates to the same page as https://support.smartbear.com/versions/ and https://support.smartbear.com/versions.

         

        So, even though your given virt contains template parameter at the end of the path, it looks reasonable that if this final parameter is missed, then the path still looks like a valid REST path (for example, like a request to get IDs of all creditors for the given subject) and ServiceV has no good reason to consider that this is a request with the missed last parameter. And thus it returns default internal 404 because no virt was specified for the requested resource.

        This is my current understanding and explanation. Do you think I missed something ?

         

        Olga_T:
        Olga, is it possible to ask your technical writers to extend the documentation section for Template parameters with the description of ServiceV behavior when the final parameter in the path is missed and what actions must be done in this case, based on the approach by MeT? Thank you.

         

    • AlexKaras's avatar
      AlexKaras
      Champion Level 3

      MeT:
      Hi,

       

      I am also pretty new to ServiceV and use your case as a learning example :)

      I found some problems setting up the Virt as per your description, contacted Support (via the https://support.smartbear.com/message/?prod=ReadyAPI form) and was recommended to try Parameter type of dispatching.

      Haven't you consider this option?

      • MeT's avatar
        MeT
        Occasional Contributor

        AlexKaras

        Hi Alex,

         

        Going for the Parameter dispatch style was indeed the first attempt I used for my implementation, given my path uses two TEMPLATE parameters. :smileywink:

        Unfortunately, one of the inbound values (the {creditor_id}) passed as argument to the parameter in the request is very complex to validate, in order to select the suitable mock response to dispatch (for the validation I use regular expressions) and I found that the visual facilities provided by ServiceV were not up to the task, to be honest.

        That aside, one of my main goals with ServiceV is to build up a script library for our testers to re-use, so... hence my decision to opt in for the Script dispatch style.

        I have of course contacted support too, and the private discussion is still open with them, since their argumentations insofar don't really fully convince me. :smileyindifferent:

         

        I'll keep posting the info here for the rest of the community too, of course.

         

        Cheers,

        MeT

         

  • TanyaYatskovska's avatar
    TanyaYatskovska
    SmartBear Alumni (Retired)

    Hi Community,

     

    Is there anybody who faced a similar behavior? Could you please share your thoughts about this issue?