<?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>javascript Archives - Nerd Corner</title>
	<atom:link href="https://nerd-corner.com/tag/javascript/feed/" rel="self" type="application/rss+xml" />
	<link>https://nerd-corner.com/tag/javascript/</link>
	<description>Craft your dreams!</description>
	<lastBuildDate>Wed, 11 Dec 2024 13:10:33 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.2</generator>

<image>
	<url>https://nerd-corner.com/wp-content/uploads/2019/10/cropped-LogoNerdCorner-2-32x32.png</url>
	<title>javascript Archives - Nerd Corner</title>
	<link>https://nerd-corner.com/tag/javascript/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Lessons Learned: Hosting NestJS App on Vercel</title>
		<link>https://nerd-corner.com/lessons-learned-hosting-nestjs-app-on-vercel/</link>
					<comments>https://nerd-corner.com/lessons-learned-hosting-nestjs-app-on-vercel/#respond</comments>
		
		<dc:creator><![CDATA[Nerds]]></dc:creator>
		<pubDate>Thu, 14 Nov 2024 07:19:52 +0000</pubDate>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[angular]]></category>
		<category><![CDATA[config]]></category>
		<category><![CDATA[cookie-sessions]]></category>
		<category><![CDATA[CORS error]]></category>
		<category><![CDATA[Cors error nest]]></category>
		<category><![CDATA[database config]]></category>
		<category><![CDATA[database hosting]]></category>
		<category><![CDATA[express]]></category>
		<category><![CDATA[express-sessions]]></category>
		<category><![CDATA[express.js]]></category>
		<category><![CDATA[google cloud]]></category>
		<category><![CDATA[google cloud mysql]]></category>
		<category><![CDATA[Hosting]]></category>
		<category><![CDATA[internal server error vercel]]></category>
		<category><![CDATA[internal server error vercel nest]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[Lessons Learned]]></category>
		<category><![CDATA[mySql]]></category>
		<category><![CDATA[Nest]]></category>
		<category><![CDATA[Nest hosting issues]]></category>
		<category><![CDATA[NestJs]]></category>
		<category><![CDATA[Redis]]></category>
		<category><![CDATA[redis session management]]></category>
		<category><![CDATA[redis session management nest.js]]></category>
		<category><![CDATA[session management]]></category>
		<category><![CDATA[Step by step guide]]></category>
		<category><![CDATA[typescript]]></category>
		<category><![CDATA[Vercel]]></category>
		<category><![CDATA[vercel.json]]></category>
		<category><![CDATA[Visual Studio]]></category>
		<category><![CDATA[with credentials]]></category>
		<guid isPermaLink="false">https://nerd-corner.com/?p=1621</guid>

					<description><![CDATA[<p>After spending hours getting my NestJS app up and running on Vercel, I figured it was time to document what I learned—not only to save &#8230; </p>
<p>The post <a href="https://nerd-corner.com/lessons-learned-hosting-nestjs-app-on-vercel/">Lessons Learned: Hosting NestJS App on Vercel</a> appeared first on <a href="https://nerd-corner.com">Nerd Corner</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>After spending hours getting my NestJS app up and running on Vercel, I figured it was time to document what I learned—not only to save myself time in the future, but hopefully to help others avoid some of the pitfalls I ran into. Here’s a breakdown of what worked, what didn’t, and how I finally got everything running smoothly.</p>
<p><em><strong>This might also be interesting for you:</strong> <a href="https://nerd-corner.com/import-swagger-in-node-typescript-project/" target="_blank" rel="noopener">Adding Swagger to Node Server</a></em></p>
<h3>Step 1: Setting Up NestJS Vercel hosting</h3>
<p>First things first, getting the basic setup to deploy on Vercel. Vercel is awesome for serverless, but working with NestJS needed a few tweaks. The main thing is to set up a <code>vercel.json</code> configuration file, which tells Vercel exactly how to handle your app.</p>
<p>Here’s the configuration I ended up with:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="beyond">{
  "version": 2,
  "builds": [
    {
      "src": "src/main.ts",
      "use": "@vercel/node"
    }
  ],
  "routes": [
    {
      "src": "/(.*)",
      "dest": "src/main.ts",
      "methods": [
        "GET",
        "POST",
        "PUT",
        "PATCH",
        "OPTIONS",
        "DELETE",
        "HEAD",
        "CONNECT",
        "TRACE"
      ]
    }
  ]
}
</pre>
<p>I deployed it to Vercel and got the following error:</p>
<pre>This Serverless Function has crashed. Your connection is working correctly. 
Vercel is working correctly. 500: INTERNAL_SERVER_ERROR 
Code: FUNCTION_INVOCATION_FAILED ID: bom1::sgk4v-1711014022883-1e9ed54f4c37</pre>
<p>Looking in the logs, I noticed the database connection was an issue and in addition got the following log message:</p>
<pre>No exports found in module "/var/task/app-name/src/main.js".
Did you forget to export a function or a server?</pre>
<p>Turned out I could ignore the second part of the error message and just focus on the database connection.</p>
<h3>Step 2: Configuring the Database</h3>
<p>For my app, I used a mysql database with multiple schemas. I tried several free offers, but they were not compatible with the multiple schemas approach. Therefore I ended up with hosting it on Google Cloud. I scaled it down to a price of 0.01$ per hour and used the 300$ newbie offer.</p>
<p>Allowing Vercel to connect required setting the IP to <code>0.0.0.0/0</code> in Google Cloud’s configuration, making the database accessible from any IP address. <strong>Important note</strong>: make sure you test locally before deploying to Vercel, or you’ll be dealing with errors like these:</p>
<h3>Step 3: Dealing with CORS</h3>
<p>CORS caused also some headaches. Make sure you allow <code>OPTIONS</code> for CORS preflight requests, as Vercel needed explicit permission for cross-origin requests. I ended up adding a lot of headers to make sure requests were allowed:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="beyond">app.enableCors({
    origin: 'domain-name',
    credentials: true,
    methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
    allowedHeaders: [
      'Origin',
      'X-Requested-With',
      'Content-Type',
      'Accept',
      'Authorization',
    ],
  });</pre>
<h3>Step 4: Switching to <code>express-session</code> and Redis for Session Management</h3>
<p>One of the trickiest parts was getting sessions to work. I started with the <code>cookie-session</code> library, but Vercel completely ignore it. After digging into the docs and some trial and error, I switched to <code>express-session</code>, which is more popular and works nicer with Vercel’s serverless environment.</p>
<p>For some reason the import syntax has to be exactly like this:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="beyond">import session = require('express-session');</pre>
<p>I also had to configure the session middleware with <code>trust proxy</code> enabled, since Vercel proxies requests. Here’s what the final setup looked like:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="beyond">const expressApp = app.getHttpAdapter().getInstance();
expressApp.set('trust proxy', true);</pre>
<p><span style="font-size: 1.125rem;">Also s</span>etting <code>secure: true</code> and <code>sameSite: 'none'</code> was essential to ensure cookies work across HTTPS and cross-origin requests!</p>
<p>Keep in mind, with Vercel, multiple serverless instances can handle requests simultaneously, which caused session conflicts. To fix this, I connected my session storage to a Redis instance. Luckily this was super easy.</p>
<p><a href="https://redis.io/">Redis</a> keeps session data consistent, avoiding conflicts across requests, especially under load. The code I ended up with:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="beyond">const expressApp = app.getHttpAdapter().getInstance();
expressApp.set('trust proxy', true);

const redisClient = createClient({
    password: process.env.REDIS_PASSWORD,
    socket: {
      host: process.env.REDIS_HOST,
      port: parseInt(process.env.REDIS_PORT, 10),
    },
  });

  redisClient
    .connect()
    .catch((err) =&gt;
      console.log('Could not establish a connection with Redis: ' + err),
    );

  redisClient.on('error', (err) =&gt; console.log('Redis error: ' + err));
  redisClient.on('connect', () =&gt;
    console.log('Connected to Redis successfully'),
  );

  app.use(
    session({
      store: new RedisStore({ client: redisClient }),
      secret: process.env.COOKIE_SECRET,
      cookie: {
        secure: process.env.NODE_ENV !== 'development',
        sameSite: process.env.NODE_ENV === 'development' ? 'lax' : 'none',
        maxAge: 86400000,
      },
    }),
  );</pre>
<p><span style="font-family: 'Roboto Condensed', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif; font-size: 1.75rem;">Step 5: Add </span><code>withCredentials</code><span style="font-family: 'Roboto Condensed', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif; font-size: 1.75rem;"> in the Frontend</span></p>
<p>This step is just a side note: For session cookies to work between the frontend and backend, <code>withCredentials</code> need to be set to <code>true</code> on my frontend’s HTTP requests. This allows cookies to be included in cross-origin requests, which is important when the frontend and backend are hosted separately. I had to make sure Angular’s HTTP client had this setting enabled.</p>
<h3>Step 6: Include font</h3>
<p>To include font files in your NestJS project, you can use the <code>compilerOptions</code> in the <code>nest-cli.json</code> file to define assets for build output, like specifying <code>"include": "**/*.ttf"</code> and <code>"outDir": "dist/src"</code>.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-title="nest-cli.json" data-enlighter-theme="beyond">{
  "$schema": "https://json.schemastore.org/nest-cli",
  "collection": "@nestjs/schematics",
  "sourceRoot": "src",
  "compilerOptions": {
    "assets": [
      {
        "include": "**/*.ttf",
        "outDir": "dist/src"
      }
    ],
    "deleteOutDir": true
  }
}</pre>
<p>After the build, ensure the fonts are correctly referenced in your code using <code>path.resolve</code>, e.g., <code>path.resolve(__dirname, '../fonts/Roboto-Regular.ttf')</code>. This approach ensures the font files are bundled with the build and accessible during runtime.</p>
<h3>Final Thoughts to NestJS Vercel hosting</h3>
<p>Deploying my NestJS app on Vercel was a true roller coaster. Sometimes, I felt like I was on the verge of getting everything working perfectly, only to be hit with new errors that sent me back to troubleshooting mode. There were moments of frustration—especially around the session handling and CORS issues. But each solution brought a new high, and every error fixed felt like a little victory.</p>
<p>Now, with everything finally working smoothly, I can say it feels awesome. Seeing my app live and functioning the way I envisioned is worth all the headaches. It’s a huge relief, but even more, it’s deeply satisfying to know I’ve overcome each hurdle and can look back on what I learned. I hope this guide can save others some of those low points and help them reach that “it just works” moment a little faster!</p>
<p>The post <a href="https://nerd-corner.com/lessons-learned-hosting-nestjs-app-on-vercel/">Lessons Learned: Hosting NestJS App on Vercel</a> appeared first on <a href="https://nerd-corner.com">Nerd Corner</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nerd-corner.com/lessons-learned-hosting-nestjs-app-on-vercel/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>WeMos D1 R2 &#8211; Host entire website with html, css &#038; js</title>
		<link>https://nerd-corner.com/wemos-d1-r2-host-entire-website-with-html-css-js/</link>
					<comments>https://nerd-corner.com/wemos-d1-r2-host-entire-website-with-html-css-js/#respond</comments>
		
		<dc:creator><![CDATA[Nerds]]></dc:creator>
		<pubDate>Wed, 06 Mar 2024 12:18:52 +0000</pubDate>
				<category><![CDATA[Arduino projects]]></category>
		<category><![CDATA[Hardware]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Arduino]]></category>
		<category><![CDATA[Arduino with Wifi]]></category>
		<category><![CDATA[C programming]]></category>
		<category><![CDATA[communication technique]]></category>
		<category><![CDATA[control Arduino with browser]]></category>
		<category><![CDATA[data transfer]]></category>
		<category><![CDATA[entire website]]></category>
		<category><![CDATA[ESP8266]]></category>
		<category><![CDATA[ESP8266 with mDNS]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[JS]]></category>
		<category><![CDATA[led]]></category>
		<category><![CDATA[local network]]></category>
		<category><![CDATA[network]]></category>
		<category><![CDATA[Step by step guide]]></category>
		<category><![CDATA[Webserver]]></category>
		<category><![CDATA[website hosting]]></category>
		<category><![CDATA[WeMos]]></category>
		<category><![CDATA[WeMos D1]]></category>
		<category><![CDATA[WeMos D1 in Arduino IDE]]></category>
		<category><![CDATA[WeMos D1 mini]]></category>
		<category><![CDATA[WeMos D1 R2]]></category>
		<category><![CDATA[WeMOS D1 Webserver]]></category>
		<category><![CDATA[WIFI]]></category>
		<guid isPermaLink="false">https://nerd-corner.com/de/?p=1547</guid>

					<description><![CDATA[<p>The first part of the WeMos series explained the setup and Wi-Fi integration. Building on this, this article describes step by step how to host &#8230; </p>
<p>The post <a href="https://nerd-corner.com/wemos-d1-r2-host-entire-website-with-html-css-js/">WeMos D1 R2 &#8211; Host entire website with html, css &#038; js</a> appeared first on <a href="https://nerd-corner.com">Nerd Corner</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The first part of the WeMos series explained the setup and Wi-Fi integration. Building on this, this article describes step by step how to host a complete website with HTML pages, CSS styling and JavaScript functions on a WeMos. The whole thing is pretty simple and incredibly helpful! I can&#8217;t believe how hard it is to find proper instructions for this important function anywhere on the internet.</p>
<p>I often see blog articles where the HTML code is embedded in the Arduino file. You can do this for a mini demonstration, but it&#8217;s complete rubbish for everyday use. It is far too confusing and as soon as the project grows it is no longer usable.</p>
<p>The proper alternative is to set up a folder called &#8220;data&#8221; and store the web pages in this folder as html files. In addition, the styling is saved as a CSS file and functions can even be executed via a JavaScript file. So everything is 1:1 like on a normal web server!</p>
<p><em><strong>This might also be interesting for you:</strong> <a href="https://nerd-corner.com/wemos-d1-r2-setup-and-wifi-integration/">WeMos D1 R2 first steps and Wifi integration</a></em></p>
<h2>List of components</h2>
<ul>
<li>Arduino IDE (development environment)</li>
<li>WeMos D1 R2</li>
</ul>
<h2>The setup of the file system (officially SPIFFS) needs to be done once and is very easy:</h2>
<p><a href="https://nerd-corner.com/wemos-d1-r2-setup-and-wifi-integration/">(First you should have completed the basic setup from the first part!)</a></p>
<ol>
<li>Download a copy of the file &#8220;ESP8266FS-0.2.0.zip&#8221; from GitHub and unzip it</li>
<li>Place the file esp8266fs.jar in the Arduino tool directory. The path looks like this: [home_dir]\Arduino\tools\ESP8266FS\tool\esp8266fs.jar (See picture) I had to create the path part tools\ESP8266FS\tool\ in the Arduino folder myself.<img fetchpriority="high" decoding="async" class="zoooom aligncenter wp-image-1531" src="https://nerd-corner.com/wp-content/uploads/2024/03/Screenshot-file-path-esp8266fs.jar-.png" alt="Screenshot file path esp8266fs.jar" width="1080" height="335" srcset="https://nerd-corner.com/wp-content/uploads/2024/03/Screenshot-file-path-esp8266fs.jar-.png 1190w, https://nerd-corner.com/wp-content/uploads/2024/03/Screenshot-file-path-esp8266fs.jar--300x93.png 300w, https://nerd-corner.com/wp-content/uploads/2024/03/Screenshot-file-path-esp8266fs.jar--1024x318.png 1024w, https://nerd-corner.com/wp-content/uploads/2024/03/Screenshot-file-path-esp8266fs.jar--768x238.png 768w" sizes="(max-width: 1080px) 100vw, 1080px" /></li>
<li>Restart the Arduino IDE.</li>
</ol>
<p>That&#8217;s it already! You can now see the new item &#8220;ESP8266 Sketch Data Upload&#8221; in the Arduino IDE under Tools.</p>
<h2>How can I use the new file system now?</h2>
<ol>
<li>Create an additional folder with the name &#8220;data&#8221; in your current WeMos project folder. As shown in the following image</li>
</ol>
<p><img decoding="async" class="zoooom aligncenter wp-image-1528" src="https://nerd-corner.com/wp-content/uploads/2024/03/Wemos-data-folder.png" alt="Wemos data folder" width="1040" height="324" srcset="https://nerd-corner.com/wp-content/uploads/2024/03/Wemos-data-folder.png 1146w, https://nerd-corner.com/wp-content/uploads/2024/03/Wemos-data-folder-300x93.png 300w, https://nerd-corner.com/wp-content/uploads/2024/03/Wemos-data-folder-1024x319.png 1024w, https://nerd-corner.com/wp-content/uploads/2024/03/Wemos-data-folder-768x239.png 768w" sizes="(max-width: 1040px) 100vw, 1040px" /></p>
<ol start="2">
<li>Place the files you want to upload in the &#8216;data&#8217; directory</li>
<li>In the Arduino IDE, select the WeMos in the &#8216;Tools&#8217; menu and select a size for &#8216;Flash Size&#8217;</li>
<li>Close the dialogue box for the serial monitor!</li>
<li>Select the &#8216;ESP8266 Sketch Data Upload&#8217; option from the &#8216;Tools&#8217; menu.</li>
</ol>
<p><img decoding="async" class="zoooom aligncenter wp-image-1529" src="https://nerd-corner.com/wp-content/uploads/2024/03/data-folder-upload.png" alt="Data folder upload" width="805" height="518" srcset="https://nerd-corner.com/wp-content/uploads/2024/03/data-folder-upload.png 851w, https://nerd-corner.com/wp-content/uploads/2024/03/data-folder-upload-300x193.png 300w, https://nerd-corner.com/wp-content/uploads/2024/03/data-folder-upload-768x495.png 768w" sizes="(max-width: 805px) 100vw, 805px" /></p>
<p>As soon as the upload is complete, the message window of the Arduino IDE shows 100% upload.</p>
<h2>WeMos example programme for switching the OnBoard LED on and off</h2>
<p>Similar to the first part, the web server will control the OnBoard LED. The code from the first part also serves as the basis. The revised code looks like this:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="cpp" data-enlighter-theme="atomic" data-enlighter-title="D1_webserver_filesystem">#include &lt;ESP8266WiFi.h&gt;
#include &lt;ESP8266WebServer.h&gt;
#include &lt;ESP8266mDNS.h&gt;

ESP8266WebServer server(80);

void setup() {
  Serial.begin(115200); //Baudrate
  Serial.println("ESP starts");

  WiFi.begin("NerdCornerWiFi","NerdCornerPassword");


  Serial.print("Connecting...");

  while(WiFi.status()!=WL_CONNECTED){ //Loop which makes a point every 500ms until the connection process has finished

    delay(500);
    Serial.print(".");
  }
  Serial.println();

  Serial.print("Connected! IP-Address: ");
  Serial.println(WiFi.localIP()); //Displaying the IP Address

  if (MDNS.begin("nerd-corner")) {
    Serial.println("DNS started, available with: ");
    Serial.println("http://nerd-corner.local/");
  }

  server.serveStatic("/", SPIFFS, "/", "max-age=86400");
  SPIFFS.begin();

  server.onNotFound([](){ 
    server.send(404, "text/plain", "Landing page not found! Don't forget to name your landing page 'index.html'!");  
  });
 
  server.on("/led", HTTP_POST, []() {    
     
    const String ledState = server.arg("ledstate");
    if(ledState=="on"){
      switchLedOn();
    }
    else if(ledState=="off"){
      switchLedOff();
    }
    server.send(200, "text/json", "{\"result\":\"ok\"}");
  });

  server.begin();
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  server.handleClient();
  MDNS.update();

}

void switchLedOff(){ 
  digitalWrite(LED_BUILTIN, HIGH);   // turn the D1 LED off 
}

void switchLedOn(){ 
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED on 
}</pre>
<p>I would like to point out a few special features. For example, we have added the following:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="cpp" data-enlighter-theme="atomic">server.serveStatic("/", SPIFFS, "/", "max-age=86400"); 
SPIFFS.begin();</pre>
<p>Without these two lines, access to the files in the &#8220;data&#8221; folder would not be possible. Please note that the name &#8220;index.html&#8221; is set as the default for the landing page. However, you can change this if you really want to.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="cpp" data-enlighter-theme="atomic">server.on("/led", HTTP_POST, []() {    
     
    const String ledState = server.arg("ledstate");
    if(ledState=="on"){
      switchLedOn();
    }
    else if(ledState=="off"){
      switchLedOff();
      }
      server.send(200, "text/json", "{\"result\":\"ok\"}");
  });</pre>
<p>The &#8220;/led&#8221; endpoint receives the commands from the web server. If the command is &#8220;on&#8221;, the LED is switched on and if &#8220;off&#8221;, the LED is switched off.</p>
<h2>Wemos website for switching the WeMos OnBoard LED on and off</h2>
<p>The example website has a very simple structure. It primarily consists of 2 buttons for switching the LED on and off.</p>
<p><img loading="lazy" decoding="async" class="zoooom aligncenter wp-image-1536" src="https://nerd-corner.com/wp-content/uploads/2024/03/Webseite-Wemos-Control.jpeg" alt="Website Wemos control LED" width="875" height="1946" srcset="https://nerd-corner.com/wp-content/uploads/2024/03/Webseite-Wemos-Control.jpeg 921w, https://nerd-corner.com/wp-content/uploads/2024/03/Webseite-Wemos-Control-135x300.jpeg 135w, https://nerd-corner.com/wp-content/uploads/2024/03/Webseite-Wemos-Control-461x1024.jpeg 461w, https://nerd-corner.com/wp-content/uploads/2024/03/Webseite-Wemos-Control-768x1708.jpeg 768w, https://nerd-corner.com/wp-content/uploads/2024/03/Webseite-Wemos-Control-691x1536.jpeg 691w" sizes="auto, (max-width: 875px) 100vw, 875px" /></p>
<p>The folder structure of the website is very clearly organised. There is a main page with the name &#8220;index.html&#8221;. This name is common worldwide for the main pages and is also automatically recognised by WeMos. There is also a &#8220;CSS&#8221; folder for styling and a &#8220;JS&#8221; folder for functions.</p>
<p><img loading="lazy" decoding="async" class="zoooom aligncenter wp-image-1537" src="https://nerd-corner.com/wp-content/uploads/2024/03/Screenshot-data-file-system.png" alt="Screenshot esp8266 data file system" width="1045" height="347" srcset="https://nerd-corner.com/wp-content/uploads/2024/03/Screenshot-data-file-system.png 1152w, https://nerd-corner.com/wp-content/uploads/2024/03/Screenshot-data-file-system-300x100.png 300w, https://nerd-corner.com/wp-content/uploads/2024/03/Screenshot-data-file-system-1024x340.png 1024w, https://nerd-corner.com/wp-content/uploads/2024/03/Screenshot-data-file-system-768x255.png 768w" sizes="auto, (max-width: 1045px) 100vw, 1045px" /></p>
<p>We link the styles in the header area of the website. There is a standard bootstrap, which automatically makes everything a bit nicer, and a custom styles file with my own customisations. The functions of the website are also linked in the header area. I use the jQuery standard to send requests from the website to the WeMos. My own custom functions are in the &#8220;index.js&#8221;.</p>
<p>Please note that the jQuery file must be included BEFORE your own file, otherwise no jQuery commands can be used in your own code! The custom functions are then used by the buttons. The HTML code of the page looks as follows:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="html" data-enlighter-theme="atomic">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;&lt;/html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;meta charset="utf-8" /&gt;
    &lt;meta
      name="viewport"
      content="width=device-width, initial-scale=1, shrink-to-fit=no"
    /&gt;
    &lt;script type="text/javascript" src="js/jquery-3.5.1.min.js"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="./js/index.js"&gt;&lt;/script&gt;
    &lt;link rel="stylesheet" href="css/bootstrap.min.css" /&gt;
    &lt;link rel="stylesheet" href="css/custom-style.css" /&gt;
    &lt;title&gt;D1 Webserver&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;D1 Webserver with filesystem&lt;/h1&gt;
    &lt;p&gt;
      This is an example for a WeMos Webserver with a filesystem. You can easily
      create webpages with html, css and js!
    &lt;/p&gt;

    &lt;h3&gt;Example to turn on and off the built in LED&lt;/h3&gt;
    &lt;button class="button-style" onclick="changeLEDState('on')"&gt;Turn on&lt;/button&gt;
    &lt;button class="button-style" onclick="changeLEDState('off')"&gt;
      Turn off
    &lt;/button&gt;

    &lt;h3&gt;Example to demo a JS function&lt;/h3&gt;
    &lt;button class="button-style" onclick="showAlert()"&gt;Show alert&lt;/button&gt;
  &lt;/body&gt;
&lt;/html&gt;
</pre>
<p>Special attention is paid to the JavaScript function &#8220;changeLEDState(value)&#8221;</p>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">function changeLEDState(value) {
  $.post("/led", { ledstate: value });
}</pre>
<p>Because jQuery is used for communication with the WeMos, a simple dollar sign with the corresponding request command is sufficient. A value is also sent with this POST request, which is either &#8220;on&#8221; or &#8220;off&#8221; to switch the LED on and off.</p>
<p>The web page can be downloaded as a zip file below.</p>
<h2>Files to download</h2>
<ul>
<li><a  data-e-Disable-Page-Transition="true" class="download-link" title="" href="https://nerd-corner.com/download/1540/?tmstv=1756250010" rel="nofollow" id="download-link-1540" data-redirect="false" >
	Wemos example webserver to control OnBoard LED</a>
