Skip to content

03 Error handling

There are situations where we need to manage errors with more sophistication. For instance:

  • Validating input data before processing it (see Example 1).
  • Returning a custom error message to the client (see Example 1).
  • Halting the execution of all commands if an error occurs (see Example 2).
  • Returning a status code other than 200 (see Example 2).

DB SCRIPT

SQL Script required for SRS
SQL
CREATE TABLE [dbo].[TestData](
  [id] [int] IDENTITY(1,1) NOT NULL,
  [tuuid] [uniqueidentifier] NULL,
  [tint] [int] NULL,
  [tvarchar] [varchar](150) NULL,
  [tvarchar2] [varchar](150) NULL,
  [tdecimal] [decimal](18, 2) NULL,
  [tsmalldate] [smalldatetime] NULL,
  [tbit] [bit] NULL,
CONSTRAINT [PK_TestData] PRIMARY KEY CLUSTERED 
(
  [id] ASC
) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[TestData] ADD  CONSTRAINT [DF_TestData_tuuid]  DEFAULT (newid()) FOR [tuuid]
GO

Example 1

XML
<srs title="My title" acl="sys_administrator" name="300">
  <def>
    <itm model="param" name="tvarchar" opts="req"></itm>
    <itm model="param" name="tdecimal" opts="req" type="decimal"></itm>
    <itm model="param" name="tsmalldate" type="date"></itm>
    <itm model="param" name="tvarchar2" opts="server">[[kv.v.user.username]]</itm>
    <itm model="command" name="api" type="dtsingle">
      <![CDATA[
BEGIN TRY 

    --some custom validation
    if (len(@tvarchar) <5 )
        raiserror('Value to short: %s', 16, 1, @tvarchar)

    INSERT into [dbo].[TestData] 
    ( [tvarchar],[tvarchar2],[tdecimal],[tsmalldate],[tbit] ) 
    VALUES (@tvarchar,@tvarchar2,@tdecimal,@tsmalldate,1)

    select @@rowcount as 'affected_rows' , SCOPE_IDENTITY() last_id

END TRY 
BEGIN CATCH 
  declare @errmsg varchar(500) = (select ERROR_MESSAGE())
  raiserror(@errmsg  ,16, 1)
END CATCH; 
  ]]>
    </itm>
    <itm model="command" name="select" opts="get">
     select * from [dbo].[TestData]
    </itm>
  </def>
</srs>

Testing

You can test the SRS by making the following request: Experiment with different values for tvarchar and tdecimal to observe how the error handling functions.

Test 1 executing post with invalid body parameters

HTTP
1
2
3
4
5
6
7
8
9
POST {{host}}/api/srs/300/start.json
Authorization: Token {{token}}
content-type: application/json

{
    "tvarchar": "sele",
    "tdecimal": 3, 
    "tsmalldate": "2021-01-10"
}
Response Http status 200
XML
{
  "success": false,
  "message": "Vaue to short: sele",
  "apipath": "/api/srs/300/start.json",
  "apimethod": "POST",
  "basepath": "http://127.0.0.1",
  "filepath": "/srs/testy/300-test.xml",
  "name": "300-test",
  "id": "300",
  "opts": null,
  "session_id": "dd7a75b4-8af6-4f98-b9a4-32042108174c",
  "label": "300-test",
  "description": null,
  "cache": null,
  "executed_at": "2024-08-14T22:27:59.3625645Z",
  "acl": "sys_administrator",
  "tables": [],
  "def": [],
  "data": {
    "debugger": [
      {
        "t": 33,
        "k": "inf/srs/load/profile",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 0,
        "k": "inf/srs/load/app",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 32,
        "k": "inf/srs/load/roles",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 39,
        "k": "inf/srs/load/srs",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 0,
        "k": "inf/srs/parameters",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 0,
        "k": "inf/srs/init",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 117,
        "k": "err/srs/command/db/300/api",
        "v": "Vaue to short: sele",
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 117,
        "k": "inf/srs/command/db/300/api",
        "v": "",
        "c": 0,
        "a": 0,
        "i": null
      },
      {
        "t": 117,
        "k": "inf/srs/command/total",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 0,
        "k": "inf/srs/post",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      }
    ]
  }
}

Test 2 executing post with valid body parameters

HTTP
1
2
3
4
5
6
7
8
9
POST {{host}}/api/srs/300/start.json
Authorization: Token {{token}}
content-type: application/json

{
    "tvarchar": "select",
    "tdecimal": 3, 
    "tsmalldate": "2021-01-10"
}
Response Http status 200
XML
{
  "success": true,
  "message": "",
  "apipath": "/api/srs/300/start.json",
  "apimethod": "POST",
  "basepath": "http://127.0.0.1",
  "filepath": "/srs/testy/300-test.xml",
  "name": "300-test",
  "id": "300",
  "opts": null,
  "session_id": "19710a13-980c-4d1c-8997-415e02803619",
  "label": "300-test",
  "description": null,
  "cache": null,
  "executed_at": "2024-08-14T22:32:45.9745817Z",
  "acl": "sys_administrator",
  "tables": [],
  "def": [],
  "data": {
    "debugger": [
      {
        "t": 36,
        "k": "inf/srs/load/profile",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 0,
        "k": "inf/srs/load/app",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 0,
        "k": "inf/srs/load/roles",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 37,
        "k": "inf/srs/load/srs",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 0,
        "k": "inf/srs/parameters",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 0,
        "k": "inf/srs/init",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 123,
        "k": "inf/srs/command/db/300/api",
        "v": "",
        "c": 1,
        "a": 1,
        "i": null
      },
      {
        "t": 123,
        "k": "inf/srs/command/total",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 0,
        "k": "inf/srs/post",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      }
    ],
    "api": [
      {
        "affected_rows": 1,
        "last_id": 60.0
      }
    ]
  }
}

Test 3 executing post with query parameter

HTTP
GET {{host}}/api/srs/300/start.json?tvarchar=select&tdecimal=1
Authorization: Token {{token}}
Response Http status 200
XML
{
  "success": true,
  "message": "",
  "apipath": "/api/srs/300/start.json?tvarchar=select&tdecimal=1",
  "apimethod": "GET",
  "basepath": "http://127.0.0.1",
  "filepath": "/srs/testy/300-test.xml",
  "name": "300-test",
  "id": "300",
  "opts": null,
  "session_id": "1cd6f0a7-ce16-4b64-ad7e-5b7c642a47d2",
  "label": "300-test",
  "description": null,
  "cache": null,
  "executed_at": "2024-08-14T22:36:29.7066079Z",
  "acl": "sys_administrator",
  "tables": [],
  "def": [],
  "data": {
    "debugger": [
      {
        "t": 44,
        "k": "inf/srs/load/profile",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 0,
        "k": "inf/srs/load/app",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 0,
        "k": "inf/srs/load/roles",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 0,
        "k": "inf/srs/load/srs",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 0,
        "k": "inf/srs/parameters",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 0,
        "k": "inf/srs/init",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 100,
        "k": "inf/srs/command/db/300/select",
        "v": "",
        "c": 2,
        "a": -1,
        "i": null
      },
      {
        "t": 195,
        "k": "inf/srs/command/db/300/api",
        "v": "",
        "c": 1,
        "a": 1,
        "i": null
      },
      {
        "t": 195,
        "k": "inf/srs/command/total",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      },
      {
        "t": 0,
        "k": "inf/srs/post",
        "v": null,
        "c": null,
        "a": null,
        "i": null
      }
    ],
    "api": [
      {
        "affected_rows": 1,
        "last_id": 3.0
      }
    ],
    "select": [
      {
        "id": 1,
        "tuuid": "76c1d535-2207-48fc-abbf-562d7cc3f81f",
        "tint": null,
        "tvarchar": "select",
        "tvarchar2": "[email protected]",
        "tdecimal": 1.00,
        "tsmalldate": null,
        "tbit": true
      },
      {
        "id": 2,
        "tuuid": "09464c8b-5c9a-42f0-8cc5-67bf59a4f956",
        "tint": null,
        "tvarchar": "select",
        "tvarchar2": "[email protected]",
        "tdecimal": 1.00,
        "tsmalldate": null,
        "tbit": true
      }
    ]
  }
}

Example 2

Utilize the special command name srssetup to validate business logic and halt processing if an error is detected.

XML
<srs title="My title" name="334">
  <def>
    <itm model="param" name="username" opts="server">[[kv.v.user.username]]</itm>
    <itm model="param" name="ordernumber"  type="int"></itm>
    <itm model="command" name="srssetup" label="validate business logic">
      <![CDATA[
BEGIN TRY 
  if (@ordernumber is null)
    raiserror('ordernumber not provided',16, 1)

  if (@ordernumber >10)
        raiserror('Order Not found', 16, 1) 
  else
    RAISERROR('Order found, CONTINUE', 0, 1) WITH NOWAIT;

Print 'Order Processing'

END TRY 
BEGIN CATCH 
    declare @errmsg varchar(500) = (select ERROR_MESSAGE())
    raiserror(@errmsg  ,16, 1)
END CATCH; 
  ]]>
    </itm>

    <itm model="command" name="command2" opts="get">
      select 'command2' as text</itm>
    <itm model="command" name="command3" opts="get">
      select 'command3' as text</itm>
  </def>
</srs>
HTTP
GET {{host}}/api/srs/334/api.json?ordernumber=11
Authorization: Token {{token}}

HTTP/1.1 400 Bad Request

JSON
1
2
3
4
5
6
7
{
  "success": false,
  "message": "ordernumber not provided",
  "requestID": "",
  "executed_at": "2024-08-14T23:12:39.6194917Z",
  "data": {}
}
HTTP
GET {{host}}/api/srs/334/api.json?ordernumber=9
Authorization: Token {{token}}
JSON
{
  "success": true,
  "message": "Order found, CONTINUE\nOrder Processing\n",
  "apipath": "/api/srs/334/api.json?ordernumber=9",
  "apimethod": "GET",
  "basepath": "http://127.0.0.1",
  "filepath": "/srs/testy/334.xml",
  "name": "334",
  "id": "334",
  "opts": null,
  "session_id": "0f159414-3010-4bef-a8dd-51940d8989a7",
  "label": "334",
  "description": null,
  "cache": null,
  "executed_at": "2024-08-14T23:28:21.0515049Z",
  "acl": "app_erp",
  "tables": [],
  "def": [],
  "data": {
    "srssetup": [],
    "command2": [
      {
        "text": "command2"
      }
    ],
    "command3": [
      {
        "text": "command3"
      }
    ]
  }
}