{"id":831,"date":"2020-10-11T07:41:35","date_gmt":"2020-10-11T11:41:35","guid":{"rendered":"http:\/\/salzlechner.com\/dev\/?p=831"},"modified":"2020-10-11T07:41:35","modified_gmt":"2020-10-11T11:41:35","slug":"starzen-rest-library-for-dataflex-webapp-order-api","status":"publish","type":"post","link":"http:\/\/salzlechner.com\/dev\/2020\/10\/11\/starzen-rest-library-for-dataflex-webapp-order-api\/","title":{"rendered":"StarZen REST library for DataFlex WebApp \u2013 Order API"},"content":{"rendered":"<p>[et_pb_section fb_built=&#8221;1&#8243; _builder_version=&#8221;3.22&#8243;][et_pb_row _builder_version=&#8221;3.25&#8243; background_size=&#8221;initial&#8221; background_position=&#8221;top_left&#8221; background_repeat=&#8221;repeat&#8221;][et_pb_column type=&#8221;4_4&#8243; _builder_version=&#8221;3.25&#8243; custom_padding=&#8221;|||&#8221; custom_padding__hover=&#8221;|||&#8221;][et_pb_text _builder_version=&#8221;3.26.7&#8243; z_index_tablet=&#8221;500&#8243; text_text_shadow_horizontal_length_tablet=&#8221;0px&#8221; text_text_shadow_vertical_length_tablet=&#8221;0px&#8221; text_text_shadow_blur_strength_tablet=&#8221;1px&#8221; link_text_shadow_horizontal_length_tablet=&#8221;0px&#8221; link_text_shadow_vertical_length_tablet=&#8221;0px&#8221; link_text_shadow_blur_strength_tablet=&#8221;1px&#8221; ul_text_shadow_horizontal_length_tablet=&#8221;0px&#8221; ul_text_shadow_vertical_length_tablet=&#8221;0px&#8221; ul_text_shadow_blur_strength_tablet=&#8221;1px&#8221; ol_text_shadow_horizontal_length_tablet=&#8221;0px&#8221; ol_text_shadow_vertical_length_tablet=&#8221;0px&#8221; ol_text_shadow_blur_strength_tablet=&#8221;1px&#8221; quote_text_shadow_horizontal_length_tablet=&#8221;0px&#8221; quote_text_shadow_vertical_length_tablet=&#8221;0px&#8221; quote_text_shadow_blur_strength_tablet=&#8221;1px&#8221; header_text_shadow_horizontal_length_tablet=&#8221;0px&#8221; header_text_shadow_vertical_length_tablet=&#8221;0px&#8221; header_text_shadow_blur_strength_tablet=&#8221;1px&#8221; header_2_text_shadow_horizontal_length_tablet=&#8221;0px&#8221; header_2_text_shadow_vertical_length_tablet=&#8221;0px&#8221; header_2_text_shadow_blur_strength_tablet=&#8221;1px&#8221; header_3_text_shadow_horizontal_length_tablet=&#8221;0px&#8221; header_3_text_shadow_vertical_length_tablet=&#8221;0px&#8221; header_3_text_shadow_blur_strength_tablet=&#8221;1px&#8221; header_4_text_shadow_horizontal_length_tablet=&#8221;0px&#8221; header_4_text_shadow_vertical_length_tablet=&#8221;0px&#8221; header_4_text_shadow_blur_strength_tablet=&#8221;1px&#8221; header_5_text_shadow_horizontal_length_tablet=&#8221;0px&#8221; header_5_text_shadow_vertical_length_tablet=&#8221;0px&#8221; header_5_text_shadow_blur_strength_tablet=&#8221;1px&#8221; header_6_text_shadow_horizontal_length_tablet=&#8221;0px&#8221; header_6_text_shadow_vertical_length_tablet=&#8221;0px&#8221; header_6_text_shadow_blur_strength_tablet=&#8221;1px&#8221; box_shadow_horizontal_tablet=&#8221;0px&#8221; box_shadow_vertical_tablet=&#8221;0px&#8221; box_shadow_blur_tablet=&#8221;40px&#8221; box_shadow_spread_tablet=&#8221;0px&#8221;]In this part of the REST API Library series we will create the order API based on DAWs order entry sample database.<\/p>\n<p>We will take a look at additional features such as paging, selections as well as additional features to schemas\/models.<\/p>\n<p>to get started lets create the order api controller by adding a new http handler based on the cszWebAPIController class.<\/p>\n<pre>\/\/\nObject oOrderAPI is a cszWebAPIController\n\u00a0 \u00a0 Set psControllerDescription to \"allows viewing, adding and deleting orders\"\n\u00a0 \u00a0 Set psControllerTitle to \"Order API\"\n\u00a0 \u00a0 Set psControllerVersion to \"1\"\n\u00a0 \u00a0 Set psPath to \"api\/v1\/order\"\n\u00a0 \u00a0 Set psVerbs to \"*\"\n\n\u00a0 \u00a0 Object oVendor_DD is a cVendorDataDictionary\n    End_Object\n\n    Object oInventory_DD is a cInventoryDataDictionary\n        Set DDO_Server to oVendor_DD\n    End_Object\n\n    Object oSalesPerson_DD is a cSalesPersonDataDictionary\n    End_Object\n\n    Object oCustomer_DD is a cCustomerDataDictionary\n    End_Object\n\n    Object oOrderHeader_DD is a cOrderHeaderDataDictionary\n        Set DDO_Server to oSalesPerson_DD\n        Set DDO_Server to oCustomer_DD\n    End_Object\n\n    Object oOrderDetail_DD is a cOrderDetailDataDictionary\n        Set DDO_Server to oInventory_DD\n        Set Constrain_file to OrderHeader.File_number\n        Set DDO_Server to oOrderHeader_DD\n    End_Object\n    \n    Set Main_DD to oOrderHeader_DD\n    ...\nEnd_Object<\/pre>\n<p>&nbsp;[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row _builder_version=&#8221;3.26.7&#8243;][et_pb_column type=&#8221;4_4&#8243; _builder_version=&#8221;3.26.7&#8243;][et_pb_text _builder_version=&#8221;3.26.7&#8243;]<\/p>\n<p>Next we will define our schema\/model for the API.<\/p>\n<pre>Procedure OnDefineModelColumnsCustomer\n    Send AddTableColumn File_Field Customer.Customer_Number\n    Send AddTableColumn File_Field Customer.Name\n    Send AddTableColumn File_Field Customer.Address\nEnd_Procedure\n\nProcedure OnDefineModelColumnsInventory\n    Send AddTableColumn File_Field Inventory.Item_ID\n    Send AddTableColumn File_Field Inventory.Description\n    Send AddTableColumn File_Field Inventory.On_Hand\n    Send AddTableColumn File_Field Inventory.Unit_Price\nEnd_Procedure\n\nProcedure OnDefineModelDetail\n    Send AddTableColumn File_Field OrderDetail.Detail_Number\n    Send AddTableColumn File_Field OrderDetail.Order_Number\n    Send AddTableColumn File_Field OrderDetail.Item_ID\n    Send AddTableColumn File_Field OrderDetail.Qty_Ordered\n    Send AddTableColumn File_Field OrderDetail.Price\n    Send AddTableColumn File_Field OrderDetail.Extended_Price\n\n    Send AddModelParent \"inventory\" (RefProc(OnDefineModelColumnsInventory)) True\nEnd_Procedure\n\nProcedure OnDefineModels\n    Send BeginModel \"order\"\n\n    Send AddTableColumn File_Field OrderHeader.Order_Number\n    Send AddTableColumn File_Field OrderHeader.Customer_Number\n\n    Send AddModelParent \"Customer\" (RefProc(OnDefineModelColumnsCustomer)) True\n\n    Send AddModelChild \"Detail\" OrderDetail.File_Number (RefProc(OnDefineModelDetail)) True\n\n    Send AddTableColumn File_Field OrderHeader.Order_Date\n    Send AddTableColumn File_Field OrderHeader.Terms\n    Send AddTableColumn File_Field OrderHeader.Ship_Via\n    Send AddTableColumn File_Field OrderHeader.Ordered_By\n    Send AddTableColumn File_Field OrderHeader.SalesPerson_ID\n    Send AddTableColumn File_Field OrderHeader.Order_Total\n    Send AddTableColumn File_Field OrderHeader.Last_Detail_Num\n\n    Send EndModel\n\n    Send BeginModel \"orderlist\"\n\n    Send AddTableColumn File_Field OrderHeader.Order_Number\n    Send AddTableColumn File_Field OrderHeader.Customer_Number\n    Send AddTableColumn File_Field OrderHeader.Order_Date\n    Send EndModel\nEnd_Procedure\n<\/pre>\n<p>\u00a0We are definfing a schema called order. This is our main schema and contains the\u00a0 order header fields as well as a parent schema for customer. We also added a child schema for the detail lines as well.<\/p>\n<p>In addition we are declaring a second schema called &#8216;orderlist&#8217; which we will use to demonstrate using multiple schemas in an API controller.<\/p>\n<p>[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row _builder_version=&#8221;3.26.7&#8243;][et_pb_column type=&#8221;4_4&#8243; _builder_version=&#8221;3.26.7&#8243;][et_pb_text _builder_version=&#8221;3.26.7&#8243;]Now lets declare our standard GET route to return a list of orders<\/p>\n<p>&nbsp;<\/p>\n<pre>\/\/\nSend RegisterPath \"GET\" \"\" (RefProc(WebAPI_Get)) \nSet psPathSummary to \"Get List of orders\"\nSet psPathDescription to \"Use this API to retrieve a list of orders\"\nSend AddPathresponse 200 \"successful return of list of orders\" \"application\/json\" True \"order\"<\/pre>\n<p>just like the inventory example we simply declare a GET route with the default WebAPI_Get method, summary and description info for the API documentation.<\/p>\n<p>We also define the response<\/p>\n<p>A test of the new API returns all orders in a json array. This can lead to a lot of data of course.<\/p>\n<p>In order to limit the amount of data returned we want to add paging functionality. The REST library supports required and optional paging and the paging settings can be made for each controller as well as for each path.<\/p>\n<p>to enable paging we can add the following code to our controller<\/p>\n<pre>\/\/ enable required paging\nSend SetPaging WEBAPI_PAGING_REQUIRED 50 20\n<\/pre>\n<p>This line will set the controllers paging default to required with a maximum of 50 records per page and a default of 20.<\/p>\n<p>this will make 3 changes to the API.<\/p>\n<p>first the output will automatically be governed by the paging settings.<\/p>\n<p>second on the input side we can now supply the following query parameters<\/p>\n<ul>\n<li>page<br \/>\nthe current page to be returned<\/li>\n<li>pageSize<br \/>\nnumber of rows to return. this cannot be greater than the maximum page size defined on the controller or route<\/li>\n<\/ul>\n<p>ad last but not least the return data will include a X-Pagination http header containing the information on the page returned.<\/p>\n<p>The X-Pagination header contains a json object with the following fields<\/p>\n<ul>\n<li>PageSize<\/li>\n<li>CurrentPage<\/li>\n<li>TotalCount (not with embedded db)<\/li>\n<li>TotalPages\u00a0(not with embedded db)<\/li>\n<\/ul>\n<p>the X-Pagination header can be used by the calling program.<\/p>\n<p>In addition to paging we want to be able to sort the orders by different sort orders. We need to declare these so we can allow the client to set the sort order<\/p>\n<p>lets add the following to our route delcaration<\/p>\n<pre>Send AddPathOrder \"orderNumber\" 1 True \n\nSend AddPathOrder \"orderDate\" 3 True\nSend AddPathOrder \"Customer\" 2 False\nSet psPathDefaultOrder to \"orderNumber\"\n<\/pre>\n<p>this will declare 3 different sort orders, by order number, order date as well as customer. The first two allow descending orders as well.<\/p>\n<p>And last we set the default sort order to order number.<\/p>\n<p>this now enables the client to send two additional query parameters<\/p>\n<ul>\n<li>order<\/li>\n<li>desc<\/li>\n<\/ul>\n<p>for example<\/p>\n<p><strong>\/api\/v1\/order?order=orderDate&amp;desc=true<\/strong><\/p>\n<p>or with paging<\/p>\n<p><strong>\/api\/v1\/order?order=orderDate&amp;desc=true&amp;page=10<\/strong><\/p>\n<p>Of course we also need to be able to select orders for example by date. Lets add some functionality to do just that.<\/p>\n<p>First we modify the orderheader datadictionary to add the constraint logic<\/p>\n<pre>Object oOrderHeader_DD is a cOrderHeaderDataDictionary\n    Set DDO_Server to oSalesPerson_DD\n    Set DDO_Server to oCustomer_DD\n\n    Property Date pdDateFrom \"\"\n    Property Date pdDateTo \"\"\n\n    Procedure OnConstrain \n        If (pdDateFrom(Self)&lt;&gt;\"\") Constrain OrderHeader.Order_Date ge (pdDateFrom(Self))\n        If (pdDateTo(Self)&lt;&gt;\"\") Constrain OrderHeader.Order_Date le (pdDateTo(Self))\n    End_Procedure\n\n    Procedure ClearConstraints\n       Set pdDateFrom to \"\"\n       Set pdDateTo to \"\"\n       Send Rebuild_Constraints\n    End_Procedure\nEnd_Object<\/pre>\n<p>now we add a new method for our order API<\/p>\n<pre>Procedure WebAPI_GetOrders\n    Date dFrom dTo\n    Get UrlParameter \"dateFrom\" to dFrom\n    Get UrlParameter \"dateTo\" to dTo\n\n    Set pdDateFrom of oOrderHeader_DD to dFrom\n    Set pdDateTo of oOrderHeader_DD to dTo\n    Send Rebuild_Constraints to oOrderHeader_DD\n\n    \/\/ call original get API\n    Send webAPI_Get\n\n    Send ClearConstraints to oOrderHeader_DD\nEnd_Procedure<\/pre>\n<p>this new method gets the url parameters &#8216;dateFrom&#8217; and &#8216;dateTo&#8217; and uses these values to initialize the DDs constraints<\/p>\n<p>then we simply call the original GET API to get the data and then clear the constraints<\/p>\n<p>we need to modify the route declaration to call this new method<\/p>\n<pre>Send RegisterPath \"GET\" \"\" (RefProc(WebAPI_GetOrders))<\/pre>\n<p>this will now allow the user of the API to specify the dateFrom and dateTo parameters to constrain the orders returned.<\/p>\n<p>Of course all these changes are also made to the OpenAPI documentation as well<\/p>\n<p>Now as a last feature lets see how we can use a second schema in the same API to return the same dataset with a different schema<\/p>\n<p>All we need to do is to declare a new route as follows<\/p>\n<pre>Send RegisterPath \"GET\" \"\/orderlist\" (RefProc(webAPI_Get)) \"orderlist\"<\/pre>\n<p>as you can see in this route we are calling the same WebAPI_GET method but we are\u00a0 specifying a different schema called &#8220;orderlist&#8221;.<\/p>\n<p>this will return the same dataset but with a much smaller number of fields.<\/p>\n<p>In the following posts in this series we will look into detailed features such as authentication and more.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row _builder_version=&#8221;3.26.7&#8243;][et_pb_column type=&#8221;4_4&#8243; _builder_version=&#8221;3.26.7&#8243;][et_pb_text _builder_version=&#8221;3.26.7&#8243;]\n\t\t<div class='author-shortcodes'>\n\t\t\t<div class='author-inner'>\n\t\t\t\t<div class='author-image'>\n\t\t\t<img src='http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2016\/02\/mike5crop-566174_60x60.jpg' alt='' \/>\n\t\t\t<div class='author-overlay'><\/div>\n\t\t<\/div> \n\t\t<div class='author-info'>\n\t\t\tMichael Salzlechner is the CEO of StarZen Technologies, Inc.<\/p>\n<p>He was part of the Windows Team at Data Access Worldwide that created the DataFlex for Windows Product before joining\u00a0StarZen Technologies. StarZen Technologies provides consulting services as well as custom Application development and third party products<\/p>\n\t\t<\/div>\n\t\t\t<\/div>\n\t\t<\/div>[\/et_pb_text][\/et_pb_column][\/et_pb_row][\/et_pb_section]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this part of the REST API Library series we will create the order API based on DAWs order entry sample database. We will take a look at additional features such as paging, selections as well as additional features to schemas\/models. to get started lets create the order api controller by adding a new http [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"on","_et_pb_old_content":"","_et_gb_content_width":"","ngg_post_thumbnail":0,"footnotes":""},"categories":[6,27,1],"tags":[],"class_list":["post-831","post","type-post","status-publish","format-standard","hentry","category-dataflex","category-dataflex-webapp","category-uncategorized"],"_links":{"self":[{"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/posts\/831","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/comments?post=831"}],"version-history":[{"count":11,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/posts\/831\/revisions"}],"predecessor-version":[{"id":854,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/posts\/831\/revisions\/854"}],"wp:attachment":[{"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/media?parent=831"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/categories?post=831"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/tags?post=831"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}