</li>
</ul>
<p>The post <a href="https://nerd-corner.com/wemos-d1-r2-host-entire-website-with-html-css-js/">WeMos D1 R2 &#8211; Host entire website with html, css &#038; js</a> appeared first on <a href="https://nerd-corner.com">Nerd Corner</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nerd-corner.com/wemos-d1-r2-host-entire-website-with-html-css-js/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Import Swagger in Node TypeScript Project</title>
		<link>https://nerd-corner.com/import-swagger-in-node-typescript-project/</link>
					<comments>https://nerd-corner.com/import-swagger-in-node-typescript-project/#comments</comments>
		
		<dc:creator><![CDATA[Nerds]]></dc:creator>
		<pubDate>Wed, 26 Oct 2022 17:10:41 +0000</pubDate>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[angular]]></category>
		<category><![CDATA[Api]]></category>
		<category><![CDATA[Backend]]></category>
		<category><![CDATA[Backend Server]]></category>
		<category><![CDATA[Backend with Swagger]]></category>
		<category><![CDATA[CRUD]]></category>
		<category><![CDATA[Endpoints]]></category>
		<category><![CDATA[express.js]]></category>
		<category><![CDATA[Github]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[Node]]></category>
		<category><![CDATA[Node with Swagger and Typescript]]></category>
		<category><![CDATA[Node.js]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[Server]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[software development]]></category>
		<category><![CDATA[Step by step guide]]></category>
		<category><![CDATA[Swagger]]></category>
		<category><![CDATA[swagger documentation]]></category>
		<category><![CDATA[Swagger express]]></category>
		<category><![CDATA[Swagger.json]]></category>
		<category><![CDATA[typescript]]></category>
		<guid isPermaLink="false">https://nerd-corner.com/de/?p=1287</guid>

					<description><![CDATA[<p>I recently coded a Node server with express.js in Typescript. This is a typical combination for backend development. It is especially beneficial if you already &#8230; </p>
<p>The post <a href="https://nerd-corner.com/import-swagger-in-node-typescript-project/">Import Swagger in Node TypeScript Project</a> appeared first on <a href="https://nerd-corner.com">Nerd Corner</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>I recently coded a Node server with express.js in Typescript. This is a typical combination for backend development. It is especially beneficial if you already have experience with frontend development in Typescript. In general I strongly recommend to use Typescript instead of Javascript for frontend as well as backend development. Typescript uses Javascript but is type based and therefore not as error prone!</p>
<p>Also, the focus should always be on clean code and it should be properly documented. Especially when a project gets bigger, proper documented work pays off. For example, to document REST endpoints it is recommended to use Swagger. The Swagger API documentation provides an overview of all endpoints and even the possibility to interact with them.</p>
<p><strong><em>This might also be interesting for you: </em></strong><a href="https://nerd-corner.com/how-to-build-a-custom-angular-reactive-svg-form-with-clickable-elements/" target="_blank" rel="noopener"><em>Angular Form with clickable SVG</em></a></p>
<h2>List of components</h2>
<ul>
<li>IDE (for example VS Code)</li>
<li>Node.js</li>
</ul>
<h2>Documentation with swagger</h2>
<p>Although Swagger is quite well known, I could not find a detailed implementation guide. Therefore I would like to explain 2 ways to implement Swagger in an existing node server. The first way is to add Swagger parameters directly to each endpoint. This is probably the faster variant, but can get messy depending on the number of endpoints. The second option is to create a &#8220;swagger.json&#8221; file that summarizes the parameters of the endpoints.</p>
<p>To use Swagger the following library and its type extension will be needed:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">npm install --save  swagger-ui-express
npm install --save-dev @types/swagger-ui-express</pre>
<p>Swagger creates documentation of the endpoints:</p>
<p><img loading="lazy" decoding="async" class="zoooom aligncenter wp-image-1271" src="https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerDocu.jpg" alt="Example Swagger Docu" width="1647" height="853" srcset="https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerDocu.jpg 1847w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerDocu-300x155.jpg 300w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerDocu-1024x531.jpg 1024w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerDocu-768x398.jpg 768w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerDocu-1536x796.jpg 1536w" sizes="auto, (max-width: 1647px) 100vw, 1647px" /></p>
<p>These can be opened and you can see an example request and an example response:</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-1273 zoooom" style="font-size: 1.125rem;" src="https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint.jpg" alt="Example Swagger Endpoint 1" width="1657" height="840" srcset="https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint.jpg 1757w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint-300x152.jpg 300w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint-1024x519.jpg 1024w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint-768x389.jpg 768w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint-1536x779.jpg 1536w" sizes="auto, (max-width: 1657px) 100vw, 1657px" /><img loading="lazy" decoding="async" class="aligncenter wp-image-1272 zoooom" src="https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint2.png" alt="Example Swagger Endpoint 2" width="1657" height="803" srcset="https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint2.png 1757w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint2-300x145.png 300w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint2-1024x496.png 1024w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint2-768x372.png 768w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint2-1536x744.png 1536w" sizes="auto, (max-width: 1657px) 100vw, 1657px" /></p>
<p>The &#8220;Try it out&#8221; button can be used to interact directly with the endpoint.</p>
<h2>Swagger API documentation with params</h2>
<p>This variant is more recommended for smaller projects. First, these two Swagger libraries must be integrated into the project:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">npm install --save-dev @types/swagger-jsdoc 
npm install --save swagger-jsdoc</pre>
<p>The libraries are configured in app.ts or for non Typescript users app.js. Due to the configuration set here, the documentation is located in &#8220;/api-docs&#8221;:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-title="app.ts">import express from "express";
import bodyParser from "body-parser";
import exampleRoutes from "./routes/example-route";
import swaggerJSDoc from "swagger-jsdoc";
import swaggerUi from "swagger-ui-express";

const app = express();

const options = {
  definition: {
    openapi: "3.0.1",
    info: {
      title: "REST API for Swagger Documentation",
      version: "1.0.0",
    },
    schemes: ["http", "https"],
    servers: [{ url: "http://localhost:3000/" }],
  },
  apis: [
    `${__dirname}/routes/example-route.ts`,
    "./dist/routes/example-route.js",
  ],
};

const swaggerSpec = swaggerJSDoc(options);

app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec));
app.use(bodyParser.json());
app.use(exampleRoutes);

