IBM API Connect brings a shiny new assembly editor for defining flows for your APIs. There’s also built-in support for throwing and catching errors that you can use to make sure your API gives a well-defined response in all conditions.

I’ll walk through a not-at-all-contrived example of this, and I’ll include the entire YAML document at the bottom of this post in case you want to take it and play with the example. I’m building a calculator API, and my POST /divide was working fine until the test team got their hands on it and put a zero divisor through it….


divide_by_two

Looking good…


divide_by_zero_unhandled

Not so good…

Not ideal output for the user. Now, I *could* try to tackle this problem with JSON schema and use the validate policy to prevent the user sending a zero divisor, but I find it doesn’t take long before JSON schema get a little out of hand. Real world problems are rarely solvable with JSON schema alone, so let’s tackle this a different way.

Let’s drag an ‘if’ node into our flow and configure it to trigger when a divisor of zero is encountered:


empty_if

The if node

  
- if:
    title: if divisor is zero
    condition: request.parameters.divisor == 0
    execute: []
  

And the YAML for the if node

Now let’s drag a ‘throw’ node into our ‘if’:


configured_throw

The fully configured if node

  
- if:
    title: if divisor is zero
    condition: request.parameters.divisor == 0
    execute:
      - throw:
          title: throw
          name: DivideByZeroError
  

And the accompanying YAML

So, now we’ve isolated the specific conditions which cause our operation problems. Next we need to gracefully deal with it. There’s a ‘Show catches’ switch in the assembly menu bar. Selecting that shows a catch section in the assembly canvas:


show_catches

Show catches

Here I can define any number of catch conditions and handle them appropriately. In this case, I want to create a meaningful error message for my user that conforms to the Error definition I’ve put in my swagger document:

  
Error:
  properties:
    message:
      type: string
      description: The error message
  description: Standard error response
  required:
    - message
  

My standard error response definition

Clicking on “catch” opens up an info panel where you can add and remove any catch clauses you need. Let’s add a catch clause and set it to trigger on our new DivideByZeroError (type DivideByZeroError into the text box and hit enter). You’ll also see a dropdown of pre-defined errors appears – these are standard errors that can be thrown by various policies in API Connect, and can be caught and handled in the same way.


configure_catches

Configuring my catch

Don’t forget to hit enter after typing in the error name! Also, notice that the DivideByZeroError doesn’t appear in the list of available errors? It’s on my list to do something about that…

Now, let’s drag in a ‘set-variable’ policy and set it up as follows:

  • set the message body to {“message”: “…”}
  • set the status code to 400
  • set the content type to application/json
  
- set-variable:
    title: Rewrite Error
    actions:
      - set: message.body
        value: "{\"message\":\"I'm sorry Dave, I'm afraid I can't let you do that\"}"
      - set: message.status.code
        value: '400'
      - set: message.headers.content-type
        value: application/json
  

My set-variable policy configuring the error response

Now, when I invoke this operation with a zero divisor, I can see I’ve triggered the if condition, thrown the DivideByZeroError, caught it, and cleaned up the response being sent back to the user. Much better!


divide_by_zero_caught

The final working example

Here’s a final screenshot of the assembly I’ve built here, followed by the entire swagger document. Feel free to try it out for yourself!


complete_assembly

The completed assembly

  
swagger: '2.0'
info:
  version: 1.0.1
  title: Calculator API
  x-ibm-name: Calculator-API
  contact:
    name: Chris Bygrave
    email: bygravec@uk.ibm.com
    url: 'http://www.ibm.com'
  description: ''
host: $(catalog.host)
basePath: /calculate
paths:
  /divide:
    post:
      responses:
        '200':
          description: 200 OK
          schema:
            $ref: '#/definitions/integerResult'
        '400':
          description: Divide by zero
          schema:
            $ref: '#/definitions/Error'
      parameters:
        - name: divisor
          type: integer
          required: false
          in: query
          format: int32
          description: The divisor
        - name: numerator
          type: integer
          required: false
          in: query
          description: The numerator
          format: int32
  /multiply: {}
  /add: {}
securityDefinitions:
  clientID:
    description: ''
    in: header
    name: X-IBM-Client-Id
    type: apiKey
security:
  - clientID: []
x-ibm-configuration:
  assembly:
    execute:
      - if:
          title: if divisor is zero
          condition: request.parameters.divisor == 0
          execute:
            - throw:
                title: throw
                name: DivideByZeroError
      - map:
          title: Divide numerator by divisor
          inputs:
            numerator:
              schema:
                type: integer
              variable: request.parameters.numerator
            divisor:
              schema:
                type: integer
              variable: request.parameters.divisor
          outputs:
            output:
              schema:
                $ref: '#/definitions/integerResult'
              variable: message.body
          actions:
            - set: output.result
              from:
                - numerator
                - divisor
              value: $(numerator) / $(divisor)
    catch:
      - errors:
        - DivideByZeroError
        execute:
          - set-variable:
              title: Rewrite Error
              actions:
                - set: message.body
                  value: "{\"message\":\"I'm sorry Dave, I'm afraid I can't let you do that\"}"
                - set: message.status.code
                  value: '400'
                - set: message.headers.content-type
                  value: application/json
  enforced: true
  testable: true
  phase: realized
  cors:
    enabled: true
  gateway: datapower-gateway
schemes:
  - https
produces:
  - application/json
  - application/xml
consumes:
  - application/json
  - application/xml
definitions:
  Error:
    properties:
      message:
        type: string
        description: The error message
    description: Standard error response
    required:
      - message
  integerResult:
    properties:
      result:
        type: integer
        format: int32
    additionalProperties: true
    required:
      - result
  

The whole swagger document

2 comments on"Throwing and catching errors in IBM API Connect"

  1. Does enabling catching these errors create any performance impact on the response time for the API’s being monitored?

    Are there considerations for log sizing or other factors?

    We are using IBM Cloud version

  2. Roberto de Gasperi March 09, 2018

    Really good article, precisely what I needed, thank you!

Join The Discussion

Your email address will not be published. Required fields are marked *