<?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>angular Archives - Nerd Corner</title>
	<atom:link href="https://nerd-corner.com/tag/angular/feed/" rel="self" type="application/rss+xml" />
	<link>https://nerd-corner.com/tag/angular/</link>
	<description>Craft your dreams!</description>
	<lastBuildDate>Sun, 16 Mar 2025 18:49:48 +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>angular Archives - Nerd Corner</title>
	<link>https://nerd-corner.com/tag/angular/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Deployment of a WebApp with Kubernetes and Caddy</title>
		<link>https://nerd-corner.com/deployment-of-a-webapp-with-kubernetes-and-caddy/</link>
					<comments>https://nerd-corner.com/deployment-of-a-webapp-with-kubernetes-and-caddy/#respond</comments>
		
		<dc:creator><![CDATA[Nerds]]></dc:creator>
		<pubDate>Sun, 16 Feb 2025 18:31:48 +0000</pubDate>
				<category><![CDATA[Angular]]></category>
		<category><![CDATA[App development]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[angular]]></category>
		<category><![CDATA[Caddy]]></category>
		<category><![CDATA[Caddy Server]]></category>
		<category><![CDATA[Cluster]]></category>
		<category><![CDATA[ClusterIP]]></category>
		<category><![CDATA[ConfigMap]]></category>
		<category><![CDATA[Container]]></category>
		<category><![CDATA[Deployment]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Domain]]></category>
		<category><![CDATA[Domain Registration]]></category>
		<category><![CDATA[Hetzner]]></category>
		<category><![CDATA[Images]]></category>
		<category><![CDATA[Ingress]]></category>
		<category><![CDATA[Ingress Controller]]></category>
		<category><![CDATA[ip addres]]></category>
		<category><![CDATA[K3s]]></category>
		<category><![CDATA[Kubectl]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[LoadBalancer]]></category>
		<category><![CDATA[mySql]]></category>
		<category><![CDATA[Nest.js]]></category>
		<category><![CDATA[Node Port]]></category>
		<category><![CDATA[Pods]]></category>
		<category><![CDATA[Redis]]></category>
		<category><![CDATA[Reverse Proxy]]></category>
		<category><![CDATA[Server]]></category>
		<category><![CDATA[Service]]></category>
		<category><![CDATA[Step by step guide]]></category>
		<category><![CDATA[Traefik]]></category>
		<guid isPermaLink="false">https://nerd-corner.com/de/?p=1695</guid>

					<description><![CDATA[<p>After describing how to create production-ready Docker images and upload them to Docker Hub in the last article, it is now time to make these &#8230; </p>
<p>The post <a href="https://nerd-corner.com/deployment-of-a-webapp-with-kubernetes-and-caddy/">Deployment of a WebApp with Kubernetes and Caddy</a> appeared first on <a href="https://nerd-corner.com">Nerd Corner</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>After describing how to create production-ready Docker images and upload them to Docker Hub in the last article, it is now time to make these images available on a server. The aim is to make the web application accessible to everyone via a dedicated domain. To do this, we use a virtual private server (VPS) from Hetzner and deploy Kubernetes (k3s) with Caddy as a reverse proxy.</p>
<p><strong><em>You might also be interested in this: </em></strong><a href="https://nerd-corner.com/create-docker-images-and-upload-them-to-docker-hub/"><em>Create Docker images and upload them to Dockerhub</em></a></p>
<h2>Set up a VPS with Hetzner</h2>
<p>Hetzner often offers referral links with credit benefits for new customers. Of course, you can also use other providers, but Hetzner is attractively priced and offers solid services.</p>
<h3>What is a VPS?</h3>
<p>A Virtual Private Server (VPS) is a virtual server that is operated on a physical machine and acts as an independent server. It offers more control than classic shared hosting and is a cost-effective alternative to dedicated servers. Access is usually via SSH (Secure Shell), which allows us to control the server via the command line.</p>
<h3>SSH access to the VPS</h3>
<p>Once a VPS has been created, it is usually managed via a secure shell (SSH). SSH is a protocol that enables encrypted connections to remote servers. The following command is used to connect to the server:</p>
<p data-start="1137" data-end="1384"><span style="background-color: #e9ebec; color: #222222; font-family: Monaco, Consolas, 'Andale Mono', 'DejaVu Sans Mono', monospace; font-size: 15px;">ssh root@&lt;IP-Server&gt;</span></p>
<p>If an SSH key has been stored, authentication can be carried out using public key authentication, which is more secure than a password.</p>
<h3>Create a server at Hetzner</h3>
<ol>
<li>After logging into the Hetzner Cloud, we navigate to “Projects” and create a new project.</li>
<li>Select “Add server” and can configure an instance.</li>
<li>The cheapest model is often sufficient to start with. However, I recommend activating the option for an IPv4 address, as purely IPv6-based setups often cause compatibility problems.</li>
</ol>
<h3>Setting up a domain</h3>
<p>To access the application later under your own domain, you must register a domain and link it to the server.</p>
<h3>Apply for a domain at Hetzner</h3>
<ol>
<li>Register a new domain or add an existing domain in the Hetzner ConsoleH.</li>
<li>To manage DNS entries, we need to activate DNS access.</li>
</ol>
<h3>Set name servers</h3>
<p>The following name servers should be used:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">helium.ns.hetzner.de. 
hydrogen.ns.hetzner.com. 
oxygen.ns.hetzner.com.</pre>
<p>These new name servers offer better performance and flexibility compared to the old Hetzner name servers:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">ns1.first-ns.de.
robotns2.second-ns.de.
robotns3.second-ns.com.</pre>
<p>However, both nameserver variants are possible! The DNS changes take some time. However, we can use tools such as MXToolbox to check whether the changes have already taken place.</p>
<h3>Connect the domain to the server</h3>
<p>Now the IP address of the server must be linked to the domain:</p>
<ol>
<li>Switch to DNS zones in the Hetzner Cloud.</li>
<li>Select the registered domain.</li>
<li>Create a new A-Record and enter the IPv4 address of the server.</li>
<li>If available, remove the IPv6 record (AAAA) to avoid compatibility problems.</li>
</ol>
<p>You can also use <a href="http://mxtoolbox.com">MXToolbox</a> to check whether the DNS changes have already been applied.</p>
<h2>Set up Kubernetes</h2>
<p>Kubernetes is a powerful orchestration tool for containers. I use k3s, a lean Kubernetes variant that is particularly suitable for smaller environments.</p>
<h3>Install K3s on the server</h3>
<p>Connect to the server via SSH and install k3s with the following command:</p>
<pre><code class="language-sh">curl -sfL https://get.k3s.io | sh - </code></pre>
<p>The script installs k3s and starts the Kubernetes service. After installation, k3s can be checked with the following command:</p>
<pre><code class="language-sh">kubectl get nodes
</code></pre>
<p>k3s comes with its own kubectl version, so that no separate installation is necessary.</p>
<h3>Create YAML files for FE, BE, MySQL and Redis</h3>
<p>To deploy our application, we need YAML files for:</p>
<ul>
<li>Frontend (Angular)</li>
<li>Backend (NestJS)</li>
<li>Database (MySQL)</li>
<li>Session-Management (Redis)</li>
</ul>
<p>A deployment file for the backend could look like this:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: backend
  template:
    metadata:
      labels:
        app: backend
    spec:
      containers:
        - name: backend
          image: dockerhub-user/backend:latest
          ports:
            - containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
  name: backend-service
spec:
  selector:
    app: backend
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3000
  type: ClusterIP
</pre>
<h3>What are deployments and services?</h3>
<ul>
<li>Deployments manage the provision and scaling of containers.</li>
<li>Services ensure a stable network connection between containers.</li>
<li>ClusterIP means that the service is only accessible within the Kubernetes cluster.</li>
</ul>
<h3>Set up Caddy as a reverse proxy</h3>
<p>A reverse proxy is required to ensure that incoming traffic is distributed correctly. K3s comes with Traefik by default, but I opted for a simpler solution: Caddy. I was really surprised how little guidance or documentation there is on Caddy in combination with Kubernetes.</p>
<h3>Why Kubernetes with Caddy?</h3>
<ul>
<li>Automatic Let&#8217;s Encrypt SSL certificates</li>
<li>Simple configuration via Caddyfile</li>
<li>Built-in load balancer</li>
</ul>
<h3>Remove Traefik</h3>
<pre><code class="language-sh">kubectl delete helmrelease traefik -n kube-system
</code></pre>
<h3>Create Caddy Deployment</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">apiVersion: apps/v1
kind: Deployment
metadata:
  name: caddy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: caddy
  template:
    metadata:
      labels:
        app: caddy
    spec:
      containers:
        - name: caddy
          image: caddy
          volumeMounts:
            - name: caddy-config
              mountPath: /etc/caddy/Caddyfile
      volumes:
        - name: caddy-config
          configMap:
            name: caddy-config
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: caddy-config
data:
  Caddyfile: |

    example.com {
        reverse_proxy backend-service:3000
    }

---
apiVersion: v1
kind: Service
metadata:
  name: caddy-service
spec:
  type: LoadBalancer
  selector:
    app: caddy
  ports:
    - port: 80
      targetPort: 80
    - port: 443
      targetPort: 443</pre>
<p>Important: Since Let&#8217;s Encrypt has a rate limit, tests should first be carried out with staging certificates!</p>
<h2>Conclusion</h2>
<p>After these steps, the application is now running in a Kubernetes cluster on a Hetzner VPS and can be accessed via its own domain. The next step would be to set up an automatic CI/CD pipeline to deploy new versions without manual effort.</p>
<p>The post <a href="https://nerd-corner.com/deployment-of-a-webapp-with-kubernetes-and-caddy/">Deployment of a WebApp with Kubernetes and Caddy</a> appeared first on <a href="https://nerd-corner.com">Nerd Corner</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nerd-corner.com/deployment-of-a-webapp-with-kubernetes-and-caddy/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Create Docker images and upload them to Docker Hub</title>
		<link>https://nerd-corner.com/create-docker-images-and-upload-them-to-docker-hub/</link>
					<comments>https://nerd-corner.com/create-docker-images-and-upload-them-to-docker-hub/#respond</comments>
		
		<dc:creator><![CDATA[Nerds]]></dc:creator>
		<pubDate>Thu, 16 Jan 2025 18:16:16 +0000</pubDate>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[angular]]></category>
		<category><![CDATA[Backend]]></category>
		<category><![CDATA[Backend Server]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Docker Hub]]></category>
		<category><![CDATA[Docker Images]]></category>
		<category><![CDATA[Docker Repository]]></category>
		<category><![CDATA[frontend]]></category>
		<category><![CDATA[google cloud mysql]]></category>
		<category><![CDATA[guide]]></category>
		<category><![CDATA[Images]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[mySql]]></category>
		<category><![CDATA[Nest]]></category>
		<category><![CDATA[Nest.js]]></category>
		<category><![CDATA[Redis]]></category>
		<category><![CDATA[redis session management]]></category>
		<category><![CDATA[redis session management nest.js]]></category>
		<category><![CDATA[Repository]]></category>
		<category><![CDATA[Step by step guide]]></category>
		<guid isPermaLink="false">https://nerd-corner.com/de/?p=1691</guid>

					<description><![CDATA[<p>In this article, I will show you how to create production-ready Docker images for a web application with Angular, NestJS, MySQL and Redis and then &#8230; </p>
<p>The post <a href="https://nerd-corner.com/create-docker-images-and-upload-them-to-docker-hub/">Create Docker images and upload them to Docker Hub</a> appeared first on <a href="https://nerd-corner.com">Nerd Corner</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In this article, I will show you how to create production-ready Docker images for a web application with Angular, NestJS, MySQL and Redis and then publish them on Docker Hub. The prerequisite is an installed Docker environment.</p>
<p><em><strong>You might also be interested in this: </strong><a href="https://nerd-corner.com/lessons-learned-hosting-nestjs-app-on-vercel/">Hosting NestJS on Vercel</a></em></p>
<h2>Creation of the Docker Compose Yml</h2>
<p>With Docker Compose, all components of an application can be defined via a single configuration file and built or started together.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">version: '3.8'

services:
  frontend:
    build: ./frontend
    ports:
      - "80:80"
    depends_on:
      - backend

  backend:
    build: ./backend
    ports:
      - "3000:3000"
    depends_on:
      - mysql
      - redis
    environment:
      - DATABASE_URL=mysql://user:password@mysql:3306/db
      - SESSION_STORE=redis://redis:6379

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: db
    ports:
      - "3306:3306"

  redis:
    image: redis:latest
    ports:
      - "6379:6379"</pre>
<h2>Creating the env file</h2>
<p>To manage environment variables centrally, we create an .env file:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">DATABASE_URL=mysql://user:password@mysql:3306/db 
SESSION_STORE=redis://redis:6379</pre>
<p>Important: All ENV variables used in the code must also appear in docker-compose.yml!</p>
<h2>Docker image for the frontend</h2>
<p>The Angular frontend must be built for production. Here is an example Dockerfile:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">FROM node:20 AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build --prod

FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf</pre>
<p>Since we are dependent on nginx for the build, we also need a corresponding config file:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">server {
  listen 80;
  server_name _;

  location / {
    root /usr/share/nginx/html;
    index index.html;
    try_files $uri $uri/ /index.html;
  }
}</pre>
<h2>Docker image for the backend</h2>
<p>The NestJS backend also needs to be built. Here is an optimized Dockerfile.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic"># Build stage
FROM node:20 AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build

# Production stage
FROM node:20-alpine
WORKDIR /app

COPY --from=build /app/dist ./dist
COPY package.json package-lock.json ./
RUN npm install --only=production
CMD ["node", "dist/main.js"]</pre>
<h2>Building the app with Docker Compose</h2>
<p>Once all the Dockerfiles have been configured, the images can now be built. The whole thing is really easy with Docker compose.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">docker compose up -d --build</pre>
<p>The images are then ready, the containers are built and the app can be tested locally! The last step is to upload the images to DockerHub so that they can be used more easily later for deployment on a server.</p>
<h2>Uploading to Docker Hub</h2>
<p>Uploading is explained step by step below:</p>
<ol>
<li>Create an account on <a href="https://www.docker.com/products/docker-hub/">Dockerhub</a></li>
<li>Create a repository for the frontend and backend (1 private repo is currently free)</li>
<li>Build the images and tag them:
<pre class="EnlighterJSRAW" data-enlighter-language="generic">docker tag &lt;image-id&gt; dockerAccountName/frontend:latest
docker tag &lt;image-id&gt; dockerAccountName/backend:latest</pre>
</li>
<li>Sign up and push the images:
<pre class="EnlighterJSRAW" data-enlighter-language="generic">docker login
docker push dockerAccountName/frontend:latest
docker push dockerAccountName/backend:latest</pre>
</li>
</ol>
<h2>Outlook: Deployment with Kubernetes</h2>
<p>Now that the images are on Docker Hub, nothing stands in the way of deployment. I have opted for a Kubernetes cluster on a Hetzner VPS. <a href="https://nerd-corner.com/deployment-of-a-webapp-with-kubernetes-and-caddy/">More information here</a>.</p>
<p>The post <a href="https://nerd-corner.com/create-docker-images-and-upload-them-to-docker-hub/">Create Docker images and upload them to Docker Hub</a> appeared first on <a href="https://nerd-corner.com">Nerd Corner</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nerd-corner.com/create-docker-images-and-upload-them-to-docker-hub/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<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>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 fetchpriority="high" 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="(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 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="(max-width: 1657px) 100vw, 1657px" /><img 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="(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 Custom Angular Reactive SVG Form with clickable elements</title>
		<link>https://nerd-corner.com/how-to-build-a-custom-angular-reactive-svg-form-with-clickable-elements/</link>
					<comments>https://nerd-corner.com/how-to-build-a-custom-angular-reactive-svg-form-with-clickable-elements/#comments</comments>
		
		<dc:creator><![CDATA[Nerds]]></dc:creator>
		<pubDate>Thu, 30 Dec 2021 17:20:52 +0000</pubDate>
				<category><![CDATA[Angular]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[angular]]></category>
		<category><![CDATA[Angular reactive forms]]></category>
		<category><![CDATA[create SVG]]></category>
		<category><![CDATA[custom angular form]]></category>
		<category><![CDATA[custom form]]></category>
		<category><![CDATA[custom reactive angular form]]></category>
		<category><![CDATA[custom reactive form]]></category>
		<category><![CDATA[ng]]></category>
		<category><![CDATA[reactive]]></category>
		<category><![CDATA[reactive form with SVG]]></category>
		<category><![CDATA[reactive forms]]></category>
		<category><![CDATA[SVG]]></category>
		<category><![CDATA[SVG binding]]></category>
		<category><![CDATA[SVG plan]]></category>
		<category><![CDATA[TDD]]></category>
		<guid isPermaLink="false">https://nerd-corner.com/de/?p=1149</guid>

					<description><![CDATA[<p>During the Corona pandemic, many companies and employees discovered home office. As a result, it became apparent that not every employee required his own workstation. &#8230; </p>
<p>The post <a href="https://nerd-corner.com/how-to-build-a-custom-angular-reactive-svg-form-with-clickable-elements/">How to build a Custom Angular Reactive SVG Form with clickable elements</a> appeared first on <a href="https://nerd-corner.com">Nerd Corner</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>During the Corona pandemic, many companies and employees discovered home office. As a result, it became apparent that not every employee required his own workstation. Instead, companies now offer a shared desk model. This means that employees flexibly share workstations. Often, you can reserve your desired workstation in advance. This workplace booking function has attracted me for some time. I find the possibility to create a Custom Reactive Form in Angular, which also includes an office plan, particularly interesting. In the Custom Angular Reactive SVG Form there is the possibility to select a workstation from the office plan and to mark it with a color. As soon as a workstation has been chosen, the form will be validated and the desk will be bookable. In the following the implementation is explained step by step.</p>
<p><em><strong>This might also be interesting for you:</strong> <a href="https://nerd-corner.com/how-to-build-a-push-based-architecture-in-angular-facade-design-pattern/">How to build an Angular PUSH architecture.</a></em></p>
<h2>List of components</h2>
<ul>
<li>Development environment (e.g. VS Code)</li>
<li>Angular CLI</li>
<li><a  data-e-Disable-Page-Transition="true" class="download-link" title="" href="https://nerd-corner.com/download/1134/?tmstv=1756217887" rel="nofollow" id="download-link-1134" data-redirect="false" >
	SVG File</a>
</li>
</ul>
<p><iframe loading="lazy" id="angularFrame" title="Angular Seat Booker App" src="https://nerd-corner.com/angular/SVG-form/" width="600" height="380" frameborder="0"><span data-mce-type="bookmark" style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" class="mce_SELRES_start">﻿</span><span data-mce-type="bookmark" style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" class="mce_SELRES_start">﻿</span><span data-mce-type="bookmark" style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" class="mce_SELRES_start">﻿</span><span data-mce-type="bookmark" style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" class="mce_SELRES_start">﻿</span><br />
</iframe></p>
<h2>Creation of an office plan</h2>
<p><img loading="lazy" decoding="async" class="zoooom aligncenter wp-image-1138" src="https://nerd-corner.com/wp-content/uploads/2021/12/Office-plan.jpg" alt="SVG office plan with clickable elements Angular Form SVG" width="720" height="497" srcset="https://nerd-corner.com/wp-content/uploads/2021/12/Office-plan.jpg 726w, https://nerd-corner.com/wp-content/uploads/2021/12/Office-plan-300x207.jpg 300w" sizes="auto, (max-width: 720px) 100vw, 720px" /></p>
<p>I would almost say that creating the office plan was the hardest part of the task. The office plan can be created in different ways. The important thing is it has to be an SVG file. I used Adobe Xd and worked with lines, rectangles and circles. The result could be prettier, but it is enough to demonstrate the functionality. You can use my plan or create your own.</p>
<p>After the SVG image is created, the areas that represent a workspace need to be grouped together. I assigned the class &#8220;seat&#8221; to the group. It looks like this:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="html" data-enlighter-theme="atomic">&lt;g class="seat" &gt;
    &lt;g id="table-0" transform="translate(19 59)"&gt;
      &lt;rect width="66" height="35" stroke="none" /&gt;
      &lt;rect x="2.5" y="2.5" width="61" height="30" fill="none" /&gt;
    &lt;/g&gt;
    &lt;g id="screen-0" transform="translate(31 84)"&gt;
      &lt;rect id="fill" width="42" height="4" stroke="none" /&gt;
      &lt;path
        d="M0,1.5h42M39.5,0v4M42,2.5h-42M2.5,4v-4"
        fill="none"
        clip-path="url(#clip)"
      /&gt;
    &lt;/g&gt;
    &lt;g id="chair-0" transform="translate(40 30)"&gt;
      &lt;ellipse cx="12.5" cy="11" rx="12.5" ry="11" stroke="none" /&gt;
      &lt;ellipse cx="12.5" cy="11" rx="10" ry="8.5" fill="none" /&gt;
    &lt;/g&gt;
  &lt;/g&gt;</pre>
<p>The code snippet shown corresponds to a workstation, such as the one in the red circle here:</p>
<p><img loading="lazy" decoding="async" class="zoooom aligncenter wp-image-1140" src="https://nerd-corner.com/wp-content/uploads/2021/12/one-seat-1.png" alt="SVG office plan place selected Angular Form SVG" width="1140" height="625" srcset="https://nerd-corner.com/wp-content/uploads/2021/12/one-seat-1.png 1151w, https://nerd-corner.com/wp-content/uploads/2021/12/one-seat-1-300x164.png 300w, https://nerd-corner.com/wp-content/uploads/2021/12/one-seat-1-1024x561.png 1024w, https://nerd-corner.com/wp-content/uploads/2021/12/one-seat-1-768x421.png 768w" sizes="auto, (max-width: 1140px) 100vw, 1140px" /></p>
<h2>Creation of the Angular Reactive Form</h2>
<p>To include the office plan in a reactive form, we create a new Angular project. I took inspiration for the project from the German YouTuber Unleashed Design: https://www.youtube.com/watch?v=NOuVxP7FxBc. In general, I can highly recommend his videos! You always learn new tips and tricks, especially when dealing with Angular.</p>
<p>We need the ReactiveFormsModule for the Reactive Angular Form SVG. Then we create a FormGroup and FormControl fields. I have named the FormGroup reservationForm. It contains a field for the name, a field for the weekday and a field for the place you want to book.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="atomic">public reservationForm: FormGroup = new FormGroup({
    name: new FormControl('', [Validators.required], []),

    weekday: new FormControl('', [Validators.required], []),

    seat: new FormControl('', [Validators.required], []),
  });</pre>
<p>To be able to display the form some html code is necessary:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="html" data-enlighter-theme="atomic">&lt;form [formGroup]="reservationForm"&gt;
  &lt;label for="name"&gt; Your name:&lt;/label&gt;
  &lt;input id="name" type="text" formControlName="name" placeholder="Name" /&gt;

  &lt;label for="weekday"&gt; Enter the reservation day:&lt;/label&gt;
  &lt;input
    id="weekday"
    type="text"
    formControlName="weekday"
    placeholder="Monday"
  /&gt;
&lt;/form&gt;</pre>
<p>For a better demonstration, it makes sense to also display the value of the form:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="html" data-enlighter-theme="atomic">&lt;p&gt;Values: {{ reservationForm.value | json }}&lt;/p&gt;
&lt;p&gt;Form valid: {{ reservationForm.valid }}&lt;/p&gt;</pre>
<h2>Making Seats Component for the Custom Angular Reactive SVG Form</h2>
<p>To build a custom form field, the first thing we need is a new component. Here we can directly use a tip from Unleashed Design. Angular offers the possibility to include SVG images as templateUrl. We delete the seats.component.html and replace it with our SVG office plan named seats.component.svg. In the seats.component.ts we can replace the templateUrl with the SVG file:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="atomic">selector: 'app-seats',
templateUrl: './seats.component.svg',
styleUrls: ['./seats.component.sass'],</pre>
<p>The custom form field can now be included in the reactive form:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="html" data-enlighter-theme="atomic">&lt;app-seats id="seat" formControlName="seat"&gt;&lt;/app-seats&gt;</pre>
<p>In the Sass file, the SVG office plan can be customized as desired. Colors, line thicknesses, and much more can be set here. I have customized it so that the office plan turns red when the SVG form field is invalidated:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="scss" data-enlighter-theme="atomic">$successColour: #19e619

:host
    &amp;.ng-touched, &amp;.ng-dirty
            &amp;.ng-invalid
                svg
                    .wall, .seat
                        stroke: red

    svg
        margin: 25px 0 25px 0
        
        .wall
            stroke: black
            fill: #fff 
            stroke-width: 5
        .separators
            stroke: black
            fill: none
            stroke-width: 5
        .separate-room
            stroke: black
            fill: none
            stroke-width: 5

        .seat
            stroke: grey
            cursor: pointer
            fill: #fff 
            transition: all 250ms
            stroke-width: 4
            &amp;.selected
                fill: $successColour
                stroke-width: 1
</pre>
<h2>Adding the ControlValueAccessor</h2>
<p>We can already see our office plan in the Reactive Form, but it is still without functionality. To change that a ControlValueAccessor is needed. The ControlValueAccessor serves as an interface for a custom form control that integrates with Angular forms. The ControlValueAccessor asks for these four methods:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="atomic">interface ControlValueAccessor {
  writeValue(obj: any): void
  registerOnChange(fn: any): void
  registerOnTouched(fn: any): void
  setDisabledState(isDisabled: boolean)?: void
}</pre>
<p>More information about the ControlValueAccessor can be found in the doc: https://angular.io/api/forms/ControlValueAccessor</p>
<p>In order for the seats.component.ts component to get access to the VALUE_ACCESSOR we need to configure the following provider:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="atomic">providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() =&gt; SeatsComponent),
      multi: true,
    },
  ],</pre>
<h2>Variables and methods for the Angular Forms ControlValueAccessor</h2>
<p>The next step looks more complicated than it actually is. Basically, these are fixed variables and methods that every custom form field needs.</p>
<p>Every custom reactive form needs the following variables. The variable onTouched, in order for the form field to become touched later. Also onChange and the static variable touched as a boolean to know if the form field is already touched. A form field can also be disabled, so the static variable isDisabled is also required as a boolean. Of course every custom form also uses a value.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="atomic">public onTouched = () =&gt; {};
public onChange = (value: string) =&gt; {};
public touched: boolean = false;
public isDisabled: boolean = false;
public value: string = '';</pre>
<p>Every Custom Reactive Form also needs the possibility to change these variables. This is where the ControlValueAccessor methods discussed in the previous section come into play. One is the writeValue function, which sets the value variable to a new value. The markAsTouched function calls onTouched and sets the variable touched to true if the custom form field has not been clicked before. Finally, the two methods registerOnChange and registerOnTouched are needed. Both actually only update their respective value. The registerOnChange function updates the value onChange and registerOnTouched updates the value onTouched. The reactiveFormModule can also disable entire forms. To ensure that the custom reactive form field also listens to this, the setDisabledState method is used. With this method the variable isDisabled can be changed.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="atomic">writeValue(value: string): void {
  this.value = value;
}
markAsTouched(): void {
  if (!this.touched) {
    this.onTouched();
    this.touched = true;
  }
}
registerOnChange(onChange: any): void {
  this.onChange = onChange;
}
registerOnTouched(onTouched: any): void {
  this.onTouched = onTouched;
}

setDisabledState(isDisabled: boolean): void {
  this.isDisabled = isDisabled;
}</pre>
<h2>Bind SVG groups to the form variables</h2>
<p>In order for the SVG office plan to be functionally usable, we still need the possibility to select individual workstations. For this we use the Angular binding possibilities. A function isSelected() is required to detect and change the sytling of the workstation.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="html" data-enlighter-theme="atomic">[class.selected]="isSelected('seat-0')"
(click)="select('seat-0')"</pre>
<p>Also a function select(), which recognizes the selected seat of the Custom Angular Reactive SVG Form by the name (&#8220;seat-1&#8221;, &#8220;seat-2&#8243;&#8230;). Within this select() function it is first checked if the form is disabled in general. If this is not the case, a second query checks if the seat has already been selected. If this is the case the value becomes nothing, otherwise the value becomes the name of the seat, for example &#8220;seat-3&#8221;.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="atomic">public select(option: string): void {
  if (!this.isDisabled) {
    if (this.isSelected(option)) {
      this.value = '';
    } else {
      this.value = option;
    }
    this.onChange(this.value);
    this.markAsTouched();
  }
}

public isSelected(option: string): boolean {
  return option === this.value;
}</pre>
<h2>Download files</h2>
<ul>
<li><a href="https://github.com/hanneslim/Angular-form-with-SVG-options">Project on Github</a></li>
</ul>
<p>The post <a href="https://nerd-corner.com/how-to-build-a-custom-angular-reactive-svg-form-with-clickable-elements/">How to build a Custom Angular Reactive SVG Form with clickable elements</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-custom-angular-reactive-svg-form-with-clickable-elements/feed/</wfw:commentRss>
			<slash:comments>1</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>