app.listen(3000);</pre>
<p>The endpoint is described with the parameters as follows:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-title="example-route.ts">import { Router } from "express";
import { exampleFunction } from "../controller/example";

const router = Router();

/**
 * @swagger
 * /example:
 *      post:
 *          summary: Send the text to the server
 *          tags:
 *              - ExampleEndpoints
 *          description: Send a message to the server and get a response added to the original text.
 *          requestBody:
 *              required: true
 *              content:
 *                  application/json:
 *                      schema:
 *                          type: object
 *                          properties:
 *                              responseText:
 *                                  type: string
 *                                  example: This is some example string! This is an endpoint
 *          responses:
 *              201:
 *                  description: Success
 *                  content:
 *                      application/json:
 *                          schema:
 *                              type: object
 *                              properties:
 *                                  text:
 *                                      type: string
 *                                      example: This is some example string!
 *              404:
 *                  description: Not found
 *              500:
 *                  description: Internal server error
 */
router.post("/example", exampleFunction);

export default router;
</pre>
<h2>Swagger API documentation with swagger.json</h2>
<p>To have a better overview and not to mix the documentation with the actual code, it is recommended to use one, or even more json files. When using TypeScript, the Swagger.json file must be placed in the rootDirectory:</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-1276 zoooom" src="https://nerd-corner.com/wp-content/uploads/2022/10/foulderStructureOfSwaggerJson.jpg" alt="Foulder Structure with Swagger.json" width="170" height="344" srcset="https://nerd-corner.com/wp-content/uploads/2022/10/foulderStructureOfSwaggerJson.jpg 199w, https://nerd-corner.com/wp-content/uploads/2022/10/foulderStructureOfSwaggerJson-148x300.jpg 148w" sizes="auto, (max-width: 170px) 100vw, 170px" /></p>
<p>Again, the configuration is first defined in app.ts or, for non-Typescript users, in app.js. The domain path &#8220;/api-docs&#8221; is also selected here for the documentation:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-title="app.ts">import express from "express";
import bodyParser from "body-parser";
import exampleRoutes from "./routes/example-route";
import swaggerUi from "swagger-ui-express";

