<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Blog @ SIB Visions &#187; REST</title>
	<atom:link href="http://blog.sibvisions.com/tag/rest/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.sibvisions.com</link>
	<description>Blog @ SIB Visions</description>
	<lastBuildDate>Mon, 30 Mar 2026 11:14:36 +0000</lastBuildDate>
		<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>JVx&#039; REST interface Update for JVx 2.8</title>
		<link>https://blog.sibvisions.com/2018/10/30/jvx-rest-interface-update-for-jvx-2-8/</link>
		<comments>https://blog.sibvisions.com/2018/10/30/jvx-rest-interface-update-for-jvx-2-8/#comments</comments>
		<pubDate>Tue, 30 Oct 2018 14:23:34 +0000</pubDate>
		<dc:creator>rjahn</dc:creator>
				<category><![CDATA[API]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[JVx]]></category>
		<category><![CDATA[REST]]></category>

		<guid isPermaLink="false">https://blog.sibvisions.com/?p=8143</guid>
		<description><![CDATA[Our generic REST interface in JVx is well documented and different examples for different technologies are available. The generic approach itself is smart but not super specific because the implementation follows the CoC paradigm. It's awesome for "REST out-of-the-box" without additional coding effort, but the flexibility is sometimes missing.
We tried to break some of this [...]]]></description>
			<content:encoded><![CDATA[<p>Our generic REST interface in JVx is well <a href="http://doc.sibvisions.com/jvx/common/util/rest">documented</a> and <a href="http://doc.sibvisions.com/jvx/home">different examples</a> for different technologies are available. The generic approach itself is smart but not super specific because the implementation follows the <a href="https://en.wikipedia.org/wiki/Convention_over_configuration">CoC</a> paradigm. It's awesome for "REST out-of-the-box" without additional coding effort, but the flexibility is sometimes missing.</p>
<p>We tried to break some of this restrictions and get more flexibility. Here is a list of new features to explain some details:</p>
<ul>
<li><strong>Fetch on demand</strong>
<p>The old implementation always returned all records from the database. It wasn't possible to implement paging or lazy loading. To solve this problem, we introduced new request parameters:</p>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;">_firstRow<br />
_maxRows</div>
</div>
<p>With _firstRow (starts from 0) you define the start record number. The _maxRows defines the amount of records for the resultset, e.g. start from 0 and return max. 20 records, start from 20 and return 20 records
</li>
<li><strong>Configure visible columns</strong>
<p>The old implementation returned the same column list for the REST call and the GUI/frontend. But sometimes the REST call should return a different list of columns because some internal columns aren't relevant or should be hidden. The new implementation got a new property in the metadata object: <strong>visibleColumnNames</strong>. If you set this property, the REST interface will return only the configure columns. The GUI won't recognize the new property because GUI controls have own visible column properties.</li>
<li><strong>Actions with Array parameters</strong>
<p>The old implementation didn't support simple Arrays like <strong>BigDecimal[]</strong> as parameter types for action calls. Only <strong>List<BigDecimal></strong> was supported. The new implementation supports Arrays but it's not possible to mix Array and List parameters. An example:</p>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;"><span class="co1">//valid</span><br />
<span class="kw1">public</span> <span class="kw3">String</span> createPerson<span class="br0">&#40;</span><span class="kw3">String</span><span class="br0">&#91;</span><span class="br0">&#93;</span> name, <span class="kw3">String</span><span class="br0">&#91;</span><span class="br0">&#93;</span> title<span class="br0">&#41;</span><br />
<span class="co1">//valid</span><br />
<span class="kw1">public</span> <span class="kw3">String</span> createPerson<span class="br0">&#40;</span>List<span class="sy0">&lt;</span>String<span class="sy0">&gt;</span> name, List<span class="sy0">&lt;</span>String<span class="sy0">&gt;</span> title<span class="br0">&#41;</span><br />
<span class="co1">//invalid</span><br />
<span class="kw1">public</span> <span class="kw3">String</span> createPerson<span class="br0">&#40;</span><span class="kw3">String</span><span class="br0">&#91;</span><span class="br0">&#93;</span> name, List<span class="sy0">&lt;</span>String<span class="sy0">&gt;</span> title<span class="br0">&#41;</span></div>
</div>
</li>
<li><strong>New admin zone</strong>
<p>We introduced a new admin zone for generic admin options. The URLs are:</p>
<div class="codesnip-container" >
<div class="html4strict codesnip" style="font-family:monospace;">http://.../services/rest/APPLICATION_NAME/_admin/ACTION_NAME<br />
http://.../services/rest/APPLICATION_NAME/_admin/ACTION_NAME/ACTION_PARAM</div>
</div>
<p>Currently, we support following actions (POST requests): changePassword, testAuthentication</p>
<p>The request needs a JSON object with username, oldpassword, newpassword or password properties.</li>
<li><strong>Configurable zones</strong>
<p>We now allow custom zones. The current default zones are:</p>
<div class="codesnip-container" >
<div class="html4strict codesnip" style="font-family:monospace;">http://.../services/rest/APPLICATION_NAME/_admin/...<br />
http://.../services/rest/APPLICATION_NAME/LIFECYCLE_CLASS/data/OBJECT_NAME/...<br />
http://.../services/rest/APPLICATION_NAME/LIFECYCLE_CLASS/action/ACTION_NAME/...<br />
http://.../services/rest/APPLICATION_NAME/LIFECYCLE_CLASS/object/OBJECT_NAME/...</div>
</div>
<p>The zone names are: <strong>_admin</strong>, <strong>data</strong>, <strong>action, object</strong><br />
It's possible to set custom names with following parameters in the deployment descriptor: <strong>zone.admin</strong>, <strong>zone.data</strong>, <strong>zone.action</strong>, <strong>zone.object</strong></li>
<li><strong>Hide object names</strong>
<p>If you want to hide the object name(s), e.g.</p>
<div class="codesnip-container" >
<div class="html4strict codesnip" style="font-family:monospace;">https://.../demoerp/services/rest/DemoERP/Customers/data/customer/</div>
</div>
<p>The URL contains the Lifecycle Name (Customers) and the object name (customer). Both are easy to understand. In this example, we return the customer list from our customers object. If you want to use different names, it's possible to change the name in the lifecycle object code, e.g.</p>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;">@Replacement<span class="br0">&#40;</span>name<span class="sy0">=</span><span class="st0">&quot;business&quot;</span><span class="br0">&#41;</span><br />
<span class="kw1">public</span> <span class="kw1">class</span> Customers <span class="kw1">extends</span> Session<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; @Replacement<span class="br0">&#40;</span>name<span class="sy0">=</span><span class="st0">&quot;clist&quot;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">public</span> IStorage getCustomer<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ...<br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>With above code, it'll be possible to request:</p>
<div class="codesnip-container" >
<div class="html4strict codesnip" style="font-family:monospace;">https://.../demoerp/services/rest/DemoERP/business/data/clist/</div>
</div>
</li>
</ul>
<p>The updated implementation is still a generic solution but it's now more flexible than before and should help you to offer new services. To use the new features, simply use our nightly <a href="https://dev.sibvisions.com/jvx.nightly/">JVx builds</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.sibvisions.com/2018/10/30/jvx-rest-interface-update-for-jvx-2-8/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AngularJS 4 with VisionX and JVx REST services</title>
		<link>https://blog.sibvisions.com/2017/10/23/angularjs-4-with-visionx-and-jvx-rest-services/</link>
		<comments>https://blog.sibvisions.com/2017/10/23/angularjs-4-with-visionx-and-jvx-rest-services/#comments</comments>
		<pubDate>Mon, 23 Oct 2017 21:58:43 +0000</pubDate>
		<dc:creator>rjahn</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AngularJS]]></category>
		<category><![CDATA[JVx]]></category>
		<category><![CDATA[REST]]></category>

		<guid isPermaLink="false">https://blog.sibvisions.com/?p=7337</guid>
		<description><![CDATA[Some time ago I wrote articles about my "web-technology" tests. The first article covered AngularJS with JVx in action. It was a simple list view for contacts, had an Edit form and was based on AngularJS 1.4. The second article was about Oracle JET with JVx. The result was another list view with contacts, without [...]]]></description>
			<content:encoded><![CDATA[<p>Some time ago I wrote articles about my "web-technology" tests. The first article covered <a href="https://blog.sibvisions.com/2015/06/15/angularjs-with-jvx-in-action/">AngularJS with JVx in action</a>. It was a simple list view for contacts, had an Edit form and was based on AngularJS 1.4. The second article was about <a href="https://blog.sibvisions.com/2016/02/29/using-oracle-jet-with-visionxjvx/">Oracle JET with JVx</a>. The result was another list view with contacts, without Edit form.</p>
<p>Both solutions were more or less a demonstration for the automatic REST interface of JVx but not a real technology PoC.</p>
<p>The second article about Oracle JET was written in Feb 2016 and the first, about AngularJS, was written in July 2015 - long time ago. Currently, Angular 4 is available and Angular 5 is coming. Big version jumps with big API changes and many new features.</p>
<p>Last week, I thought it might a good idea to start a new evaluation of AngularJS. One week later, I think different... but one step after another.</p>
<p>My plan was the creation of a very simple application with some enhanced features, like routing, CRUD, styling, custom components, REST with authentication, Deployment. This was the base idea because I read really cool marketing articles about Angular and thought it might be easy to create a simple application with expected features.</p>
<p><strong>So, what did I do to start?</strong></p>
<p>The <a href="https://angular.io/tutorial/">Angular tutorial</a> was great for a jump start. You'll build a smart heroes application with a small dashboard. Sure, it's not a real world application but has everything on board and hey, the Tutorial will show how to integrate REST services. I thought it might be an easy task and won't last more than 1 day!</p>
<p>The tutorial has 7 chapters and the last one integrates REST. The chapter 1 was easy, because it was the instruction <img src='https://blog.sibvisions.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  The second chapter contains the setup process which should be trivial, because I manually tried to create an AngularJS 4 application from scratch and it was super simple. But the setup for the tutorial wasn't easy because the creation of a new project from scratch contained too many files and the expected project layout (shown in the tutorial) was reduced to a bare minimum. It wasn't possible to delete all additional files because the project preview in the browser didn't work afterwards. So I decided to download the example archive.</p>
<p>This was the right decission because everything was pre-configured <img src='https://blog.sibvisions.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  First lesson learned: Project configuration is not easy and woha, many different config files.</p>
<p>It was super easy to follow the tutorial and chapters 3, 4 were relative short and fast to do. Starting with chapter 5, the whole thing was starting to get complex because Service integration, Routing and HTTP(REST) were complex things. The chapters 5, 6 and 7 are very long and boring because you have to do so many things (hey, it's a tutorial and it's good as it is!).<br />
No worries because I'm an "expert" and so I jumped to Chapter 6 and downloaded the finished example archive. The example was working without problems in my test environment <img src='https://blog.sibvisions.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  but it was without support for HTTP/REST calls because I thought it might be a good idea to integrate the features based on the tutorial on my own.</p>
<p>So the next step was the integration of my own REST service instead of the dummy service in the tutorial. But first... I needed a REST service.</p>
<p>The creation of a web service was super easy because of our <a href="https://visionx.sibvisions.com">Low Code Development Platform - VisionX</a>. It creates <a href="http://jvx.sibvisions.com/">JVx</a> based applications with all gimmicks. I did create a simple Heroes application with VisionX. The application has one screen:</p>
<div id="attachment_7339" class="wp-caption aligncenter" style="width: 310px"><a href="https://blog.sibvisions.com/wp-content/uploads/2017/10/visionx_heroes_app.png" rel="lightbox[7337]"><img src="https://blog.sibvisions.com/wp-content/uploads/2017/10/visionx_heroes_app-300x228.png" alt="Heroes app created with VisionX" title="visionx_heroes_app" width="300" height="228" class="size-medium wp-image-7339" /></a><p class="wp-caption-text">Heroes app created with VisionX</p></div>
<p>The application was ready to use in 1 minute and had one database table:</p>
<div id="attachment_7341" class="wp-caption aligncenter" style="width: 310px"><a href="https://blog.sibvisions.com/wp-content/uploads/2017/10/visionx_heroes_dbmodel.png" rel="lightbox[7337]"><img src="https://blog.sibvisions.com/wp-content/uploads/2017/10/visionx_heroes_dbmodel-300x178.png" alt="Heroes table" title="visionx_heroes_dbmodel" width="300" height="178" class="size-medium wp-image-7341" /></a><p class="wp-caption-text">Heroes table</p></div>
<p>The heroes table contains the columns: ID and NAME. Thanks to JVx, the REST service was ready-to-use. The request: <em><strong>http://localhost/services/rest/Heroes/HeroesWorkScreen/data/heroes</strong></em></p>
<p>returned the JSON string with my test data:</p>
<div class="codesnip-container" >
<div class="javascript codesnip" style="font-family:monospace;"><span class="br0">&#91;</span><br />
&nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="st0">&quot;ID&quot;</span><span class="sy0">:</span> <span class="nu0">1</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">&quot;NAME&quot;</span><span class="sy0">:</span> <span class="st0">&quot;Superman&quot;</span><br />
&nbsp; <span class="br0">&#125;</span><span class="sy0">,</span><br />
&nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="st0">&quot;ID&quot;</span><span class="sy0">:</span> <span class="nu0">4</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">&quot;NAME&quot;</span><span class="sy0">:</span> <span class="st0">&quot;Rambo (John)&quot;</span><br />
&nbsp; <span class="br0">&#125;</span><span class="sy0">,</span><br />
&nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="st0">&quot;ID&quot;</span><span class="sy0">:</span> <span class="nu0">6</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">&quot;NAME&quot;</span><span class="sy0">:</span> <span class="st0">&quot;Wolverine (X-Men)&quot;</span><br />
&nbsp; <span class="br0">&#125;</span><span class="sy0">,</span><br />
&nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="st0">&quot;ID&quot;</span><span class="sy0">:</span> <span class="nu0">2</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">&quot;NAME&quot;</span><span class="sy0">:</span> <span class="st0">&quot;Batman&quot;</span><br />
&nbsp; <span class="br0">&#125;</span><span class="sy0">,</span><br />
&nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="st0">&quot;ID&quot;</span><span class="sy0">:</span> <span class="nu0">5</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">&quot;NAME&quot;</span><span class="sy0">:</span> <span class="st0">&quot;Captain America&quot;</span><br />
&nbsp; <span class="br0">&#125;</span><span class="sy0">,</span><br />
&nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="st0">&quot;ID&quot;</span><span class="sy0">:</span> <span class="nu0">3</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">&quot;NAME&quot;</span><span class="sy0">:</span> <span class="st0">&quot;ANT MAN&quot;</span><br />
&nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#93;</span></div>
</div>
<p>So, my backend was ready.</p>
<p>The Next step was the integration into my Angular frontend. It was easy to find the right source file for the integration, because the hero-service was encapsulated. The first problem was that my REST service required authentication and the service implementation didn't use authentication. I had the same problem with missing authentication support in Angular 1.4 but found some useful things on stackoverflow. With Angular 4 everything has changed because you code Typescript and the API is different to 1.4, so my old solution didn't work. I tried to find something in the Internet but had a lot of problems because most help was for Angular 2. And I found so many github issues for http authentication and most issues had tons of comments... frustrating and not effective.</p>
<p>I tried to search in the official Angular documentation and found some hints about HttpClient in the <a href="https://angular.io/guide/http">online guide</a>. But I didn't know HttpClient because my example was created with HttpModule. Not helpful that the example from the tutorial is different to the official documentation.... or.... I didn't read the details.... or.... I'm a bad developer.... or (and this is a fact) my Javascript/Typescript know-how is not enough. But anyway, it was not a standard task to add authentication to my hero-service.</p>
<p>I'm not 100% sure how I solved the problem, but I guess I read the <a href="https://angular.io/api/http/RequestOptions">API doc about http</a> and an <a href="https://medium.com/google-developer-experts/angular-2-introduction-to-new-http-module-1278499db2a0">information about the new Angular2 HttpModule</a> (means that HttpModule is old and HttpClient is new?). I googled around for sime time and tried a lot of hints, but it was painful. So much documentation about such a simple problem and no concreate solution for the http authentication problem.</p>
<p>Here's my solution:</p>
<div class="codesnip-container" >
<div class="javascript codesnip" style="font-family:monospace;"><span class="kw2">export</span> <span class="kw2">class</span> HeroService <span class="br0">&#123;</span><br />
&nbsp; <br />
&nbsp; <span class="kw2">private</span> heroesUrl <span class="sy0">:</span> string<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; <span class="kw2">private</span> options <span class="sy0">:</span> RequestOptions<span class="sy0">;</span><br />
&nbsp; <span class="kw2">private</span> headers <span class="sy0">:</span> Headers<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; constructor<span class="br0">&#40;</span><span class="kw2">private</span> http<span class="sy0">:</span> Http<span class="br0">&#41;</span> <br />
&nbsp; <span class="br0">&#123;</span> <br />
&nbsp; &nbsp; <span class="kw1">this</span>.<span class="me1">headers</span> <span class="sy0">=</span> <span class="kw2">new</span> Headers<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">this</span>.<span class="me1">headers</span>.<span class="me1">append</span><span class="br0">&#40;</span><span class="st0">'Accept'</span><span class="sy0">,</span> <span class="st0">'application/json'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">this</span>.<span class="me1">headers</span>.<span class="me1">append</span><span class="br0">&#40;</span><span class="st0">'Content-Type'</span><span class="sy0">,</span> <span class="st0">'application/json'</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">this</span>.<span class="me1">headers</span>.<span class="me1">append</span><span class="br0">&#40;</span><span class="st0">'Authorization'</span><span class="sy0">,</span> <span class="st0">'Basic '</span> <span class="sy0">+</span> btoa<span class="br0">&#40;</span><span class="st0">&quot;admin:admin&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw1">this</span>.<span class="me1">options</span> <span class="sy0">=</span> <span class="kw2">new</span> RequestOptions<span class="br0">&#40;</span><span class="br0">&#123;</span> headers<span class="sy0">:</span> <span class="kw1">this</span>.<span class="me1">headers</span><span class="sy0">,</span> withCredentials<span class="sy0">:</span> <span class="kw2">true</span> <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">this</span>.<span class="me1">heroesUrl</span> <span class="sy0">=</span> <span class="st0">'http://localhost/services/rest/Heroes/HeroesWorkScreen/data/heroes'</span><span class="sy0">;</span><br />
&nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; getHeroes<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">:</span> Promise<span class="sy0">&lt;</span>Hero<span class="br0">&#91;</span><span class="br0">&#93;</span><span class="sy0">&gt;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw1">this</span>.<span class="me1">http</span>.<span class="me1">get</span><span class="br0">&#40;</span><span class="kw1">this</span>.<span class="me1">heroesUrl</span><span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">options</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span class="me1">toPromise</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span class="me1">then</span><span class="br0">&#40;</span>response <span class="sy0">=&gt;</span> response.<span class="me1">json</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="kw1">as</span> Hero<span class="br0">&#91;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span class="kw1">catch</span><span class="br0">&#40;</span><span class="kw1">this</span>.<span class="me1">handleError</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <span class="br0">&#125;</span></p>
<p><span class="br0">&#125;</span></div>
</div>
<p>I know that username and admin are hard-coded but it's a simple test application without login. It's not really a problem to add a login form if needed and to replace the hard-coded values with variables.</p>
<p>After I solved the authentication problem, and everything was working in my test environment, I tried to continue with tutorial chapter 7 and tried to add new features like Adding new heroes, Deleting heroes. This was really straight forward and worked without problems, even with authentication.</p>
<p>Yuhu. After two days I had a working Angular 4 application which reads data from a REST service and offers CRUD. A simple routing was available and I had custom components, styling and was happy. I thought the next step should be a test deployment. Sounds easy and I thought it couldn't be a problem... but... deployment hell.</p>
<p><strong>Why is Angular deployment so complex?</strong></p>
<p>The documentation has a lot of information about <a href="https://angular.io/guide/deployment">deployment</a>. The simple deployment is really straight-forward because it's enough to copy/paste your development environment. But this is not recommended for production environments because of performance and many other things. So, i tried to deploy a production ready application and not my development environment... And the nightmare started.</p>
<p>I found a <a href="https://coursetro.com/posts/code/64/How-to-Deploy-an-Angular-App-(Angular-4)">super simple deployment guide for Angular 4</a>. First problem: didn't work for my example project because:</p>
<div class="codesnip-container" >Unable to find @angular/cli in devDependencies</p>
<p>Please take the following steps to avoid issues:<br />
"npm install --save-dev @angular/cli@latest"</p></div>
<p>After installing the missing module, the next problem:</p>
<div class="codesnip-container" >Cannot read property 'config' of null<br />
TypeError: Cannot read property 'config' of null</div>
<p>Also no problem because google found that my project needs an additional config file:</p>
<p><strong>.angular-cli.json</strong></p>
<p>I found this file in my demo Angular application, created from scratch. I tried to edit and adapt the file for my heroes application and the next problem came up:</p>
<div class="codesnip-container" >ENOENT: no such file or directory, stat '...\angular-tour-of-heroes\src\tsconfig.app.json'</div>
<p>No problem, same solution as before (copy/paste/change).</p>
<p>Hurray, the command:</p>
<div class="codesnip-container" >ng build -prod</div>
<p>was successful!</p>
<p>The dist folder contained my production ready application with 6 files! Great.</p>
<p>The deployment to my Tomcat application server was also super easy, because VisionX is able to create war files with a single mouse click. I changed the created war file and put the built Angular files in the root directory and deployed the war file.</p>
<p>No surprise, the application didn't work because some javascript files weren't found. The developer console of Chrome browser was a big help!</p>
<p><strong>So, what should I do?</strong></p>
<p>No... not Google. I read the development guide and found the solution in section <a href="https://angular.io/guide/deployment#load-npm-package-files-from-the-web-systemjs">Load npm package files from the web (SystemJS)</a>.</p>
<p>So, I changed my deployment and replaced <strong>node_modules</strong> in my <em>index.html</em> with <strong>https://unpkg.com/</strong>. This solved one problem but the developer console showed more 404 errors. I had to remove following:</p>
<div class="codesnip-container" >
<div class="html4strict codesnip" style="font-family:monospace;"><span class="sc2">&lt;<a href="http://december.com/html/4/element/script.html"><span class="kw2">script</span></a>&gt;</span>System.import('main.js').catch(function(err){ console.error(err); });<span class="sc2">&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/script.html"><span class="kw2">script</span></a>&gt;</span></div>
</div>
<p>and</p>
<div class="codesnip-container" >
<div class="html4strict codesnip" style="font-family:monospace;"><span class="sc2">&lt;<a href="http://december.com/html/4/element/link.html"><span class="kw2">link</span></a> <span class="kw3">rel</span><span class="sy0">=</span><span class="st0">&quot;stylesheet&quot;</span> <span class="kw3">href</span><span class="sy0">=</span><span class="st0">&quot;styles.css&quot;</span>&gt;</span></div>
</div>
<p>I also had to replace the <strong>node_modules</strong> path in systemjs.config.js with <strong>https://unpkg.com/</strong>. Oh, and the file was missing in dist folder. I decided to follow the deployment guide and created a file with the name <strong>systemjs.config.server.js</strong>. If you do this, the <strong>index.html</strong> needs a changed mapping.</p>
<p>I didn't replace the values by hand. Here's my ant build file:</p>
<div class="codesnip-container" >
<div class="xml codesnip" style="font-family:monospace;"><span class="sc3"><span class="re1">&lt;project</span> <span class="re0">name</span>=<span class="st0">&quot;AngularJS&quot;</span> <span class="re0">default</span>=<span class="st0">&quot;start.complete&quot;</span><span class="re2">&gt;</span></span></p>
<p>&nbsp; <span class="sc-1">&lt;!--</span><br />
<span class="sc-1"> &nbsp;*****************************************************************</span><br />
<span class="sc-1"> &nbsp;* information</span><br />
<span class="sc-1"> &nbsp;*****************************************************************</span><br />
<span class="sc-1"> &nbsp;--&gt;</span></p>
<p>&nbsp; <span class="sc3"><span class="re1">&lt;description<span class="re2">&gt;</span></span></span>Angular JS deployment<span class="sc3"><span class="re1">&lt;/description<span class="re2">&gt;</span></span></span></p>
<p>&nbsp; <span class="sc-1">&lt;!--</span><br />
<span class="sc-1"> &nbsp;*****************************************************************</span><br />
<span class="sc-1"> &nbsp;* tasks</span><br />
<span class="sc-1"> &nbsp;*****************************************************************</span><br />
<span class="sc-1"> &nbsp;--&gt;</span></p>
<p>&nbsp; <span class="sc3"><span class="re1">&lt;target</span> <span class="re0">name</span>=<span class="st0">&quot;start.complete&quot;</span> <span class="re0">description</span>=<span class="st0">&quot;Prepares production files&quot;</span><span class="re2">&gt;</span></span></p>
<p>&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;property</span> <span class="re0">name</span>=<span class="st0">&quot;heroes&quot;</span> <span class="re0">location</span>=<span class="st0">&quot;D:/dev/other/angularjs/angular-tour-of-heroes&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;property</span> <span class="re0">name</span>=<span class="st0">&quot;dist&quot;</span> &nbsp; <span class="re0">location</span>=<span class="st0">&quot;${heroes}/dist&quot;</span> <span class="re2">/&gt;</span></span></p>
<p>&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;replace</span> <span class="re0">file</span>=<span class="st0">&quot;${dist}/index.html&quot;</span> <span class="re0">encoding</span>=<span class="st0">&quot;UTF-8&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;replacetoken<span class="re2">&gt;</span></span></span><span class="sc2">&lt;![CDATA[&lt;link rel=&quot;stylesheet&quot; href=&quot;styles.css&quot;&gt;]]&gt;</span><span class="sc3"><span class="re1">&lt;/replacetoken<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;replacevalue<span class="re2">&gt;</span></span></span><span class="sc2">&lt;![CDATA[]]&gt;</span><span class="sc3"><span class="re1">&lt;/replacevalue<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/replace<span class="re2">&gt;</span></span></span></p>
<p>&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;replace</span> <span class="re0">file</span>=<span class="st0">&quot;${dist}/index.html&quot;</span> <span class="re0">encoding</span>=<span class="st0">&quot;UTF-8&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;replacetoken<span class="re2">&gt;</span></span></span><span class="sc2">&lt;![CDATA[&lt;script&gt;System.import('main.js').catch(function(err){ console.error(err); });&lt;/script&gt;]]&gt;</span><span class="sc3"><span class="re1">&lt;/replacetoken<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;replacevalue<span class="re2">&gt;</span></span></span><span class="sc2">&lt;![CDATA[]]&gt;</span><span class="sc3"><span class="re1">&lt;/replacevalue<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/replace<span class="re2">&gt;</span></span></span></p>
<p>&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;replace</span> <span class="re0">file</span>=<span class="st0">&quot;${dist}/index.html&quot;</span> <span class="re0">encoding</span>=<span class="st0">&quot;UTF-8&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;replacetoken<span class="re2">&gt;</span></span></span><span class="sc2">&lt;![CDATA[node_modules/]]&gt;</span><span class="sc3"><span class="re1">&lt;/replacetoken<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;replacevalue<span class="re2">&gt;</span></span></span><span class="sc2">&lt;![CDATA[https://unpkg.com/]]&gt;</span><span class="sc3"><span class="re1">&lt;/replacevalue<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/replace<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;replace</span> <span class="re0">file</span>=<span class="st0">&quot;${dist}/index.html&quot;</span> <span class="re0">encoding</span>=<span class="st0">&quot;UTF-8&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;replacetoken<span class="re2">&gt;</span></span></span><span class="sc2">&lt;![CDATA[&lt;script src=&quot;systemjs.config.js&quot;&gt;&lt;/script&gt;]]&gt;</span><span class="sc3"><span class="re1">&lt;/replacetoken<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;replacevalue<span class="re2">&gt;</span></span></span><span class="sc2">&lt;![CDATA[&lt;script src=&quot;systemjs.config.server.js&quot;&gt;&lt;/script&gt;]]&gt;</span><span class="sc3"><span class="re1">&lt;/replacevalue<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/replace<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;copy</span> <span class="re0">file</span>=<span class="st0">&quot;${heroes}/src/systemjs.config.server.js&quot;</span> <span class="re0">tofile</span>=<span class="st0">&quot;${dist}/systemjs.config.server.js&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; <span class="sc3"><span class="re1">&lt;/target<span class="re2">&gt;</span></span></span></p>
<p><span class="sc3"><span class="re1">&lt;/project<span class="re2">&gt;</span></span></span></div>
</div>
<p>With above changes, it was possible to use my application with my tomcat application server. But I had two more problems!</p>
<p><strong>First</strong>, my REST service URL was wrong because it was set for my dev environment.<br />
<strong>Second</strong>, the browser reload of URLs didn't work because the application server returned 404 for e.g. <em>https://cloud.sibvisions.com/heroes/heroes/3</em></p>
<p>Two more problems, omg.</p>
<p>But clear, the REST service URL can't be the same in the prod environment. I saw that Angular comes with support for environments and thought this would solve my first problem.... No way!<br />
The problem was that the environment integration worked for build time, but not for development. It wasn't possible to import the environment constant in my Typescript files. It wasn't possible beause the file wasn't routed correctly and I didn't find a solution for this problem. The dev server returned 404 for the access to ../environments/environment.js. I tried to find a solution for more than one day, but gave up. I found out that the config files of an Angular application are evil. You have so many options and have absolutely no idea what's right. This is a common problem if you search the internet and it's a good idea to use a pre-created configuration. But the configuration of the heroes application was different to a newly created configuration. So I reverted all my environment changes and decided to follow the <a href="https://angular.io/guide/deployment#enable-production-mode">official documentation</a>. This  code is the clue:</p>
<div class="codesnip-container" >
<div class="javascript codesnip" style="font-family:monospace;"><span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!/</span>localhost<span class="sy0">/</span>.<span class="me1">test</span><span class="br0">&#40;</span>document.<span class="me1">location</span>.<span class="me1">host</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; enableProdMode<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>It doesn't read the value from the environment constant, as recommended <a href="http://tattoocoder.com/angular-cli-using-the-environment-option/">here</a>. Not sure if this was recommended in Angular 2 and not for Angular 4, but the support is still built-in. I found so many horrible solutions for the environment problem, but no simple and easy one.</p>
<p>I solved the problem with my heroes-service and static properties. Yep, static field properties. It's that easy!</p>
<p>Here's a snippet from my service:</p>
<div class="codesnip-container" >
<div class="javascript codesnip" style="font-family:monospace;"><span class="kw2">export</span> <span class="kw2">class</span> HeroService <span class="br0">&#123;</span><br />
&nbsp; <br />
&nbsp; <span class="kw2">private</span> static heroesUrl <span class="sy0">:</span> string<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; <span class="kw2">public</span> static initMode<span class="br0">&#40;</span>prodMode<span class="sy0">:</span> boolean<span class="br0">&#41;</span><span class="sy0">:</span> <span class="kw1">void</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>prodMode<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; enableProdMode<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; HeroService.<span class="me1">heroesUrl</span> <span class="sy0">=</span> <span class="st0">'https://cloud.sibvisions.com/heroes/services/rest/Heroes/HeroesWorkScreen/data/heroes'</span><span class="sy0">;</span> <br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; HeroService.<span class="me1">heroesUrl</span> <span class="sy0">=</span> <span class="st0">'http://localhost/services/rest/Heroes/HeroesWorkScreen/data/heroes'</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; <span class="br0">&#125;</span><br />
...</div>
</div>
<p>I used the recommended environment detection in my main.ts:</p>
<div class="codesnip-container" >
<div class="javascript codesnip" style="font-family:monospace;">HeroService.<span class="me1">initMode</span><span class="br0">&#40;</span><span class="sy0">!/</span>localhost<span class="sy0">/</span>.<span class="me1">test</span><span class="br0">&#40;</span>document.<span class="me1">location</span>.<span class="me1">host</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
<p>This solved my environment problem completely. I'm not sure what's the best solution and I would recommend the built-in environment solution, but there should be a working tutorial or example for development and deployment.</p>
<p>Second lesson learned: Deployment is not easy with Angular if you want to make it right. The documentation is not clear and it's complex!!!</p>
<p>Back to my second problem: browser reload!<br />
This is documented <a href="https://angular.io/guide/deployment#routed-apps-must-fallback-to-indexhtml">here</a>. Clear, isn't it?</p>
<p>So, no solution for my Apache Tomcat installation. Rewrite rules are supported but why so tricky? I won't configure routing in my application and in the application server. This should simply work.<br />
I tried to find a simple solution and created a simple Filter, because too much configuration was not what I want!</p>
<p>My filter:</p>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;"><span class="kw1">public</span> <span class="kw4">void</span> doFilter<span class="br0">&#40;</span>ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain<span class="br0">&#41;</span> <span class="kw1">throws</span> <span class="kw3">IOException</span>, ServletException<br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">String</span> sURI <span class="sy0">=</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>HttpServletRequest<span class="br0">&#41;</span>pRequest<span class="br0">&#41;</span>.<span class="me1">getRequestURI</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>StringUtil.<span class="me1">isEmpty</span><span class="br0">&#40;</span>FileUtil.<span class="me1">getExtension</span><span class="br0">&#40;</span>sURI<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; RequestDispatcher reqdis <span class="sy0">=</span> pRequest.<span class="me1">getRequestDispatcher</span><span class="br0">&#40;</span>sIndex<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; reqdis.<span class="me1">forward</span><span class="br0">&#40;</span>pRequest, pResponse<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pChain.<span class="me1">doFilter</span><span class="br0">&#40;</span>pRequest, pResponse<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</div>
<p>Configration (web.xml):</p>
<div class="codesnip-container" >
<div class="xml codesnip" style="font-family:monospace;"><span class="sc3"><span class="re1">&lt;filter<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;filter-name<span class="re2">&gt;</span></span></span>IndexHtmlFilter<span class="sc3"><span class="re1">&lt;/filter-name<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;filter-class<span class="re2">&gt;</span></span></span>demo.angular.IndexHtmlFilter<span class="sc3"><span class="re1">&lt;/filter-class<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;init-param<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;param-name<span class="re2">&gt;</span></span></span>index<span class="sc3"><span class="re1">&lt;/param-name<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;param-value<span class="re2">&gt;</span></span></span>/app/index.html<span class="sc3"><span class="re1">&lt;/param-value<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;/init-param<span class="re2">&gt;</span></span></span><br />
&nbsp;<span class="sc3"><span class="re1">&lt;/filter<span class="re2">&gt;</span></span></span><br />
&nbsp;<br />
&nbsp;<span class="sc3"><span class="re1">&lt;filter-mapping<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;filter-name<span class="re2">&gt;</span></span></span>IndexHtmlFilter<span class="sc3"><span class="re1">&lt;/filter-name<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;url-pattern<span class="re2">&gt;</span></span></span>/app/*<span class="sc3"><span class="re1">&lt;/url-pattern<span class="re2">&gt;</span></span></span><br />
&nbsp;<span class="sc3"><span class="re1">&lt;/filter-mapping<span class="re2">&gt;</span></span></span></div>
</div>
<p>Not my best code, but works.... if you put the application in a seperate folder... e.g. The REST servic call:</p>
<p>//souldn't route to index.html<br />
<em>https://cloud.sibvisions.com/heroes/services/rest/Heroes/HeroesWorkScreen/data/heroes </em></p>
<p>//should route to index.html<br />
<em>https://cloud.sibvisions.com/heroes/heroes/2</em></p>
<p>So it was easier to move the application into a sub directory: /app<br />
<em>https://cloud.sibvisions.com/heroes/<strong>app/</strong>heroes/2</em></p>
<p>and everything starting with /app/* will be routed to /app/index.html if necessary.</p>
<p>This configuration and the filter solved my second problem and hurray, my application was working without any problems!</p>
<p>Oh, in order to serve my application from the /app directory, I had to set the base href in index.html:</p>
<div class="codesnip-container" >ng build -prod --base-href /heroes/app/</div>
<p>Here's the application: <a href="https://cloud.sibvisions.com/heroes/app/">https://cloud.sibvisions.com/heroes/app/</a><br />
(Please don't delete my default heroes because there's no "restore defaults" implemented)</p>
<p><strong>What's next?</strong></p>
<p>I wasn't happy with default features of tutorial app because I missed an export feature. So I decided to add a Report which contains all my heroes. The REST service was ready in one minute because VisionX has Reporting support. But how to download/save the report?</p>
<p>I had no example and google returned too many answers for Angular 2 and one for <a href="https://shekhargulati.com/2017/07/16/implementing-file-save-functionality-with-angular-4/">Angular 4</a>. I followed the instructions and had many problems because the saveAs method wasn't found... So I had the next big problem!</p>
<p>Every new feature was a big problem for me <img src='https://blog.sibvisions.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>This feature was horrible because I had absolutely no plan about angular modules. I found several save-file modules and tried to install one by one. No module was working as documented. Not sure if the problem was because of my configuration or because of Angular 4. Finally I found <a href="https://stackoverflow.com/questions/40240796/angular-2-best-approach-to-use-filesaver-js">one solution</a> but I had to change my system.config.js manually and add:</p>
<div class="codesnip-container" >
<div class="javascript codesnip" style="font-family:monospace;"><span class="st0">'file-saver'</span><span class="sy0">:</span> <span class="st0">'npm:file-saver'</span></div>
</div>
<p>to the system loader and</p>
<div class="codesnip-container" >
<div class="javascript codesnip" style="font-family:monospace;"><span class="st0">'file-saver'</span><span class="sy0">:</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; format<span class="sy0">:</span> <span class="st0">'global'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; main<span class="sy0">:</span> <span class="st0">'FileSaver.js'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; defaultExtension<span class="sy0">:</span> <span class="st0">'js'</span><br />
&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</div>
<p>to the packages.</p>
<p>I don't know why the default module installation didn't work but it did not! </p>
<p>After everything worked in my dev environment, I tried the same application in my prod environment and... error.<br />
The FileSaver.js was not found???</p>
<p>Absolutely unclear, but I solved the problem dirty (or not) in my index.html. Simply added </p>
<div class="codesnip-container" >
<div class="html4strict codesnip" style="font-family:monospace;"><span class="sc2">&lt;<a href="http://december.com/html/4/element/script.html"><span class="kw2">script</span></a> <span class="kw3">src</span><span class="sy0">=</span><span class="st0">&quot;node_modules/file-saver/FileSaver.min.js&quot;</span>&gt;&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/script.html"><span class="kw2">script</span></a>&gt;</span></div>
</div>
<p>and it was find in dev and prod environment.</p>
<p>... I thought.</p>
<p>One more problem: Download worked but the content was damaged!</p>
<p>The problem was related to the content-type or maybe the encoding?</p>
<p>Recommended (<a href="https://shekhargulati.com/2017/07/16/implementing-file-save-functionality-with-angular-4/">Solution 1</a>, <a href="https://www.npmjs.com/package/file-saver">Solution 2</a>) solution:</p>
<div class="codesnip-container" >
<div class="javascript codesnip" style="font-family:monospace;"><span class="kw1">this</span>.<span class="me1">http</span>.<span class="me1">post</span><span class="br0">&#40;</span>HeroService.<span class="me1">heroesUrlAction</span> <span class="sy0">+</span> <span class="st0">'createListReportHeroes'</span><span class="sy0">,</span> JSON.<span class="me1">stringify</span><span class="br0">&#40;</span><span class="br0">&#91;</span><span class="kw2">null</span><span class="sy0">,</span> <span class="kw2">null</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.<span class="me1">toPromise</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.<span class="me1">then</span><span class="br0">&#40;</span>response <span class="sy0">=&gt;</span> <span class="br0">&#123;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw2">var</span> blob <span class="sy0">=</span> <span class="kw2">new</span> Blob<span class="br0">&#40;</span><span class="br0">&#91;</span>response._body<span class="br0">&#93;</span><span class="sy0">,</span> <span class="br0">&#123;</span>type<span class="sy0">:</span> <span class="st0">'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'</span><span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;saveAs<span class="br0">&#40;</span>blob<span class="sy0">,</span> <span class="st0">'report.xlsx'</span><span class="br0">&#41;</span><span class="sy0">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#125;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.<span class="kw1">catch</span><span class="br0">&#40;</span><span class="kw1">this</span>.<span class="me1">handleError</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
<p>This wasn't working because something was missing:</p>
<div class="codesnip-container" >
<div class="javascript codesnip" style="font-family:monospace;"><span class="kw2">var</span> optCopy <span class="sy0">=</span> <span class="kw2">new</span> RequestOptions<span class="br0">&#40;</span><span class="br0">&#123;</span> headers<span class="sy0">:</span> <span class="kw1">this</span>.<span class="me1">headers</span><span class="sy0">,</span> withCredentials<span class="sy0">:</span> <span class="kw2">true</span><span class="sy0">,</span> responseType<span class="sy0">:</span> ResponseContentType.<span class="me1">Blob</span> <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;+</span></p>
<p>&nbsp; &nbsp; &nbsp; <span class="kw1">this</span>.<span class="me1">http</span>.<span class="me1">post</span><span class="br0">&#40;</span>HeroService.<span class="me1">heroesUrlAction</span> <span class="sy0">+</span> <span class="st0">'createListReportHeroes'</span><span class="sy0">,</span> JSON.<span class="me1">stringify</span><span class="br0">&#40;</span><span class="br0">&#91;</span><span class="kw2">null</span><span class="sy0">,</span> <span class="kw2">null</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">,</span> optCopy<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.<span class="me1">toPromise</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.<span class="me1">then</span><span class="br0">&#40;</span>response <span class="sy0">=&gt;</span> <span class="br0">&#123;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw2">var</span> blob <span class="sy0">=</span> <span class="kw2">new</span> Blob<span class="br0">&#40;</span><span class="br0">&#91;</span>response.<span class="me1">blob</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="br0">&#123;</span>type<span class="sy0">:</span> <span class="st0">'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'</span><span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;saveAs<span class="br0">&#40;</span>blob<span class="sy0">,</span> <span class="st0">'report.xlsx'</span><span class="br0">&#41;</span><span class="sy0">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#125;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.<span class="kw1">catch</span><span class="br0">&#40;</span><span class="kw1">this</span>.<span class="me1">handleError</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
<p>Clear, the ResponseContentType.Blob has to be set!!!<br />
And if you set this type, the response._body throws a warning? Use response.blob() instead!</p>
<p>It took me one hour to remove this warning!</p>
<p><strong>Next?</strong></p>
<p>I'm done!</p>
<p>The whole application development made me 1 year older because of frustration. I know that I'm not an Angular expert and I didn't read everything in the official documentation or guide/tutorial, but the whole development was a torture - sure, the result is great!</p>
<p>Too many different solutions for simple problems: deployment, downloading a file, configuration.</p>
<p>The documentation is awesome but too complex and contains no simple use cases. A simple deployment would be awesome and the problem with environments was horrible. Angular is powerful, no doubt! The configuration and deployment aren't straight forward. Also the mechanism behind the module system was not always working, at least not for me.</p>
<p>I love using custom components and the styling integration is great. The routing configuration is error-prone without an IDE or specific tools. My application didn't use all available features like testing, linting, ...</p>
<p><strong>Finally</strong></p>
<p>The application is available as JVx application with Vaadin UI <a href="https://cloud.sibvisions.com/heroes/web/ui/">here</a>.<br />
Login with admin as username and password.</p>
<p>The <a href="https://cloud.sibvisions.com/heroes/app/">Angular 4 application</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.sibvisions.com/2017/10/23/angularjs-4-with-visionx-and-jvx-rest-services/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>JVx 1.0 with REST support</title>
		<link>https://blog.sibvisions.com/2011/12/14/jvx-1-0-with-rest-support/</link>
		<comments>https://blog.sibvisions.com/2011/12/14/jvx-1-0-with-rest-support/#comments</comments>
		<pubDate>Wed, 14 Dec 2011 20:47:54 +0000</pubDate>
		<dc:creator>rjahn</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[JVx]]></category>
		<category><![CDATA[REST]]></category>

		<guid isPermaLink="false">http://blog.sibvisions.com/?p=1116</guid>
		<description><![CDATA[Some of you asked us: When is JVx 1.0 available?
The answer was and is still: This year 
More precisely: Planned release date is Friday, 23rd December. 
The current version in our SVN repository is Feature complete. Only some tickets are still open, but all of them are not really important for 1.0. Some are beautifying [...]]]></description>
			<content:encoded><![CDATA[<p>Some of you asked us: <strong>When is JVx 1.0 available</strong>?</p>
<p>The answer was and is still: This year <img src='https://blog.sibvisions.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /><br />
More precisely: Planned release date is Friday, 23rd December. </p>
<p>The current version in our SVN repository is Feature complete. Only some tickets are still open, but all of them are not really important for 1.0. Some are beautifying and some are smaller bugs that do not hurt.<br />
We are optimistic that these are done till Friday, otherwise the open tickets will be moved to Release 1.1.</p>
<p>In addition to numerous changes and new features, the REST support is certainly one of the most interesting innovation. The feature was not originally planned for 1.0, but it is cool nowadays. </p>
<p><strong>But what do we understand as "REST support"?</strong></p>
<p>Every server-side action, and every object that is available via a Life-Cycle object, are accessible via REST calls. Don't worry about security, because the same access checks are done as for common applications. If an action or object is available for an application, it is available via REST calls.<br />
You don't need additional configurations for your applications, actions or objects - no annotations and no config files are needed.</p>
<p><strong>It sounds simple? Yes, it is so simple!</strong></p>
<p>I want to show you a short example, based on <a href="http://www.restlet.org/">Restlet</a>. We have a life-cycle object like the following:</p>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;"><span class="kw1">public</span> <span class="kw1">class</span> Address <span class="kw1">extends</span> Session<br />
<span class="br0">&#123;</span><br />
&nbsp; <span class="kw1">public</span> DBStorage getAddress<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="kw1">throws</span> <span class="kw3">Throwable</span><br />
&nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; DBStorage dbs <span class="sy0">=</span> <span class="br0">&#40;</span>DBStorage<span class="br0">&#41;</span>get<span class="br0">&#40;</span><span class="st0">&quot;address&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>dbs <span class="sy0">==</span> <span class="kw2">null</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; dbs <span class="sy0">=</span> <span class="kw1">new</span> DBStorage<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; dbs.<span class="me1">setDBAccess</span><span class="br0">&#40;</span>getDBAccess<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; dbs.<span class="me1">setWritebackTable</span><span class="br0">&#40;</span><span class="st0">&quot;ADDRESS&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; dbs.<span class="me1">open</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; put<span class="br0">&#40;</span><span class="st0">&quot;address&quot;</span>, dbs<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw1">return</span> dbs<span class="sy0">;</span><br />
&nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; <span class="kw1">public</span> <span class="kw3">String</span> getData<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="st0">&quot;Text data&quot;</span><span class="sy0">;</span><br />
&nbsp; <span class="br0">&#125;</span></p>
<p><span class="br0">&#125;</span></div>
</div>
<p>The object has one action "<strong>getData</strong>" and the object "<strong>address</strong>".</p>
<p>Now we <strong>call the action</strong>:</p>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;"><span class="kw3">String</span> sHost <span class="sy0">=</span> <span class="st0">&quot;http://localhost/jvx/services/rest/demo/Address/action/getData&quot;</span><span class="sy0">;</span></p>
<p>ClientResource cres <span class="sy0">=</span> <span class="kw1">new</span> ClientResource<span class="br0">&#40;</span>sHost<span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>Representation rep <span class="sy0">=</span> cres.<span class="me1">get</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p><span class="kw3">String</span> sData <span class="sy0">=</span> JSONUtil.<span class="me1">getObject</span><span class="br0">&#40;</span>rep, <span class="kw3">String</span>.<span class="kw1">class</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
<p>And we <strong>fetch all records</strong>:</p>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;"><span class="kw3">String</span> sHost <span class="sy0">=</span> <span class="st0">&quot;http://localhost/jvx/services/rest/demo/Address/data/address&quot;</span><span class="sy0">;</span></p>
<p>ClientResource cres <span class="sy0">=</span> <span class="kw1">new</span> ClientResource<span class="br0">&#40;</span>sHost<span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>Representation rep <span class="sy0">=</span> cres.<span class="me1">get</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p><span class="kw3">List</span> liRecords <span class="sy0">=</span> JSONUtil.<span class="me1">getObject</span><span class="br0">&#40;</span>rep, <span class="kw3">List</span>.<span class="kw1">class</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
<p>Is it as simple as expected? We hope so <img src='https://blog.sibvisions.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>Of course, there are options for fetching only specific records. Insert new records, update and delete one or more records. All options are implemented in test cases. Have a look at the <a href="http://jvx.svn.sourceforge.net/viewvc/jvx/trunk/java/library/test/com/sibvisions/rad/server/http/rest/TestCallServerResource.java?revision=3758&#038;view=markup">Action</a> or <a href="http://jvx.svn.sourceforge.net/viewvc/jvx/trunk/java/library/test/com/sibvisions/rad/server/http/rest/TestAbstractStorageServerResource.java?revision=3758&#038;view=markup">Storage</a> tests. </p>
<p>More details and the documentation will follow after the release of JVx 1.0.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.sibvisions.com/2011/12/14/jvx-1-0-with-rest-support/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
