{"id":4398,"date":"2019-01-17T18:35:26","date_gmt":"2019-01-17T17:35:26","guid":{"rendered":"https:\/\/blog.mi.hdm-stuttgart.de\/?p=4398"},"modified":"2023-06-09T12:06:40","modified_gmt":"2023-06-09T10:06:40","slug":"radcup-part-1-refactoring","status":"publish","type":"post","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2019\/01\/17\/radcup-part-1-refactoring\/","title":{"rendered":"Radcup Part 1 &#8211; Refactoring"},"content":{"rendered":"\n<p>Written by: Immanuel Haag, Christian M\u00fcller, Marc R\u00fcttler<\/p>\n\n\n\n<p>Refactoring the Radcup backend is necessary because it was developed in the year 2015.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: Docker-Setup <\/h2>\n\n\n\n<p>In order to have a complete project setup, the backend was converted to a Docker-Compose setup. This offers the developers the possibility to always work with a fresh installation within the same environment. It also fixed software-dependencies on different operating systems. For more advantages of a setup like this, please consider the official <a href=\"https:\/\/docs.docker.com\/compose\/overview\/\">docker documentation<\/a>. <br><\/p>\n\n\n<p><em>Note: you need the below mentioned files in the directory so that the docker-compose setup can run! If you want access to our repository please contact us.&nbsp;<\/em><\/p>\n\n\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\">bash-3.2$ <span class=\"hljs-built_in\" style=\"color: rgb(221, 136, 136);\">pwd<\/span>\n\/tmp\/radcup_localdevexample\n\n<span class=\"hljs-comment\" style=\"color: rgb(119, 119, 119);\">#we use the tool tree-cli, with which you can see the directory structure of our project:<\/span>\nbash-3.2$ tree\n.\n\u251c\u2500\u2500 Dockerfile\n\u251c\u2500\u2500 docker-compose.yml\n\u251c\u2500\u2500 importer\n\u2502   \u251c\u2500\u2500 Dockerfile\n\u2502   \u2514\u2500\u2500 radcupDevSample.json\n\u2502       \u2514\u2500\u2500 radcupDevelopment\n\u2502           \u251c\u2500\u2500 games.bson\n\u2502           \u251c\u2500\u2500 games.metadata.json\n\u2502           \u251c\u2500\u2500 system.indexes.bson\n\u2502           \u251c\u2500\u2500 users.bson\n\u2502           \u2514\u2500\u2500 users.metadata.json\n\u2514\u2500\u2500 src\n    \u251c\u2500\u2500 README.md\n    \u251c\u2500\u2500 config.js\n    \u251c\u2500\u2500 controllers\n    \u2502   \u251c\u2500\u2500 auth.js\n    \u2502   \u251c\u2500\u2500 game.js\n    \u2502   \u2514\u2500\u2500 user.js\n<span class=\"hljs-comment\" style=\"color: rgb(119, 119, 119);\">#--------------SNIP--------------------<\/span>\n<span class=\"hljs-comment\" style=\"color: rgb(119, 119, 119);\"># the src directory contains all necessary files of the node.js backend<\/span>\n\nThe content of the individual files (Dockerfile, docker-compose.yml, ...)\nis described in the following blogpost.<\/pre>\n<p> If you want to start the setup run this cli command: <\/p>\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\">docker-compose up --build<\/pre>\n\n\n\n<p>At this point you can see the details of the individual files:<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">1. Docker-Compose.yml:<br><\/h4>\n\n\n\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\"><span class=\"hljs-attr\">db:<\/span> <span class=\"hljs-comment\" style=\"color: rgb(119, 119, 119);\">#this is our db-container which uses the default MongoDB Image from Dockerhub<\/span>\n<span class=\"hljs-attr\">  image:<\/span> mongo\n<span class=\"hljs-attr\">  ports:<\/span>\n<span class=\"hljs-bullet\" style=\"color: rgb(221, 136, 136);\">   -<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"27017:27017\"<\/span>  <span class=\"hljs-comment\" style=\"color: rgb(119, 119, 119);\">#default exposed mongod ports<\/span>\n<span class=\"hljs-attr\">mongo-importer:<\/span>\n<span class=\"hljs-attr\">  build:<\/span> .\/importer <span class=\"hljs-comment\" style=\"color: rgb(119, 119, 119);\">#change directory to importer folder and build this dockerfile (see below for this file) <\/span>\n<span class=\"hljs-attr\">  links:<\/span> <span class=\"hljs-comment\" style=\"color: rgb(119, 119, 119);\">#because the importer-container needs access to the db we have to link it<\/span>\n<span class=\"hljs-bullet\" style=\"color: rgb(221, 136, 136);\">  -<\/span> db\n<span class=\"hljs-attr\">web:<\/span> <span class=\"hljs-comment\" style=\"color: rgb(119, 119, 119);\">#builds the radcup backend dockerfile (see below for this file) <\/span>\n<span class=\"hljs-attr\">  build:<\/span> .\n<span class=\"hljs-attr\">  links:<\/span> <span class=\"hljs-comment\" style=\"color: rgb(119, 119, 119);\">#because the container needs access to the db we have to link it<\/span>\n<span class=\"hljs-bullet\" style=\"color: rgb(221, 136, 136);\">   -<\/span> db\n<span class=\"hljs-attr\">  ports:<\/span>\n<span class=\"hljs-bullet\" style=\"color: rgb(221, 136, 136);\">   -<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"3000:3000\"<\/span> <span class=\"hljs-comment\" style=\"color: rgb(119, 119, 119);\">#exposed api ports<\/span>\n<span class=\"hljs-attr\">  environment:<\/span>\n<span class=\"hljs-attr\">   NODE_ENV:<\/span> development <span class=\"hljs-comment\" style=\"color: rgb(119, 119, 119);\">#define the environment <\/span>\n<span class=\"hljs-attr\">  command:<\/span> [<span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"npm\"<\/span>, <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"start\"<\/span>] <span class=\"hljs-comment\" style=\"color: rgb(119, 119, 119);\">#define the command which has to be executed in the container<\/span>\n<\/pre> \n<p>If you want to run the testsuite within a container you can adjust the command and nodeenv as follows:<\/p>\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\"><span class=\"hljs-attr\">NODE_ENV:<\/span> test\n<span class=\"hljs-attr\">command:<\/span> [<span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"npm\"<\/span>, <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"test\"<\/span>, <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"--exit\"<\/span> ]<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">2.1 mongo-importer Dockerfile:<br><\/h4>\n\n\n\n<p>Previously a mongodump was generated into the radcupDevSample.json folder so that some testdata is available. This dump is used by the mongo-importer container which migrates the testdata into the mongodb container of each developer.<\/p>\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\"><span class=\"hljs-keyword\" style=\"color: rgb(255, 255, 255); font-weight: 700;\">FROM<\/span> mongo\n<span class=\"hljs-keyword\" style=\"color: rgb(255, 255, 255); font-weight: 700;\">COPY<\/span> <span class=\"bash\">radcupDevSample.json \/radcupDevSample.json\n<\/span><span class=\"hljs-keyword\" style=\"color: rgb(255, 255, 255); font-weight: 700;\">CMD<\/span> <span class=\"bash\">mongorestore -h db \/radcupDevSample.json &amp;&amp;\\\nmongo db\/radcupDevelopment --eval <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"db.createUser({user: 'root', pwd: 'toor', roles:[ { role:'readWrite',db: 'dbAdmin'} ]  } ) ;\"<\/span> &amp;&amp;\\ \n<\/span>mongo db\/radcupProduction --eval <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"db.createUser({user: 'root', pwd: 'toor', roles:[ { role:'readWrite',db: 'dbAdmin'} ]  } ) ;\" <\/span> &amp;&amp;\\\nmongo db\/radcupTest --eval <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"db.createUser({user: 'root', pwd: 'toor', roles:[ { role:'readWrite',db: 'dbAdmin'} ]  } ) ;\"<\/span> <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">2.2 Web-Dockerfile:<br><\/h4>\n\n\n\n<p>This Dockerfile represents our Backend:<\/p>\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\"><span class=\"hljs-keyword\" style=\"color: rgb(255, 255, 255); font-weight: 700;\">FROM<\/span> node:jessie <span class=\"hljs-comment\" style=\"color: rgb(119, 119, 119);\">#use node, based on a Debian jessie image<\/span>\nCOPY . \/home\/app <span class=\"hljs-comment\" style=\"color: rgb(119, 119, 119);\">#copy the backend source files to \/home\/app<\/span>\nWORKDIR \/home\/app\/src <span class=\"hljs-comment\" style=\"color: rgb(119, 119, 119);\">#set the default workdirectory for the container<\/span>\nRUN npm install <span class=\"hljs-comment\" style=\"color: rgb(119, 119, 119);\">#install dependencies with nom<\/span>\n<span class=\"hljs-keyword\" style=\"color: rgb(255, 255, 255); font-weight: 700;\">USER<\/span> node <span class=\"hljs-comment\" style=\"color: rgb(119, 119, 119);\">#set the execution user to node! (This is a important security feature - if you do not do this the app-process is executed as root user! <\/span>\n<span class=\"hljs-keyword\" style=\"color: rgb(255, 255, 255); font-weight: 700;\">EXPOSE<\/span> <span class=\"hljs-number\">3000<\/span> <span class=\"hljs-comment\" style=\"color: rgb(119, 119, 119);\">#expose the api port <\/span><\/pre>\n\n\n<p>Watch the cli-output of docker-compose on your machine. After all necessary images have been downloaded and built, &nbsp;you can access the backend within the web-container. Open a browser tab and enter:<\/p>\n<p style=\"text-align: center;\"><a href=\"http:\/\/localhost:3000\/api\">http:\/\/localhost:3000\/api<\/a><\/p>\n<p>You should see a JSON Object with this content:<\/p>\n<p style=\"text-align: left; padding-left: 60px;\">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&#8220;message&#8221;:&#8221;this will be a beerpong app&#8221;}<\/p>\n<p><\/p>\n<p style=\"text-align: left;\">Finding:<\/p>\n<p style=\"text-align: left;\">Now all developers can use this nice setup in a few minutes and can now focus fully on the business logic development. We have also created a good basis for deploying the backend via the docker containers into the cloud and making it available accordingly.<\/p>\n\n\n<h4 class=\"wp-block-heading\">Frontend<br><\/h4>\n\n\n\n<p>As mentioned above, there is an ionic-hybrid app which can be linked to the radcup-backend. Since we didn&#8217;t want to install ionic and cordova, etc. on our local devices. We decided to move the frontend application to a docker-compose container setup, too. However, since our focus in this project is on the backend, the frontend is not discussed further at this point.<\/p>\n\n\n\n<h3 id=\"mce_21\" class=\"editor-rich-text__tinymce mce-content-body wp-block-heading\">Docker under Windows 10<\/h3>\n\n\n\n<p>Under Windows 10 docker required \u201cLinux Containers\u201d not \u201cWindows Containers\u201d. This can be easily changed at any time in the Docker settings. At this point we had the problem that the error message was misleading when using Docker<strong> <\/strong> containers. The error message said that the version number was incorrect, which lead us onto the wrong track. To solve the issue only changing the containers to \u201cLinux Containers\u201d did the trick.<\/p>\n\n\n\n<p>Docker also needs the Windows feature \u201cHyper-V\u201d. But if it is not installed, docker prompts one with an expressive error message.<br>Every time the runtime environment is started, docker needs access to the &#8220;Windows Hosts Files&#8221;. However, antivirus software can block this access, depending on your settings. Unfortunately, the solution seems to be to change the antivirus software settings.<br><\/p>\n\n\n\n<p>The Docker environment also needs a shared drive for the docker processes. Fortunately, Docker does this automatically and sets the permissions to the currently logged in Windows user account.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: Dependency Update<\/h2>\n\n\n\n<p>Since the backend, as mentioned before, was developed a long time ago, it was necessary to perform a dependency check. On the one hand to identify the partially obsolete or unneeded dependencies and on the other hand to remove warnings.<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p>Because a manual check of the entries, is very time-consuming, a tool was needed which carries out the analysis. For this reason, various tools were evaluated and tested.\nIn the end, our choice was <a href=\"https:\/\/www.npmjs.com\/package\/npm-check\"><code class=\"\" data-line=\"\">npm-check<\/code><\/a>.<\/p>\n<p>The following command is sufficient to install it (prerequisite: npm is installed):<\/p>\n<\/div>\n\n\n\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\">npm install -g npm-check<\/pre>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p>After the installation, you have to navigate to the directory where the <code class=\"\" data-line=\"\">package.json<\/code> is located. If the command <code class=\"\" data-line=\"\">npm-check<\/code> is executed, the file and its dependencies will be analyzed.<\/p>\n<p>Example Output:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/npm-check.png\" alt=\"npm-check Output\"><\/p>\n<p>By analyzing the dependencies, some updates were performed, some even security relevant, and several dependencies were removed.<\/p>\n<p>Before the analysis:<\/p>\n<\/div>\n\n\n\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\">Step 4\/6 : RUN npm install\n---&gt; Running in 24e38874f36f\n\n&gt; nodemon@1.18.7 postinstall \/home\/app\/src\/node_modules\/nodemon\n&gt; node bin\/postinstall || <span class=\"hljs-built_in\" style=\"color: rgb(221, 136, 136);\">exit<\/span> 0\n\nLove nodemon? You can now support the project via the open collective:\n&gt; https:\/\/opencollective.com\/nodemon\/donate\n\nnpm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules\/fsevents):\nnpm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.4: wanted {<span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"os\"<\/span>:<span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"darwin\"<\/span>,<span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"arch\"<\/span>:<span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"any\"<\/span>} (current: {<span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"os\"<\/span>:<span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"linux\"<\/span>,<span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"arch\"<\/span>:<span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"x64\"<\/span>})\n\nadded 356 packages from 616 contributors and audited 2535 packages in 15.28s\nfound 0 vulnerabilities<\/pre>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p>After the analysis:<\/p>\n<\/div>\n\n\n\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\">Step 4\/6 : RUN npm install\n---&gt; Running in 9fb8e1bf3f43\nadded 141 packages from 498 contributors and audited 283 packages in 6.056s<\/pre>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p>As you can see from the two outputs, analyzing the dependencies has helped a lot. For example, the number of packages has been reduced and the warnings were removed.<\/p>\n<\/div>\n\n\n\n<p>Finding:<\/p>\n\n\n\n<p>In the middle of the project there was a problem with the npm package <a href=\"https:\/\/www.zdnet.com\/article\/hacker-backdoors-popular-javascript-library-to-steal-bitcoin-funds\/\">&#8216;event-stream<\/a>&#8216;, this distributed malware and tries<strong> <\/strong>to steal from users of the Bitcoin Wallet Copay. <br>As a result, npm-install stopped running and the affected package had to be updated to a newer version without malware.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: Testsuite improvements<\/h2>\n\n\n\n<h4 class=\"wp-block-heading\">Our test setup<\/h4>\n\n\n\n<p>Our testing framework is Mocha. If started it will per default run all <em>.js<\/em> files \/ tests defined in the test folder of the application.<br>(<a href=\"https:\/\/mochajs.org\/\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\" (opens in a new tab)\">Documentation<\/a>)<a href=\"https:\/\/www.npmjs.com\/package\/npm-check\"><\/a><br>Here is one example of a test, the shortened version of the game tests:<\/p>\n\n\n\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\">[...]\n<span class=\"hljs-comment\" style=\"color: rgb(119, 119, 119);\">\/* Game Testsuite *\/<\/span>\ndescribe(<span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">'Games API Testsuite.'<\/span>, <span class=\"hljs-function\"><span class=\"hljs-keyword\" style=\"color: rgb(255, 255, 255); font-weight: 700;\">function<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  [...]\n  it(<span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">'should create a game'<\/span>, <span class=\"hljs-function\"><span class=\"hljs-keyword\" style=\"color: rgb(255, 255, 255); font-weight: 700;\">function<\/span>(<span class=\"hljs-params\">done<\/span>) <\/span>{\n    request(server.app)\n      .post(<span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">'\/api\/games'<\/span>)\n      .auth(user.email, user.password)\n      .send( game )\n      .end(<span class=\"hljs-function\"><span class=\"hljs-keyword\" style=\"color: rgb(255, 255, 255); font-weight: 700;\">function<\/span>(<span class=\"hljs-params\">err, res<\/span>)<\/span>{\n        expect(err).to.eql(<span class=\"hljs-literal\" style=\"color: rgb(255, 255, 255); font-weight: 700;\">null<\/span>);\n        expect(res.status).to.eql(<span class=\"hljs-number\">200<\/span>);\n        expect(res.body.desc).to.eql(game.desc);\n        expect(res.body.results.winner).to.eql(<span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">'No Winner'<\/span>);\n        expect(res.body.results.endTime).to.eql(<span class=\"hljs-literal\" style=\"color: rgb(255, 255, 255); font-weight: 700;\">null<\/span>);\n        expect(res.body.players.one).to.eql(user.username);\n        done();\n      });\n  });\n  [...]\n});<\/pre>\n\n\n\n<p>In the above example you can see a test which checks if a game can be created. The result of the call is checked.<\/p>\n\n\n\n<p>The following code shows a section of our package.json:<\/p>\n\n\n\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\">{\n  <span class=\"hljs-attr\">\"name\"<\/span>: <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"radcup\"<\/span>,\n  <span class=\"hljs-attr\">\"version\"<\/span>: <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"1.1.1\"<\/span>,\n  <span class=\"hljs-attr\">\"private\"<\/span>: <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">true<\/span>,\n  <span class=\"hljs-attr\">\"scripts\"<\/span>: {\n    <span class=\"hljs-attr\">\"start\"<\/span>: <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"node radcup\"<\/span>,\n    <span class=\"hljs-attr\">\"test\"<\/span>: <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"NODE_ENV=test nyc .\/node_modules\/.bin\/mocha --exit --timeout 3000; nyc report --reporter=text-summary; nyc check-coverage --branches 20 --functions 60 --lines 50; jshint '.\/' --verbose\"<\/span>\n    \"testfromclusterandrun\": <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\".\/node_modules\/.bin\/mocha --exit --timeout 3000; NODE_ENV=prodDBatlas node radcup\"<\/span>\n  },\n[...]<\/pre>\n\n\n\n<p>The file contains three script sections &#8220;start&#8221;, &#8220;test&#8221; and &#8220;testfromclusterandrun&#8221;. These define how the application can be started. If &#8220;test&#8221; is selected, the corresponding test is started. <br>We use the nyc package to handle mocha. &#8220;testfromclusterandrun&#8221; is used to start the application on the cluster. Before that a test is started, to see if everything works on the cluster.<\/p>\n\n\n\n<p>(<a href=\"https:\/\/www.npmjs.com\/package\/nyc\">NYC Documentation<\/a>)<br>(<a href=\"https:\/\/istanbul.js.org\/docs\/tutorials\/mocha\/\">NYC with Mocha<\/a>)<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p><code class=\"\" data-line=\"\">NODE_ENV=test<\/code>: This variable has to be set to <code class=\"\" data-line=\"\">test<\/code> for the integrated <code class=\"\" data-line=\"\">babel-plugin-istanbul<\/code> of the NYC package to work. This is required so that NYC fully works with Mocha.<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p><code class=\"\" data-line=\"\">nyc .\/node_modules\/.bin\/mocha --exit --timeout 3000;<\/code> starts the mocha framework and therefore the test. The exit command is necessary because otherwise this command will not return. We also defined a time-out in case it still doesn&#8217;t return, for example if the tests have an issue. The other commands will be explained in further detail, in the following sections.<\/p>\n<\/div>\n\n\n\n<h4 class=\"wp-block-heading\">How to check Code Coverage?<\/h4>\n\n\n\n<p>The Code Coverage can also be tested within the CI-pipeline and depending on the result can cause the test pipeline to fail. To let the test pipeline, fail if a certain threshold is reached, the following command is required. The command was added to the test script in the package.json.<\/p>\n\n\n\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\">nyc check-coverage --branches 20 --functions 60 --lines 50;<\/pre>\n\n\n\n<p>(<a href=\"https:\/\/www.npmjs.com\/package\/nyc#user-content-checking-coverage\ufeff\">Documentation<\/a>)<br><\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p>With the shown parameters the command checks several coverage types:\n<code class=\"\" data-line=\"\">branches &gt;= 20%, functions &gt;= 60%, lines &gt;= 50%<\/code><\/p>\n<\/div>\n\n\n\n<p>The following picture shows the results of each coverage type and shows that the pipeline fails if the threshold is not met. To show this, the branches threshold was set to 100%:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"546\" height=\"318\" data-attachment-id=\"4955\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2019\/01\/17\/radcup-part-1-refactoring\/tests\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/tests.png\" data-orig-size=\"546,318\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"tests\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/tests.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/tests.png\" alt=\"\" class=\"wp-image-4955\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/tests.png 546w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/tests-300x175.png 300w\" sizes=\"auto, (max-width: 546px) 100vw, 546px\" \/><\/figure>\n\n\n\n<p>In the table an additional type Stmts can be seen. This stands for Statements, but the coverage of this type can&#8217;t be tested.<br><\/p>\n\n\n\n<p>We also added the following command to get a more precise coverage info as overview:<\/p>\n\n\n\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\">nyc report --reporter=text-summary;<\/pre>\n\n\n\n<p>(<a href=\"https:\/\/www.npmjs.com\/package\/nyc#running-reports\ufeff\">Documentation<\/a>)<\/p>\n\n\n\n<p>The following picture shows an additional summary of the results after the table, which can already be seen in the previous picture. This run also ran successfully.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"546\" height=\"408\" data-attachment-id=\"4957\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2019\/01\/17\/radcup-part-1-refactoring\/summary\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/summary.png\" data-orig-size=\"546,408\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"summary\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/summary.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/summary.png\" alt=\"\" class=\"wp-image-4957\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/summary.png 546w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/summary-300x224.png 300w\" sizes=\"auto, (max-width: 546px) 100vw, 546px\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">How to test the javascript implementation?<\/h4>\n\n\n\n<p>We searched a test that will cause the pipeline to fail (return non-zero) if the javascript implementation, has any errors or warnings. To test the implementation the following command has to be added to the test script in the package.json. Also, the jshint npm package has to be installed and therefore we added a reference to the package.json<\/p>\n\n\n\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\">jshint <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">'.\/'<\/span> --verbose;<\/pre>\n\n\n\n<p>(<a href=\"https:\/\/jshint.com\/docs\/cli\/\">Documentation<\/a>)<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p>As one can see <code class=\"\" data-line=\"\">&#039;.\/&#039;<\/code> the command references the folder where it is started from, in our case this is the &quot;src&quot; folder of our project.<\/p>\n<\/div>\n\n\n\n<p>The following picture shows an example of found errors:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"862\" height=\"179\" data-attachment-id=\"4958\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2019\/01\/17\/radcup-part-1-refactoring\/jshint-error\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/jshint-error.png\" data-orig-size=\"862,179\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"jshint error\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/jshint-error.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/jshint-error.png\" alt=\"\" class=\"wp-image-4958\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/jshint-error.png 862w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/jshint-error-300x62.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/jshint-error-768x159.png 768w\" sizes=\"auto, (max-width: 862px) 100vw, 862px\" \/><\/figure>\n\n\n\n<p> At first jshint seemed to run into an endless loop. Because of the npm installation a folder &#8220;node_modules&#8221; was added that we forgot. And testing this folder just took way more time.<br><\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p>Of course, we didn&#8217;t want to let jshint test this folder, especially because we can&#8217;t really correct errors\/warnings in it and also because it isn&#8217;t in the scope of our project.\nBut we also didn&#8217;t want to leave it at just testing specified files, because we of course don&#8217;t want to reference each file here, that will be added to the project.\nTo solve this issue one can add a file named <code class=\"\" data-line=\"\">.jshintignore<\/code>, in the directory the jshint command will be executed (the src folder in our case). In the file one can specify which files\/folders should be ignored. Those exceptions will be interpreted using the minimatch npm module. Also, the <code class=\"\" data-line=\"\">--exclude-path<\/code> flag needs to be added once, above those path patterns. Here one can see an example:<\/p>\n<\/div>\n\n\n\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\">--exclude-path\n.\/node_modules<\/pre>\n\n\n\n<p>If there is a warning which can&#8217;t be solved it can be marked, in the code, so that it will be ignored as follows:<\/p>\n\n\n\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\">\/* jshint ignore:start *\/\n\/\/ code over several lines (for example a function) that causes a warning\n\/* jshint ignore:end *\/<\/pre>\n\n\n\n<p>As a short side node, everything that is in between those ignore comments is completely ignored, which means if one for example splits a several lines long command with those comments, jshint will see the part outside of the comment as incomplete.<\/p>\n\n\n\n<p>A Single line could also be ignored like this:<\/p>\n\n\n\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\">oneLineOfCode(); \/\/ jshint ignore:line<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4: Swagger integration<\/h2>\n\n\n\n<h4 class=\"wp-block-heading\">What is Swagger?<\/h4>\n\n\n\n<p>In short <a href=\"https:\/\/swagger.io\/\ufeff\">Swagger<\/a> can be used to design and document an API. We already had an API and therefore we only needed to document it.<\/p>\n\n\n\n<p>Swagger documents APIs and while doing this it is also an interactive tool to try out the API, so one can see for himself how the API works.<\/p>\n\n\n\n<ul class=\"wp-block-gallery columns-1 is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex\"><li class=\"blocks-gallery-item\"><figure><img loading=\"lazy\" decoding=\"async\" width=\"2495\" height=\"2296\" data-attachment-id=\"5051\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2019\/01\/17\/radcup-part-1-refactoring\/user-by-mail-executed\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/user-by-mail-executed.png\" data-orig-size=\"2495,2296\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"user by mail executed\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/user-by-mail-executed-1024x942.png\" src=\"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/user-by-mail-executed.png?fit=656%2C603&amp;ssl=1\" alt=\"\" data-id=\"5051\" data-link=\"https:\/\/blog.mi.hdm-stuttgart.de\/?attachment_id=5051\" class=\"wp-image-5051\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/user-by-mail-executed.png 2495w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/user-by-mail-executed-300x276.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/user-by-mail-executed-768x707.png 768w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/user-by-mail-executed-1024x942.png 1024w\" sizes=\"auto, (max-width: 2495px) 100vw, 2495px\" \/><\/figure><\/li><\/ul>\n\n\n\n<p>In this picture one can see a GET-API request which will return a user if given a correct email. This information can be seen and read quickly from the developer who accesses the swagger UI. Also, you can see that this GET call has a required parameter, the email address. An email address can be inserted and the call can be executed. Then you can see the request URL that was used to perform this API call. Also, the return object can be compared to an example value. This example value is also accessible if the request was not sent which means one does not have to execute it.<\/p>\n\n\n\n<p>Whilst trying out the API we also found a security issue with our API. Any logged in user can access any API path, which means any user can access, alter and delete any data.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Swagger setup<\/h4>\n\n\n\n<p>For the first setup, we found this <a href=\"https:\/\/blog.cloudboost.io\/adding-swagger-to-existing-node-js-project-92a6624b855b\">tutorial<\/a>, very helpful.<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p>We decided to use <a href=\"https:\/\/www.npmjs.com\/package\/swagger-ui-express\">Swagger-UI-Express<\/a>, because it is actively supported.              In the \u201epackage.json\u201c file one must only add the following line to the <code class=\"\" data-line=\"\">dependencies<\/code>:<\/p>\n<\/div>\n\n\n\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\">\"swagger-ui-express\": <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"^4.0.1\"<\/span><\/pre>\n\n\n\n<p>At the time of this project the current version of the Swagger UI was 4.0.1. With this line NPM will also install the Swagger UI into the Docker image.<\/p>\n\n\n\n<p>In the \u201eserver.js\u201c file, the following lines have to be added:<br><\/p>\n\n\n\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\"><span class=\"hljs-keyword\" style=\"color: rgb(255, 255, 255); font-weight: 700;\">var<\/span> swaggerUi = <span class=\"hljs-built_in\" style=\"color: rgb(221, 136, 136);\">require<\/span>(<span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">'swagger-ui-express'<\/span>);\n<span class=\"hljs-keyword\" style=\"color: rgb(255, 255, 255); font-weight: 700;\">var<\/span> swaggerDocument = <span class=\"hljs-built_in\" style=\"color: rgb(221, 136, 136);\">require<\/span>(<span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">'.\/swagger.json'<\/span>);<\/pre>\n\n\n\n<p>In the same folder as the previous two files, one more file has to be added, the &#8220;swagger.json&#8221; file. It defines the documentation which will be displayed on the swagger website. For a &#8220;how to&#8221; see the next topic &#8220;swagger.json&#8221; below, but for the moment a simple example json suffices.<\/p>\n\n\n\n<p>After building and starting the Docker image we were able to access the Swagger website under <a href=\"http:\/\/127.0.0.1:3000\/api-docs\"><a href=\"http:\/\/127.0.0.1:3000\/api-docs\">http:\/\/127.0.0.1:3000\/api-docs<\/a><\/a>. (We were testing this on a local computer, hence the call to localhost.)<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">swagger.json<\/h4>\n\n\n\n<p><strong>Useful links<\/strong><\/p>\n\n\n\n<p>To create a swagger.json we found the following links helpful:<\/p>\n\n\n\n<p>A short and easy <a href=\"https:\/\/apihandyman.io\/writing-openapi-swagger-specification-tutorial-part-1-introduction\/\">introduction<\/a>.<a href=\"https:\/\/apihandyman.io\/writing-openapi-swagger-specification-tutorial-part-1-introduction\/\"><\/a><\/p>\n\n\n\n<p>The official <a href=\"https:\/\/editor.swagger.io\/\">Swagger Editor<\/a> (optional).<br>(This website comes with an detailed example <em>Petstore<\/em>. This example can be downloaded as an swagger.yaml or swagger.json.)<\/p>\n\n\n\n<p>Detailed <a href=\"https:\/\/swagger.io\/docs\/specification\/about\/\">introduction<\/a> into the creation of a &#8220;swagger.json&#8221;.<a href=\"https:\/\/swagger.io\/docs\/specification\/about\/\"><\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/OAI\/OpenAPI-Specification\/tree\/master\/versions\">OpenAPI-Specification<\/a>.<a href=\"https:\/\/github.com\/OAI\/OpenAPI-Specification\/tree\/master\/versions\"><\/a><\/p>\n\n\n\n<p><strong>Building a swagger.json\/yml<\/strong><\/p>\n\n\n\n<p>We developed a swagger.yml and then converted it into a swagger.json, because the swagger.yml syntax is easier to use.<\/p>\n\n\n\n<p>We tried to use the swagger.yml directly without the swagger.json but we weren&#8217;t able to get it working. If we used the .yml-file in the required command, the .yml-file would be loaded, but the internal parser would throw weird errors. Even though the .yml-file was written according to specification and the swagger editor wouldn&#8217;t throw any errors or warnings.<\/p>\n\n\n\n<p>The structure of a swagger.yml(\/.json) can be divided into three parts. The first contains general info about the swagger file and API. The second part contains the API paths itself. And the last part contains the models which are used by the API.<\/p>\n\n\n\n<p>In the following sections we will introduce those three parts and will provide a short overview over each part.<\/p>\n\n\n\n<p><strong>swagger.yml part one:<\/strong><\/p>\n\n\n\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\"><span class=\"hljs-attr\">swagger:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"2.0\"<\/span>\n<span class=\"hljs-attr\">info:<\/span>\n<span class=\"hljs-attr\">  version:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"1.1.1\"<\/span>\n<span class=\"hljs-attr\">  title:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"radcup\"<\/span>\n<span class=\"hljs-attr\">  description:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"radcup backend API\"<\/span>\n<span class=\"hljs-attr\">host:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"159.122.181.248:30304\"<\/span>\n<span class=\"hljs-attr\">basePath:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"\/api\"<\/span>\n<span class=\"hljs-attr\">tags:<\/span>\n<span class=\"hljs-attr\">- name:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"Game\"<\/span>\n<span class=\"hljs-attr\">  description:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"API for games in the system\"<\/span>\n<span class=\"hljs-attr\">- name:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"Statistic\"<\/span>\n<span class=\"hljs-attr\">  description:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"API for statistics in the system\"<\/span>\n<span class=\"hljs-attr\">- name:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"User\"<\/span>\n<span class=\"hljs-attr\">  description:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"API for users in the system\"<\/span>\n<span class=\"hljs-attr\">schemes:<\/span>\n<span class=\"hljs-bullet\" style=\"color: rgb(221, 136, 136);\">-<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"http\"<\/span>\n<span class=\"hljs-attr\">consumes:<\/span>\n<span class=\"hljs-bullet\" style=\"color: rgb(221, 136, 136);\">-<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"application\/json\"<\/span>\n<span class=\"hljs-attr\">produces:<\/span>\n<span class=\"hljs-bullet\" style=\"color: rgb(221, 136, 136);\">-<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"application\/json\"<\/span>\n[...]<\/pre>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p>Under <code class=\"\" data-line=\"\">info<\/code> belongs general information about the API that is in use. <code class=\"\" data-line=\"\">host<\/code> and <code class=\"\" data-line=\"\">basePath<\/code> are used to define the URL for each API call. The <code class=\"\" data-line=\"\">host<\/code> address should of course be set to the address of the server. <code class=\"\" data-line=\"\">tags<\/code> is used to group the API calls and one can also describe each group\/tag.<\/p>\n<\/div>\n\n\n\n<p><strong>swagger.yml part two:<\/strong><\/p>\n\n\n\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\">[...]\n<span class=\"hljs-attr\">paths:<\/span>\n[...]\n  \/games\/{game_id}:\n[...]\n<span class=\"hljs-attr\">    put:<\/span>\n<span class=\"hljs-attr\">      tags:<\/span>\n<span class=\"hljs-bullet\" style=\"color: rgb(221, 136, 136);\">      -<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"Game\"<\/span>\n<span class=\"hljs-attr\">      summary:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"Update an existing game\"<\/span>\n<span class=\"hljs-attr\">      description:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"\"<\/span>\n<span class=\"hljs-attr\">      consumes:<\/span>\n<span class=\"hljs-bullet\" style=\"color: rgb(221, 136, 136);\">      -<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"application\/json\"<\/span>\n<span class=\"hljs-attr\">      produces:<\/span>\n<span class=\"hljs-bullet\" style=\"color: rgb(221, 136, 136);\">      -<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"application\/json\"<\/span>\n<span class=\"hljs-attr\">      parameters:<\/span>\n<span class=\"hljs-attr\">      - name:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"game_id\"<\/span>\n<span class=\"hljs-attr\">        in:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"path\"<\/span>\n<span class=\"hljs-attr\">        description:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"ID of game to put in\"<\/span>\n<span class=\"hljs-attr\">        required:<\/span> <span class=\"hljs-literal\" style=\"color: rgb(255, 255, 255); font-weight: 700;\">true<\/span>\n<span class=\"hljs-attr\">        type:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"string\"<\/span>\n<span class=\"hljs-attr\">      - name:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"game\"<\/span>\n<span class=\"hljs-attr\">        in:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"body\"<\/span>\n<span class=\"hljs-attr\">        description:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"Game object that needs to be updated in the store\"<\/span>\n<span class=\"hljs-attr\">        required:<\/span> <span class=\"hljs-literal\" style=\"color: rgb(255, 255, 255); font-weight: 700;\">true<\/span>\n<span class=\"hljs-attr\">        schema:<\/span>\n          $ref: <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"#\/definitions\/game\"<\/span>\n<span class=\"hljs-attr\">      responses:<\/span>\n        <span class=\"hljs-number\">200<\/span>:\n<span class=\"hljs-attr\">          description:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"\"<\/span>\n<span class=\"hljs-attr\">          schema:<\/span>\n              $ref: <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"#\/definitions\/game\"<\/span>\n\n<span class=\"hljs-attr\">    delete:<\/span>\n<span class=\"hljs-attr\">      tags:<\/span>\n<span class=\"hljs-bullet\" style=\"color: rgb(221, 136, 136);\">      -<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"Game\"<\/span>\n<span class=\"hljs-attr\">      summary:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"Deletes a game\"<\/span>\n<span class=\"hljs-attr\">      description:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"\"<\/span>\n<span class=\"hljs-attr\">      produces:<\/span>\n<span class=\"hljs-bullet\" style=\"color: rgb(221, 136, 136);\">      -<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"application\/json\"<\/span>\n<span class=\"hljs-attr\">      parameters:<\/span>\n<span class=\"hljs-attr\">      - name:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"game_id\"<\/span>\n<span class=\"hljs-attr\">        in:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"path\"<\/span>\n<span class=\"hljs-attr\">        description:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"Game id to delete\"<\/span>\n<span class=\"hljs-attr\">        required:<\/span> <span class=\"hljs-literal\" style=\"color: rgb(255, 255, 255); font-weight: 700;\">true<\/span>\n<span class=\"hljs-attr\">        type:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"string\"<\/span>\n<span class=\"hljs-attr\">      responses:<\/span>\n        <span class=\"hljs-number\">200<\/span>:\n<span class=\"hljs-attr\">          description:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"Deleted game 'game_id'\"<\/span>\n[...]<\/pre>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p>The second part consists of <code class=\"\" data-line=\"\">paths<\/code>, those define each API path. The shown code snippet defines one path <code class=\"\" data-line=\"\">\/games\/{game_id}<\/code> with a PUT and DELETE command. This path has also an in path parameter <code class=\"\" data-line=\"\">{game_id}<\/code>.<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p>The PUT command is sorted under the <code class=\"\" data-line=\"\">Game<\/code> tag and has a short <code class=\"\" data-line=\"\">summary<\/code> and a long <code class=\"\" data-line=\"\">description<\/code> field. It consumes a .json-file and also produces one. It also requires two parameters first an in path id of the game that shall be updated and an in body .json-file of the altered game. With <code class=\"\" data-line=\"\">schema<\/code> the model of a game json can be referenced here. This allows the swagger website to show an example model of the game which is required. Under <code class=\"\" data-line=\"\">responses<\/code> is defined how the responses should look like. In this case the code should be <code class=\"\" data-line=\"\">200<\/code> and the updated game model is expected.<\/p>\n<\/div>\n\n\n\n<p>In comparison to the PUT command, the DELETE command only requires the in path game_id and produces a json file. The response here isn&#8217;t a json file.<\/p>\n\n\n\n<p>Whilst programming this second part, we encountered two problems.<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p>We defined two paths that where similar, <code class=\"\" data-line=\"\">\/users\/{email}:<\/code> with Get and <code class=\"\" data-line=\"\">\/users\/{user_id}:<\/code> with PUT and DELETE. The swagger editor prompted us with an error <strong>&quot;Semantic error [\u2026] Equivalent paths are not allowed.&quot;<\/strong>. We ignored this error because we could still generate the json and the json did run as well. Another workaround we found is to add a comment to the paths <code class=\"\" data-line=\"\">\/users\/{email}#email<\/code>. The following picture shows how this would look like in the UI:<\/p>\n<\/div>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"484\" height=\"294\" data-attachment-id=\"4977\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2019\/01\/17\/radcup-part-1-refactoring\/path-problem-workaround\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/path-problem-workaround.png\" data-orig-size=\"484,294\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"path problem workaround\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/path-problem-workaround.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/path-problem-workaround.png\" alt=\"\" class=\"wp-image-4977\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/path-problem-workaround.png 484w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/path-problem-workaround-300x182.png 300w\" sizes=\"auto, (max-width: 484px) 100vw, 484px\" \/><\/figure>\n\n\n\n<p>To use this solution wasn&#8217;t the nicer solution in our scenario and because of this we did choose the first one.<\/p>\n\n\n\n<p>The other problem we found was that it seems, one can&#8217;t write any symbol combination in a string. We wanted to write &#8220;\\&lt;username&gt;&#8221; in a description property but this letter combination was omitted on the website. The string &#8220;Created user  <br>\\&lt;username&gt; test  test&#8221; for example, resulted in &#8220;Created user  test  test&#8221;. Mind that letters after the letter combination are not cut off and if an underscore is added the letter combination won&#8217;t be omitted. This sequenz can be escaped via the backslash like this &#8220;\\&#8221;.<\/p>\n\n\n\n<p><strong>swagger.yml part three:<\/strong><\/p>\n\n\n\n<pre class=\"hljs\" style=\"display: block; overflow-x: auto; padding: 0.5em; background-color: rgb(68, 68, 68); color: rgb(221, 221, 221);\">[...]\n<span class=\"hljs-attr\">definitions:<\/span>\n<span class=\"hljs-attr\">  game:<\/span>\n<span class=\"hljs-attr\">    type:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"object\"<\/span>\n<span class=\"hljs-attr\">    required:<\/span>\n<span class=\"hljs-bullet\" style=\"color: rgb(221, 136, 136);\">      -<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"_id\"<\/span>\n<span class=\"hljs-attr\">    properties:<\/span>\n<span class=\"hljs-attr\">      players:<\/span>\n        $ref: <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"#\/definitions\/players\"<\/span>\n<span class=\"hljs-attr\">      results:<\/span>\n        $ref: <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"#\/definitions\/results\"<\/span>\n<span class=\"hljs-attr\">      desc:<\/span>\n<span class=\"hljs-attr\">        type:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"string\"<\/span>\n<span class=\"hljs-attr\">      _id:<\/span>\n<span class=\"hljs-attr\">        type:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"string\"<\/span>\n<span class=\"hljs-attr\">        uniqueItems:<\/span> <span class=\"hljs-literal\" style=\"color: rgb(255, 255, 255); font-weight: 700;\">true<\/span>\n<span class=\"hljs-attr\">      time:<\/span>\n<span class=\"hljs-attr\">        type:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"string\"<\/span>\n<span class=\"hljs-attr\">      lng:<\/span>\n<span class=\"hljs-attr\">        type:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"number\"<\/span>\n<span class=\"hljs-attr\">      lat:<\/span>\n<span class=\"hljs-attr\">        type:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"number\"<\/span>\n<span class=\"hljs-attr\">      state:<\/span>\n<span class=\"hljs-attr\">        type:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"string\"<\/span>\n\n<span class=\"hljs-attr\">  games:<\/span>\n<span class=\"hljs-attr\">    type:<\/span> <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"array\"<\/span>\n<span class=\"hljs-attr\">    items:<\/span>\n      $ref: <span class=\"hljs-string\" style=\"color: rgb(221, 136, 136);\">\"#\/definitions\/game\"<\/span>\n[...]<\/pre>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p>In the last part <code class=\"\" data-line=\"\">definitions<\/code>, are all the models defined, that where referenced (<code class=\"\" data-line=\"\">$ref:<\/code>) in the previous part.<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p>The <code class=\"\" data-line=\"\">game<\/code> object is defined with all of it <code class=\"\" data-line=\"\">properties<\/code> and some of those (e.g. <code class=\"\" data-line=\"\">players<\/code>) reference other models as well. The <code class=\"\" data-line=\"\">_id<\/code> property is also defined as unique and referenced under the <code class=\"\" data-line=\"\">required<\/code> section which, as one would assume, defines this property as required.<\/p>\n<p>The <code class=\"\" data-line=\"\">games<\/code> model describes an array of game objects.<\/p>\n<\/div>\n\n\n\n<p>Those models can also be inspected separately on the Swagger page as you can see in the following picture:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"464\" height=\"828\" data-attachment-id=\"4978\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2019\/01\/17\/radcup-part-1-refactoring\/swagger-ui-models-cut\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/swagger-ui-models-cut.png\" data-orig-size=\"464,828\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"swagger ui models-cut\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/swagger-ui-models-cut.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/swagger-ui-models-cut.png\" alt=\"\" class=\"wp-image-4978\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/swagger-ui-models-cut.png 464w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/swagger-ui-models-cut-168x300.png 168w\" sizes=\"auto, (max-width: 464px) 100vw, 464px\" \/><\/figure>\n\n\n\n<p> <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Written by: Immanuel Haag, Christian M\u00fcller, Marc R\u00fcttler Refactoring the Radcup backend is necessary because it was developed in the year 2015.<\/p>\n","protected":false},"author":884,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[651,2],"tags":[206,7,9,3,97,98,145,47,129,205,25,201,208],"ppma_author":[762],"class_list":["post-4398","post","type-post","status-publish","format-standard","hentry","category-system-designs","category-system-engineering","tag-beerpong","tag-cloud","tag-devops","tag-docker","tag-git","tag-gitlab","tag-gitlab-ci","tag-ibm","tag-ibm-bluemix","tag-ionic","tag-nodejs","tag-social-media","tag-swagger-io"],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":4395,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2019\/01\/17\/radcup-a-socialmedia-beerpong-app\/","url_meta":{"origin":4398,"position":0},"title":"Radcup &#8211; a socialmedia beerpong App","author":"Immanuel Haag","date":"17. January 2019","format":false,"excerpt":"Written by: Immanuel Haag, Christian M\u00fcller, Marc R\u00fcttler Radcup adds a bit of social media to the well-known game Beerpong. With Radcup the user has the possibility to register or login. Afterwards he can display\/localize already existing games and join them if possible or create new games. As soon as\u2026","rel":"","context":"In &quot;System Designs&quot;","block_context":{"text":"System Designs","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/system-designs\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/Screen-Shot-2019-01-06-at-15.09.35.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/Screen-Shot-2019-01-06-at-15.09.35.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/Screen-Shot-2019-01-06-at-15.09.35.png?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":4403,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2019\/01\/17\/radcup-part-2-cloud\/","url_meta":{"origin":4398,"position":1},"title":"Radcup Part 2 &#8211; Transition into Cloud","author":"Immanuel Haag","date":"17. January 2019","format":false,"excerpt":"Written by: Immanuel Haag, Christian M\u00fcller, Marc R\u00fcttler Several steps are necessary to transfer the Radcup backend to the cloud and make it accessible to everyone from the outside. These are explained in more detail in the following sections. Step 1: External MongoDB We have decided to use an external\u2026","rel":"","context":"In &quot;System Designs&quot;","block_context":{"text":"System Designs","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/system-designs\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/Screen-Shot-2018-12-29-at-23.56.46.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/Screen-Shot-2018-12-29-at-23.56.46.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/Screen-Shot-2018-12-29-at-23.56.46.png?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":4405,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2019\/01\/04\/radcup-part-3-automation\/","url_meta":{"origin":4398,"position":2},"title":"Radcup Part 3 &#8211; Automation with Gitlab CI\/CD","author":"Immanuel Haag","date":"4. January 2019","format":false,"excerpt":"Written by: Immanuel Haag, Christian M\u00fcller, Marc R\u00fcttler The goal of this blog entry is to automate the previously performed steps. At the end all manual steps should be automated when new code changes are added to the repository. The new version of the backend will be made available in\u2026","rel":"","context":"In &quot;DevOps&quot;","block_context":{"text":"DevOps","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/scalable-systems\/devops\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/Gesamtstruktur-der-Architektur-Kurzform-1.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/Gesamtstruktur-der-Architektur-Kurzform-1.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/Gesamtstruktur-der-Architektur-Kurzform-1.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/Gesamtstruktur-der-Architektur-Kurzform-1.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/01\/Gesamtstruktur-der-Architektur-Kurzform-1.png?resize=1050%2C600&ssl=1 3x"},"classes":[]},{"id":21064,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/","url_meta":{"origin":4398,"position":3},"title":"How do you get a web application into the cloud?","author":"af094","date":"11. September 2021","format":false,"excerpt":"by Dominik Ratzel (dr079) and Alischa Fritzsche (af094) For the lecture \"Software Development for Cloud Computing\", we set ourselves the goal of exploring new things and gaining experience. We focused on one topic: \"How do you get a web application into the cloud?\". In doing so, we took a closer\u2026","rel":"","context":"In &quot;Cloud Technologies&quot;","block_context":{"text":"Cloud Technologies","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/scalable-systems\/cloud-technologies\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/availableRunners-150x118.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":7154,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2019\/08\/31\/setting-up-a-ci-cd-pipeline-in-gitlab\/","url_meta":{"origin":4398,"position":4},"title":"Setting up a CI\/CD pipeline in Gitlab","author":"nr037","date":"31. August 2019","format":false,"excerpt":"Introduction For all my university software projects, I use the HdM Gitlab instance for version control. But Gitlab offers much more such as easy and good ways to operate a pipeline. In this article, I will show how we can use the CI\/CD functionality in a university project to perform\u2026","rel":"","context":"In &quot;Cloud Technologies&quot;","block_context":{"text":"Cloud Technologies","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/scalable-systems\/cloud-technologies\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/08\/Screenshot-2019-08-26-at-09.53.13.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/08\/Screenshot-2019-08-26-at-09.53.13.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/08\/Screenshot-2019-08-26-at-09.53.13.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/08\/Screenshot-2019-08-26-at-09.53.13.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/08\/Screenshot-2019-08-26-at-09.53.13.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/08\/Screenshot-2019-08-26-at-09.53.13.png?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":3314,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2018\/03\/28\/continuous-integration-deployment-for-a-cross-platform-application-part-1\/","url_meta":{"origin":4398,"position":5},"title":"Continuous Integration &#038; Deployment for a Cross-Platform Application &#8211; Part 1","author":"Tobias Eberle, Marco Maisel, Tobias Staib, Mario Walz","date":"28. March 2018","format":false,"excerpt":"When we started the project \"Flora CI\" for the lecture \"System Engineering\", we planned to deal with Continuous Integration. As an important aspect of software engineering all of us have previously been involved in projects where code of developers had to be merged and builds had to be automated somehow.\u2026","rel":"","context":"In &quot;DevOps&quot;","block_context":{"text":"DevOps","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/scalable-systems\/devops\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2018\/03\/flora-app.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2018\/03\/flora-app.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2018\/03\/flora-app.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2018\/03\/flora-app.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2018\/03\/flora-app.jpg?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2018\/03\/flora-app.jpg?resize=1400%2C800&ssl=1 4x"},"classes":[]}],"jetpack_sharing_enabled":true,"authors":[{"term_id":762,"user_id":884,"is_guest":0,"slug":"ih038","display_name":"Immanuel Haag","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/3095f100f75fe977c838303e854bb8cd3ffc7fbf01963610781fcd51bb5a4680?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/4398","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/users\/884"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/comments?post=4398"}],"version-history":[{"count":160,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/4398\/revisions"}],"predecessor-version":[{"id":6622,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/4398\/revisions\/6622"}],"wp:attachment":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/media?parent=4398"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/categories?post=4398"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/tags?post=4398"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/ppma_author?post=4398"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}