import * as swaggerDocument from "./swagger.json";

const app = express();

app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument));

app.use(bodyParser.json());

app.use(exampleRoutes);

app.listen(3000);</pre>
<p>Important note: To import JSON files into a Typescript project this must be allowed in tsconfig.json. Also, the JSON file must be located in the root directory.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-title="tsconfig.json">{
  "compilerOptions": {
    "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
    "module": "commonjs" /* Specify what module code is generated. */,
    "rootDir": "./src" /* Specify the root folder within your source files. */,
    "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,
    "resolveJsonModule": true /* Enable importing .json files. */,
    "outDir": "./dist" /* Specify an output folder for all emitted files. */,
    "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
    "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
    "strict": true /* Enable all strict type-checking options. */,
    "skipLibCheck": true /* Skip type checking all .d.ts files. */
  }
}</pre>
<p>The previous Swagger documentation with parameters would thus look like this in swagger.json:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="json">{
  "openapi": "3.0.1",
  "info": {
    "title": "REST API for Swagger Documentation",
    "version": "1.0.0"
  },
  "schemes": ["http"],
  "servers": [{ "url": "http://localhost:3000/" }],
  "paths": {
    "/example": {
      "post": {
        "tags": ["ExampleEndpoints"],
        "summary": "Send a text to the server",
        "description": "Send a message to the server and get a response added to the original text.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExampleSchemaHeader"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExampleSchemaBody"
                }
              }
            }
          },
          "404": { "description": "Not found" },
          "500": { "description": "Internal server error" }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ExampleSchemaBody": {
        "properties": {
          "responseText": {
            "type": "string",
            "example": "This is some example string! This is an endpoint"
          }
        }
      },
      "ExampleSchemaHeader": {
        "required": ["text"],
        "properties": {
          "text": {
            "type": "string",
            "example": "This is some example string!"
          }
        }
      }
    }
  }
}
</pre>
<h2>Download files</h2>
<ul>
<li><a href="https://github.com/hanneslim/Node-with-swagger-params" target="_blank" rel="noopener">Github example projcet for swagger params</a></li>
<li><a href="https://github.com/hanneslim/node-with-swagger-json" target="_blank" rel="noopener">Github example project for swagger.json</a></li>
</ul>
<p>The post <a href="https://nerd-corner.com/import-swagger-in-node-typescript-project/">Import Swagger in Node TypeScript Project</a> appeared first on <a href="https://nerd-corner.com">Nerd Corner</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nerd-corner.com/import-swagger-in-node-typescript-project/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>How to build a PUSH based architecture in Angular &#8211; Facade Design Pattern</title>
		<link>https://nerd-corner.com/how-to-build-a-push-based-architecture-in-angular-facade-design-pattern/</link>
					<comments>https://nerd-corner.com/how-to-build-a-push-based-architecture-in-angular-facade-design-pattern/#comments</comments>
		
		<dc:creator><![CDATA[Nerds]]></dc:creator>
		<pubDate>Sun, 05 Dec 2021 03:36:36 +0000</pubDate>
				<category><![CDATA[Angular]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[angular]]></category>
		<category><![CDATA[angularjs]]></category>
		<category><![CDATA[behavior subject description: Make Reactive Applications]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[observables]]></category>
		<category><![CDATA[Push Based Architecture with RxJS]]></category>
		<category><![CDATA[Remove term: Push Based Architecture with RxJS tags: angular Push Based Architecture with RxJS]]></category>
		<category><![CDATA[rxjs]]></category>
		<category><![CDATA[rxjs observables]]></category>
		<category><![CDATA[state management]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[typescript]]></category>
		<guid isPermaLink="false">https://nerd-corner.com/?p=1095</guid>

					<description><![CDATA[<p>Typically, a PULL-based architecture is used in software development and only rarely a PUSH-based architecture. A service is called to request data from a server, &#8230; </p>
<p>The post <a href="https://nerd-corner.com/how-to-build-a-push-based-architecture-in-angular-facade-design-pattern/">How to build a PUSH based architecture in Angular &#8211; Facade Design Pattern</a> appeared first on <a href="https://nerd-corner.com">Nerd Corner</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Typically, a PULL-based architecture is used in software development and only rarely a PUSH-based architecture. A service is called to request data from a server, which sends a request to the server and receives the required data. However, during this process, the main UI thread is blocked.</p>
<p>Angular itself regularly checks the view model for changes. If the view model changes due to a state change, Angular re-renders the view because Angular automatically adjusts the UI when the model changes. These continuous observations make the whole application slower.</p>
<p>Moreover, with the traditional pull approach, complexity increases. Especially when multiple views need the same data. What happens when the data changes? How are views notified that new data is available? Callback functions could help, but as a result, the application quickly becomes confusing. They also have a negative impact on handling and maintenance, especially for larger applications. After all, the objects have to be initialized individually and the dependencies or the order of the methods have to be considered.</p>
<p>A push-based architecture can be used to avoid this problem. Angular offers a great way to implement this with RxJS and the facades design pattern! The implementation is explained using an Angular example in this blog article and is transferable for all platforms and frameworks (Angular, React, Vue.js, etc.).</p>
<h2>List of components</h2>
<ul>
<li>IDE (Visual Studio Code)</li>
<li>Angular CLI</li>
</ul>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-1110 zoooom" src="https://nerd-corner.com/wp-content/uploads/2021/11/RandomBeerPUSH.png" alt="Push based Architecture Facade Service example" width="650" height="443" srcset="https://nerd-corner.com/wp-content/uploads/2021/11/RandomBeerPUSH.png 659w, https://nerd-corner.com/wp-content/uploads/2021/11/RandomBeerPUSH-300x204.png 300w" sizes="auto, (max-width: 650px) 100vw, 650px" /></p>
<h2>What is a facade actually?</h2>
<p>The facade design pattern is a central interface that communicates with various interfaces of one or more lower-level subsystems. It can perform additional functions both before and after a client request.</p>
<p>The facade object provides a unified and usually simplified interface to one or more subsystems. As an intermediary, it ensures that communication or access to the individual components of a subsystem is simplified, thereby also minimizing direct dependence on these components. It delegates the client calls in such a way that clients need to know neither the classes nor their relations and dependencies.</p>
<p>This is especially helpful in large systems when a subsystem contains many technically oriented classes that are rarely used externally. Using a facade reduces complexity by combining multiple interfaces into one. In addition, the subsystem can be extended more easily due to the loose coupling.</p>
<h2>The PUSH Architecture</h2>
<p>For a push based architecture, advanced design patterns like Redux or NgRx can be used. However, a very elegant and performant push based solution can also be achieved using RxJS.</p>
<p>Using the long-living RxJS Observable streams, changes in the data can be pushed to all subscribers. To do so, the views subscribe to the desired data stream. If the data changes, the changes are pushed directly to all subscribers via the stream without blocking the UI thread.</p>
<p>In this way, direct data access is prevented and the data is read-only. The actual data source is accessed similar to an API used by the views. The facade described at the beginning serves as the central interface here. This consists of streams that provide data when the data changes and methods to request changes to the data or request specific user-defined streams.</p>
<p>The actual raw data is only available after it has been pushed through the stream(s). This shielding centralizes all logic and forces views to passively respond to incoming data. With the push based services, Angular View components become highly performant using both ChangeDetectionStrategy.OnPush, and the async pipe for the delivered stream data.</p>
<p>Therefore, the system is lazy loading. The UI framework does not need to check for state changes of the view model and instead lazily waits for a new state to be pushed.</p>
<h2>Practical example</h2>
<p>As an example for a push based architecture a simple application is used, which receives a random beer type via the HTTP request https://random-data-api.com/api/beer/random_beer?size=1. The type of beer is displayed in a view. An input field can be used to vary the number of beers to be shown. A facade as a central element automatically pushes the new beers to the view as soon as they are available.</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-1120 zoooom" src="https://nerd-corner.com/wp-content/uploads/2021/11/facade_explanation-1.png" alt="PUSH vs PULL based architecture facade design Angular" width="1275" height="717" srcset="https://nerd-corner.com/wp-content/uploads/2021/11/facade_explanation-1.png 1280w, https://nerd-corner.com/wp-content/uploads/2021/11/facade_explanation-1-300x169.png 300w, https://nerd-corner.com/wp-content/uploads/2021/11/facade_explanation-1-1024x576.png 1024w, https://nerd-corner.com/wp-content/uploads/2021/11/facade_explanation-1-768x432.png 768w" sizes="auto, (max-width: 1275px) 100vw, 1275px" /></p>
<p>As a basis for the design pattern serves the article by Thomas Burleson: <a href="https://thomasburlesonia.medium.com/push-based-architectures-with-rxjs-81b327d7c32d" target="_blank" rel="noopener">https://thomasburlesonia.medium.com/push-based-architectures-with-rxjs-81b327d7c32d</a></p>
<h3>The first step is to set up the state management:</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">export interface Beer {
  brand: string;
  name: string;
  style: string;
  hop: string;
  alcohol: string;
}

export interface BeerState {
  beerArray: Beer[];
  size: number;
}</pre>
<h3>Next, we initialize the values of the facade&#8217;s state management:</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">export interface BeerState {
  beerArray: Beer[];
  size: number;
}

