Validate format of input

Hi All,

Have written an API proxy that accepts two query parameters.

1st query param is 'code'

2nd query param is 'id'

The query parameter 'id' has fixed format based on value of 'code'

code

Format for id


AT

1 block of 9 characters

BE

1 block of 10 digits


How do I check format of 'id' based on code?

Here is few concrete examples of what am trying to achieve.

/verify?code=AT&id=123{"errorCode": 1001, "errorCode": "Invalid parameter"}
/verify?code=AT&id=12311BBcdpass through
/verify?code=BE&id=12345678AA{"errorCode": 1001, "errorCode": "Invalid parameter"}
/verify?code=BE&id=1234567890pass through

There are 22 codes and each code have specific format. Most are simple format check, some are a bit complex.

What's the best way to achieve this?

Thanks in advance.

0 5 389
5 REPLIES 5

Two points: One to help you, and one to help me help you!

First. Some times it's easier to design APIs if you can write out exactly what you want to accomplish. For example, I would like to get a list of IDs back that match a specific CODE. Or I would like to get a list of all available CODES. What is it that you are actually trying to return? And, it's ok if you want to return multiple types of result.

Also. What does ID and CODE mean to you? Are they customer codes, product codes, location codes? Also what is the ID? User ID, product ID? Sometimes it's easier to design APIs when you are more specific about the terms.

What do you mean "check format" of the "id based on code?" Are you looking to confirm that the ID is 9 characters, or that if BE for format is 10 digits? Or do you want to return the results of those queries? Is this a GET, POST, PUT, DELETE? Etc.

Which changes the description I mentioned in the first point above. Here are examples.

GET /v1/product/code ----- get a list of all codes

GET /v1/product/code/at ----- get a list of all IDs that match the code AT

GET /v1/product/code/be ----- get a list of all IDs that match the code BE

GET /v1/product/code/{code} ----- get a list of all IDs that match that code

GET /v1/product/?ID={string} ----- get CODE value for ID value

POST /v1/product/code/at/id={string} ----- add a new ID to the AT code

In the last post example, you could configure checks and validations to ensure that the ID itself matches the format you want.

Does this answer your question, or do you have other specific needs? Could you share the one line sentence about what you want to happen.

Chris

Hi Chris,

Sorry it my first time. Here is few examples of what am trying to achieve.

Example 1

GET /v1/product/verify?code=AT,id=123

{"errorCode": 1001, "errorCode": "Invalid parameter"}

Example 2

GET /v1/product/verify?code=AT,id=12311BBcd

Pass the request to SOAP service

Example 3

GET /v1/product/verify?code=BE,id=12345678AA

{"errorCode": 1001, "errorCode": "Invalid parameter"}

Example 4

GET /v1/product/verify?code=BE,id=1234567890

Pass the request to SOAP service

There are 22 codes and each code have specific format. Most are simple format check, some are bit complex.

What's the best way to achieve this?

Thanks for the additional context. Going to loop someone else in.

@diino-at-google

You shouldn't need to perform this validation within the GET. It can be confirmed inside of the proxy and with a workflow inside of Apigee. But you can absolutely do it this way. I'll let Dino answer the how on this one.

You have a couple options for implementing that validation in Apigee .

  1. Condition elements in the flow.
  2. custom policy, for example written in JavaScript

In more detail.

In the flow language of Apigee, you can use Condition elements that tell Apigee under what condition to execute various steps. One pattern you may use to test for all 22 cases is: a compound Condition that tests for a particular value of the query param "code" and then the false Condition for the ID.

in pseudo language

If the Code is AT and the id is not 9 alphanumeric characters, then return fault 1.

if the Code is BE and the id is not 10 decimal digits, then return fault 2.

You can rely on regular expression matching in Conditions to check for strings. In actual flow language, it would look like this:

<Step>
  <Name>RaiseFault-InvalidParameter</Name>
  <Condition>request.queryparam.code = "AT" and NOT(request.queryparam.id ~~ "[0-9]{9}")</Condition>
</Step>
<Step>
  <Name>RaiseFault-InvalidParameter</Name>
  <Condition>request.queryparam.code = "BE" and NOT(request.queryparam.id ~~ "[A-Z0-9]{10}")</Condition>
</Step>
  ...

Of course, you could also combine ALL of those into one large compound Condition.

<Step>
  <Name>RaiseFault-InvalidParameter</Name>
  <Condition>
   (request.queryparam.code = "AT" and 
       NOT(request.queryparam.id ~~ "[0-9]{9}")) OR
(request.queryparam.code = "BE" and NOT(request.queryparam.id ~~ "[A-Z0-9]{10}")) OR
...
</Condition> </Step>

You also need to consider edge cases, in which code is not present, or code is "none of the above."

The RaiseFault policy just returns what you said you wanted:

<RaiseFault name='RaiseFault-InvalidParameter'>
  <FaultResponse>
    <Set>
      <Payload contentType='application/json'>{"errorCode": 1001, "errorCode": "Invalid parameter"}
</Payload>
      <StatusCode>400</StatusCode>
      <ReasonPhrase>Bad Request</ReasonPhrase>
    </Set>
  </FaultResponse>
</RaiseFault>

That might be readable to you. If you don't like the flow conditions, then you can use JavaScript to implement the checks of regular expressions and Code. In the flow, this might look like this.

<Step>
  <Name>JS-ValidateQuery</Name>
</Step>

And in JavaScript:

var patternMappings = {
  AT : "[0-9]{9}",
  BE : "[A-Z0-9]{10}",
  ..
};

var code = context.getVariable('request.queryparam.code');
if (code) {
  if (patternMappings[code]) {
    var re = new RegExp("^" + patternMappings[code] + "$");
    var id = context.getVariable('request.queryparam.id');
    if (!id.match(re)) {
      throw new Error("Invalid id parameter");
    }
  }
  else {
    throw new Error("unknown code");
  } 
}
else {
 throw new Error("missing code"); 
}

If you throw from JavaScript, it results in a Fault condition in the Apigee flow. You can use a FaultRule to handle that, and within that, AssignMessage to assign the payload to be

{"errorCode": 1001, "errorCode": "Invalid parameter"}

Either Conditions in flows, or JavaScript will work. Which of these you prefer depends on your sense of which is more readable.

@diino-at-google You are a star.

Choose option 1, i.e "conditional element in the flow'. It's more readable and I can maintain rule for each code for any changes.

Few follow up questions.

[1] The solution created more than 30 "raise fault" policies in the PreFlow for proxy endpoints. ~Will this create any performance issue in future?

[2] Explain below and how to handle it.

You also need to consider edge cases, in which code is not present, or code is "none of the above."