{"id":773,"date":"2020-10-10T22:56:40","date_gmt":"2020-10-11T02:56:40","guid":{"rendered":"http:\/\/salzlechner.com\/dev\/?p=773"},"modified":"2020-12-05T08:31:17","modified_gmt":"2020-12-05T13:31:17","slug":"starzen-rest-library-for-dataflex-webapp-a-simple-rest-service","status":"publish","type":"post","link":"http:\/\/salzlechner.com\/dev\/2020\/10\/10\/starzen-rest-library-for-dataflex-webapp-a-simple-rest-service\/","title":{"rendered":"StarZen REST library for DataFlex WebApp \u2013 A simple REST service"},"content":{"rendered":"<p>[et_pb_section fb_built=&#8221;1&#8243; _builder_version=&#8221;3.26.7&#8243;][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>To start lets create a very simple manual REST service. No database involved just a simple service that returns a simple JSON object.<\/p>\n<p>To do this we create a Web HTTP handler based on the cszWebAPIController class. lets call it oManualSimpleAPI<\/p>\n<p>o show this we modify our main router view in App.vue as follows<\/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; custom_padding=&#8221;||0px|||&#8221;]<\/p>\n<pre class=\"lang:default decode:true\">Object oManualSimpleAPI is a cszWebAPIController\n    Set psPath to \"api\/v1\/manualsimple\"\n    Set psVerbs to \"*\"\nEnd_Object\n<\/pre>\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;]<\/p>\n<p>This will create a simple Web API controller with the path<\/p>\n<ul>\n<li>api\/v1\/manualsimple<\/li>\n<\/ul>\n<p>all verbs are allowed<\/p>\n<p>by itself this will not do anything yet. We now have to declare routes\/paths and add functionality<\/p>\n<p>First we want to add a simple GET method that returns a json object<\/p>\n<p>In order to do this we add the following method to the 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;]<\/p>\n<pre class=\"lang:default decode:true\">\/\/ get method returns data as json\nProcedure ManualGet \n    Integer hoJson\n        \n    Get Create (RefClass(cJsonObject)) to hoJson\n    Send InitializeJsonType of hoJson jsonTypeObject\n        \n    Send SetMemberValue to hoJson \"timestamp\" jsonTypeString (ConvertToClient(typeDateTime, CurrentDateTime()))\n    Send SetMemberValue to hoJson \"message\" jsonTypeString \"Hello World\"\n        \n    Send OutputJson hoJson\n    Send Destroy to hoJson\nEnd_Procedure\n<\/pre>\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;]<\/p>\n<p>This method creates a json object fills it with data and returns the json data from the service.<\/p>\n<p>But we also have to declare the route as follows<\/p>\n<p>[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row _builder_version=&#8221;3.26.7&#8243; custom_margin=&#8221;14px|auto||auto||&#8221;][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<pre class=\"lang:default decode:true\">\/\/ register path with method \nSend RegisterPath \"GET\" \"\" (RefProc(ManualGet)) \nSet pbPathScalar to True\nSet psPathSummary to \"Manual API function\"\n<\/pre>\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;]<\/p>\n<p>We register a blank path with the get verb and tell the controller to call the ManualGet method for this path.<\/p>\n<p>We also tell the controller that the path has a scalar result (a single result vs a list) and we define a summary text for the route.<\/p>\n<p>Now we can test this route by calling the following url for example via Postman or curl or even simply in a browser<\/p>\n<p><em><strong>http:\/\/localhost\/szWebAPI\/api\/v1\/manualsimple<\/strong><\/em><\/p>\n<p>the server should respond with a return code of 200 and the following response body<\/p>\n<p><strong>{<\/strong><\/p>\n<div>\n<div><strong>\u00a0\u00a0\u00a0\u00a0&#8220;timestamp&#8221;:\u00a0&#8220;2020-10-10T08:51:19.048&#8221;,<\/strong><\/div>\n<div><strong>\u00a0\u00a0\u00a0\u00a0&#8220;message&#8221;:\u00a0&#8220;Hello\u00a0World&#8221;<\/strong><\/div>\n<div><strong>}<\/strong><\/div>\n<p>Now lets take a look at abother feature. The web api controller has a feature built in to document its functions using the OpenAPI specifications. These can then be viewed in swagger UI.<\/p>\n<p>by default the controller is enabled to automatically produce the documentation on the root path using a url parameter called &#8216;openapispec&#8217;<\/p>\n<p>\u00a0calling the following url on the controller<\/p>\n<p><strong>http:\/\/localhost\/szWebAPI\/api\/v1\/<em>manualsimple?<\/em>openapi=true<\/strong><\/p>\n<p>will create a yaml document with OpenAPI specifications describing the web service.<\/p>\n<p>We can use this document for example in swagger editor to show a visual representation of our API<\/p>\n<p>\u00a0<img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2020\/10\/manapi-1024x376.png\" width=\"1024\" height=\"376\" alt=\"\" class=\"wp-image-792 alignnone size-large\" srcset=\"http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2020\/10\/manapi-1024x376.png 1024w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2020\/10\/manapi-300x110.png 300w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2020\/10\/manapi-768x282.png 768w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2020\/10\/manapi-1080x397.png 1080w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2020\/10\/manapi.png 1859w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<p>you can see in this screengrab we have a GET function for the Url\u00a0<strong>\/manualsimple<\/strong>.<\/p>\n<p>It has no parameters and the response is going to send a 200 http response code.<\/p>\n<p>But we do not see what type of data is returned from the service. It would be nice to know a schema for the returned data.\u00a0<\/p>\n<p>All we need to do is to add some additional code to define a schema for the returned json data<\/p>\n<p>To do this we add the following method to our controller<\/p>\n<\/div>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;3.26.7&#8243;]<\/p>\n<pre>\/\/\nProcedure OnDefineModels\n Send BeginModel \"manual\"\n Send AddModelColumn 0 0 False jsonTypeString DF_ASCII \"timeStamp\" False False\n Send AddModelColumn 0 0 False jsonTypeString DF_ASCII \"message\" False False\n Send EndModel \nEnd_Procedure<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;3.26.7&#8243;]In the OnDefineModels event we create a model\/schema with the name manual\u00a0and add two columns to it.<\/p>\n<p>then we need to assign the model to the route as well[\/et_pb_text][et_pb_text _builder_version=&#8221;3.26.7&#8243;]<\/p>\n<pre>\/\/\nSend RegisterPath \"GET\" \"\" (RefProc(ManualGet))\nSend AddPathresponse 200 \"successful\" \"application\/json\" True \"manual\"\nSet pbPathScalar to True\nSet psPathSummary to \"Manual API function\"\u00a0<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;3.26.7&#8243;]<\/p>\n<p>We added the line to declare a response. The response code is 200, we added text and content type as well as a name for the schema which is &#8220;manual&#8221;<\/p>\n<p>Now if we look at the documentation for our API we can see that the schema is now defined in the documentation as well<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2020\/10\/manapi1-1024x730.png\" width=\"1024\" height=\"730\" alt=\"\" class=\"wp-image-787 alignnone size-large\" srcset=\"http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2020\/10\/manapi1-1024x730.png 1024w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2020\/10\/manapi1-300x214.png 300w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2020\/10\/manapi1-768x548.png 768w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2020\/10\/manapi1-400x284.png 400w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2020\/10\/manapi1-1080x770.png 1080w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2020\/10\/manapi1.png 1844w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>This will make it easier for a developer consuming our service.<\/p>\n<p>This is it for this second part of the series. In the next part we will look at an API based on a database specifically the order entry sample workspace database.<\/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;]<\/p>\n\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>\n<p>[\/et_pb_text][\/et_pb_column][\/et_pb_row][\/et_pb_section]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>To start lets create a very simple manual REST service. No database involved just a simple service that returns a simple JSON object. To do this we create a Web HTTP handler based on the cszWebAPIController class. lets call it oManualSimpleAPI o show this we modify our main router view in App.vue as followsObject oManualSimpleAPI [&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],"tags":[],"class_list":["post-773","post","type-post","status-publish","format-standard","hentry","category-dataflex","category-dataflex-webapp"],"_links":{"self":[{"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/posts\/773","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=773"}],"version-history":[{"count":26,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/posts\/773\/revisions"}],"predecessor-version":[{"id":891,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/posts\/773\/revisions\/891"}],"wp:attachment":[{"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/media?parent=773"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/categories?post=773"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/tags?post=773"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}