let _state: BeerState = {
  beerArray: [],
  size: 4
};</pre>
<h3>The facade uses RxJS streams to push data directly to the views. These streams can also automatically execute a Rest API call when the states change:</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">combineLatest(this.size$)
      .pipe(
        //switchMap: Maps values to observable. Cancels the previous inner observable.
        switchMap(([size]) =&gt; {
          return this.findBeerArray(size);
        })
      )
      .subscribe((beerArray) =&gt; {
        this.updateState({ ..._state, beerArray });
      });</pre>
<h3>Streams are set up to be persistent and only become active when data changes:</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">export class BeerFacade {

  beerArray$ = this.state$.pipe(
    map((state) =&gt; state.beerArray),
    distinctUntilChanged()
  );

  size$ = this.state$.pipe(
    map((state) =&gt; state.size),
    distinctUntilChanged()
  );

  private updateState(state: BeerState) {
    this.store.next((_state = state));
  }
}
</pre>
<h3>For better management, the streams are combined into a single one:</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">vm$: Observable&lt;BeerState&gt; = combineLatest(this.beerArray$, this.size$).pipe(
    map(([beerArray, size]) =&gt; {
      return { beerArray, size };
    })
  );</pre>
<h5>The HTTP request can be outsourced to a separate data service. However, since this is only a small sample program, the Rest API call is implemented and executed within the Facade:</h5>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">/** RandomBeer REST call */
  private findBeerArray(size: number): Observable&lt;Beer[]&gt; {
    const url = `https://random-data-api.com/api/beer/random_beer?size=${size}`;
    return this.http.get&lt;Beer[]&gt;(url);
  }</pre>
<h3>The facade and view model stream can now be easily initialized and used. Incredibly less code is required:</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">export class AppComponent {
  vm$: Observable&lt;BeerState&gt; = this.facadeService.vm$;

  //facadeService is public for direct usage in html
  constructor(public facadeService: RandomBeerFacadeService) {} 
  title = 'RandomBeerApp';
}</pre>
<h3>The view model stream data is displayed with the following code snippet:</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">&lt;div *ngIf="vm$ | async as vm"&gt;  
  &lt;ul&gt;
    &lt;li id="random-beer-list" *ngFor="let u of vm.beerArray"&gt;
      Brand: {{ u.brand }}, Alcohol: {{ u.alcohol }}, Hop: {{ u.hop }}
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;input id="input-rand-beer" type="number" (change)="facadeService.updateSize($event)" /&gt;
&lt;/div&gt;</pre>
<p>Angular&#8217;s Async Pipe ensures that the most current data is always displayed. <a href="https://angular.io/api/common/AsyncPipe" target="_blank" rel="noopener">Here is a detailed explanation of the async pipe.</a></p>
<h5>Since the facade service is declared as public, the inputs are passed directly to the updateSize function of the facade:</h5>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">updateSize(selectedSize: any) {
    const size = selectedSize.target.value;
    this.updateState({ ..._state, size });
  }</pre>
<p>As a result, the application initially displays 4 random beers. Afterwards the number can be increased to 7 by the input field. This calls the updateSize() function, which updates the state of the size$ stream using updateState(). As a result, a new REST call is automatically executed and the result is pushed to the view model. With the help of the async pipe the latest data is displayed. In our case the 7 random beer types.</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-1110 zoooom" src="https://nerd-corner.com/wp-content/uploads/2021/11/RandomBeerPUSH.png" alt="Push based Architecture Facade Service example" width="650" height="443" srcset="https://nerd-corner.com/wp-content/uploads/2021/11/RandomBeerPUSH.png 659w, https://nerd-corner.com/wp-content/uploads/2021/11/RandomBeerPUSH-300x204.png 300w" sizes="auto, (max-width: 650px) 100vw, 650px" /></p>
<h3>Finally, it makes sense to test the functionality of the individual facade components:</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">it('should get individual Observable "stream" of vm data', (done) =&gt; {
    testFacade.vm$.subscribe((vm) =&gt; {
      expect(vm.size).toEqual(initStateMock.size);
      done();
    });
  });

  it('should update state values', (done) =&gt; {
    const updatedStateMock: TestBeerState = {
      beerArray: [
        {
          brand: 'Pabst Blue Ribbon',
          name: 'Two Hearted Ale',
          style: 'Merican Ale',
          hop: 'Sorachi Ace',
          alcohol: '2,9%',
        },
        {
          brand: 'Bud Light',
          name: 'La fin Du Monde',
          style: 'Stout',
          hop: 'Bullion',
          alcohol: '2,7%',
        },
      ],
      size: 2,
    };
    testFacade['updateState'](updatedStateMock);
    testFacade.vm$.subscribe((vm) =&gt; {
      expect(vm).toEqual(updatedStateMock);
      done();
    });
  });

  it('should update the size value', (done) =&gt; {
    const newSize = 9;
    const mockEvent = {
      target: {
        value: newSize,
      },
    };
    testFacade['updateSize'](mockEvent);
    testFacade.vm$.subscribe((vm) =&gt; {
      expect(vm.size).toEqual(newSize);
      done();
    });
  });

  it('should perform a mocked http request', (done) =&gt; {
    const httpMock: HttpTestingController = TestBed.inject(
      HttpTestingController
    );

    const mockResponse = {
      brand: 'Pabst Blue Ribbon',
      name: 'Two Hearted Ale',
      style: 'Merican Ale',
      hop: 'Sorachi Ace',
      alcohol: '2,9%',
    };

    testFacade['findBeerArray'](1);
    testFacade.vm$.subscribe((tb) =&gt; {
      expect(tb.beerArray).toBeTruthy();
      expect(tb.beerArray[0].brand).toBe(mockResponse.brand);
      expect(tb.beerArray[0].name).toBe(mockResponse.name);
      expect(tb.beerArray[0].style).toBe(mockResponse.style);
      expect(tb.beerArray[0].hop).toBe(mockResponse.hop);
      expect(tb.beerArray[0].alcohol).toBe(mockResponse.alcohol);

      done();
    });

    const mockRequest = httpMock.expectOne(
      'https://random-data-api.com/api/beer/random_beer?size=1'
    );
    mockRequest.flush(mockResponse);
  });</pre>
<p>The post <a href="https://nerd-corner.com/how-to-build-a-push-based-architecture-in-angular-facade-design-pattern/">How to build a PUSH based architecture in Angular &#8211; Facade Design Pattern</a> appeared first on <a href="https://nerd-corner.com">Nerd Corner</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nerd-corner.com/how-to-build-a-push-based-architecture-in-angular-facade-design-pattern/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>
