<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Omar Elwakeel</title>
    <description>The latest articles on DEV Community by Omar Elwakeel (@omardiaa48).</description>
    <link>https://dev.to/omardiaa48</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F689216%2Fb966a399-48ba-4b8f-908d-d1d5fa3c24a2.png</url>
      <title>DEV Community: Omar Elwakeel</title>
      <link>https://dev.to/omardiaa48</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/omardiaa48"/>
    <language>en</language>
    <item>
      <title>Fullstack nodejs reactjs with docker compose</title>
      <dc:creator>Omar Elwakeel</dc:creator>
      <pubDate>Thu, 17 Nov 2022 11:37:18 +0000</pubDate>
      <link>https://dev.to/omardiaa48/fullstack-nodejs-reactjs-with-docker-compose-2ifk</link>
      <guid>https://dev.to/omardiaa48/fullstack-nodejs-reactjs-with-docker-compose-2ifk</guid>
      <description>&lt;h2&gt;
  
  
  If you have developed an application back to front and want to make automatic deployments, if you are struggling with this part, here I might answer your questions, at least some of them.
&lt;/h2&gt;

&lt;p&gt;To have automatic deployment and secure communication in a seamless way between the backend and the frontend, you can do so with many options and alternatives, one of these is using docker compose, I use it in demos so it can be easily explained.&lt;/p&gt;

&lt;p&gt;I made a repository that has all the code explained here so I don't make you bored and just go through the important bits of the code that does the magic, the url to the repository goes here &lt;a href="https://github.com/omar-diaa-48/fullstack-docker-compose-demo" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the application you can have any kind of frameworks used, but at the end you have a communication between both backend and frontend, this communication if done using &lt;strong&gt;RESTful APIs&lt;/strong&gt; then using http protocol you can transfer data in between, in our case the backend is listening to some endpoints and the frontend is using axios package to send those requests.&lt;/p&gt;

&lt;p&gt;Your project directory could be like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fctiv5k6wmfp3lpo0b4uk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fctiv5k6wmfp3lpo0b4uk.png" alt="Image description" width="482" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both backend and frontend should contain Dockerfile build and run steps as follows&lt;/p&gt;

&lt;p&gt;backend/Dockerfile&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:16.17.0-alpine

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./

RUN npm install
# If you are building your code for production
# RUN npm ci --only=production

# Bundle app source
COPY . .

EXPOSE 9000
CMD [ "npm", "start" ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;frontend/Dockerfile&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:16.17.0-alpine

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./

RUN npm install
# If you are building your code for production
# RUN npm ci --only=production

# Bundle app source
COPY . .

EXPOSE 3000
CMD [ "npm", "start" ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;docker-compose.yml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '3.4'
services:
  backend:
    build: ./backend
    container_name: backend
    environment:
      - PORT=9000
    ports:
      - '9000:9000'
    expose:
      - '9000'
    networks:
      - integration
  frontend:
    build: ./frontend
    container_name: frontend
    environment:
      - REACT_APP_BACKEND_URL=http://localhost:9000
    ports:
      - '3000:3000'
    expose:
      - '3000'
    networks:
      - integration
networks:
  integration:
    driver: bridge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To explain what is going on, the dockerfiles builds an image for your code, like a template that can be run at any time and on any platform, the docker-compose makes use of these dockerfiles as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;services: is the services you have, as you can have many, like backend and frontend, each service has the follows&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;build: path to the dockerfile&lt;/li&gt;
&lt;li&gt;container_name: name of the container to be created&lt;/li&gt;
&lt;li&gt;environment: environment variables passed into the container&lt;/li&gt;
&lt;li&gt;expose: port to be exposed to the outside of the container created&lt;/li&gt;
&lt;li&gt;networks: what network to be used, as docker compose to secure connection between containers, can be taught to create a bridge between containers to communicate through.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;networks: this is how we tell docker compose to create a network bridge to allow the containers to communicate through&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>Want to open modals from any place in your code? this article is for you!</title>
      <dc:creator>Omar Elwakeel</dc:creator>
      <pubDate>Sat, 05 Nov 2022 12:47:13 +0000</pubDate>
      <link>https://dev.to/omardiaa48/want-to-open-modals-from-any-place-in-your-code-this-article-is-for-you-5gpn</link>
      <guid>https://dev.to/omardiaa48/want-to-open-modals-from-any-place-in-your-code-this-article-is-for-you-5gpn</guid>
      <description>&lt;h2&gt;
  
  
  When I was a beginner developer, I struggled with opening and closing modals, the UI itself was no issue, but managing the state of the application modals was a trouble, if you feel or ever felt the same, go through this simple and short tutorial, I will give you a guide on how to make it better.
&lt;/h2&gt;

&lt;p&gt;Requirements&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;SPA (react, vue, ...) or SSR (next, nuxt, ...)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Application state management tool (redux, ...)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Modal design or a ready one like MUI's modals&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this tutorial, I'm going to use react, redux and MUI's modal&lt;/p&gt;

&lt;p&gt;Enough with the intro, let's start some code&lt;/p&gt;

&lt;p&gt;I suppose you will have a layout that wraps your code, assume this is the content of it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div&amp;gt;
 &amp;lt;Navbar /&amp;gt;
 {children} // these are the actual page content
 &amp;lt;Footer /&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To have a central modal to be managed from everywhere in the code you should have a central state, in my case it's redux&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ModalState {
 isOpened: boolean;
 current: "auth-modal" | "checkout-modal" | "confirm-modal";
 args: any;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;isOpened&lt;/strong&gt; is a boolean to check if the modal is currently opened&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ModalType&lt;/strong&gt; is a string that identifies the current modal to be rendered &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;args&lt;/strong&gt; is any kind of arguments you want to send to the current modal&lt;/p&gt;

&lt;p&gt;Inside the modal state slice&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openModalAction: (state, action) =&amp;gt; {
 const { current, args } = action.payload;
 return {
  isOpened: true,
  current,
  args
 }
},

closeModalAction: (state, action) =&amp;gt; {
 return {
  ...state,
  isOpened: false,
  args: []
  }
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;openModalAction&lt;/strong&gt; sets the current modal and sends the required props to that modal through the args parameter&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;closeModalAction&lt;/strong&gt; closes the modal opened no matter any&lt;/p&gt;

&lt;p&gt;Going back to the layout that is wrapping the whole app you can add one more component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div&amp;gt;
 &amp;lt;Navbar /&amp;gt;
 {children} // these are the actual page content
 &amp;lt;Footer /&amp;gt;
 &amp;lt;CentralModalRenderer /&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;for the CentralModalRenderer component, it can be like the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const dispatch = useDispatch();
const { current, isOpened, args } = useSelector((state) =&amp;gt; state.modal)

function renderCurrentComponent() {
    switch (current) {
        case "auth-modal":
            return (&amp;lt;AuthModal {...args} /&amp;gt;)
                case "checkout-modal":
            return (&amp;lt;CheckoutModal {...args} /&amp;gt;)
        default:
            return null
    }
}

const handleClose = () =&amp;gt; {
 dispatch(closeModalAction())
}

return (
    isOpened ? (
        &amp;lt;Modal 
                     open={isOpened} 
                     handleClose={handleClose}
                 &amp;gt;
            {renderCurrentComponent()}
                 &amp;lt;Modal/&amp;gt;
        ) : null
    )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Modal&lt;/strong&gt; is MUI's modal, that requires two props, boolean to for the modal to be opened or not, and on close handler&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;isOpened&lt;/strong&gt; whenever true will open the modal state&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;renderCurrentComponent&lt;/strong&gt; is a function to check which is the  current value in the modal state and renders the modal component created that matches&lt;/p&gt;

&lt;p&gt;Notice that the args are always sent to the component, so how to open it, easy&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;button
onClick={() =&amp;gt; dispatch(openModal({current:"auth-modal", args:{message:"Are you sure you want to leave?"}}))}
&amp;gt;
open modal
&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope this was enough to start your own central modal, the same idea can be used to implement a central notification system, or a central management state for UI, all over your code and components&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>modal</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>EC2 Launch template step by step</title>
      <dc:creator>Omar Elwakeel</dc:creator>
      <pubDate>Thu, 23 Jun 2022 15:58:46 +0000</pubDate>
      <link>https://dev.to/omardiaa48/ec2-launch-template-step-by-step-1kac</link>
      <guid>https://dev.to/omardiaa48/ec2-launch-template-step-by-step-1kac</guid>
      <description>&lt;h2&gt;
  
  
  Developing on your local machine is not a hassle for any one any more, deploying you code on a machine is no longer a problem also, but automating the process might be intimidating for some.
&lt;/h2&gt;

&lt;p&gt;In this article, I will go through the configuration needed to create an EC2 launch template to automate assigning a new server instance, pull the code, make the proper configuration and even start the application.&lt;/p&gt;

&lt;p&gt;Requirements&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;AWS Account&lt;/li&gt;
&lt;li&gt;Github or Bitbucket repository that contains your application (i used nodejs in mine)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;First of all, head to the EC2 Dashboard, and click on the launch template on the side navbar&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb9eizwebvy8d5srmk7s5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb9eizwebvy8d5srmk7s5.png" alt="Launch template btn" width="257" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create a launch template&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;give the template a name&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Define the OS, in my case (Ubuntu server 22.04 t2.micro) because it's free eligible&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the security group, most importantly it has an allow rule for both (http port 80, and ssh port 22)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Network settings&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configure storage&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Under the Advanced details there is an important field called user data, this part is quite important.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;User data can hold the scripts for the instance to run once it's initialized, like installing some packages, pulling the code, build and start it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feoduehqobr5abacfunoy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feoduehqobr5abacfunoy.png" alt="User data" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add thee following code, I will add a comment before each line describing what it does. &lt;strong&gt;Lines that start will ## is comments&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
## 1. This line is important for AWS EC2 to understand the context of this file
#!/bin/bash -ex

## 2. Log all incidents in a user-data.log file
exec &amp;gt; &amp;gt;(tee /var/log/user-data.log|logger -t user-data -s 2&amp;gt;/dev/console) 2&amp;gt;&amp;amp;1

## 3. Install nodejs
curl -sL https://deb.nodesource.com/setup_14.x -o nodesource_setup.sh
bash nodesource_setup.sh
apt-get -y install nodejs
apt-get -y install build-essential

## 4. Install nginx for network routing
apt-get update
apt-get -y install nginx
ufw allow 'Nginx Full'

## 5. Remove nginx default configuration
cd /etc/nginx/sites-available
unlink default

## 6. Add your custom nginx configuration
tee -a myapp.com &amp;lt;&amp;lt;EOF
server {
 listen 80 default_server;
 listen [::]:80 default_server;
 server_name myapp.com;

 location / {
   proxy_pass http://127.0.0.1:3000;
   proxy_http_version 1.1;
   proxy_set_header Upgrade \$http_upgrade;
   proxy_set_header Connection 'upgrade';
   proxy_set_header Host \$host;
 }
}
EOF

## 7. Remove nginx other configuration file
cd /etc/nginx/sites-enabled
unlink default


## 8. Link both configurations and restart nginx
ln -s /etc/nginx/sites-available/myapp.com /etc/nginx/sites-enabled/myapp.com
systemctl restart nginx

cd /home/ubuntu

## 8. Install pm2 for forever running an application
npm install pm2 -g

mkdir app
cd app

## 8. Clone your repository and you may use the password in the url to skip password check step
git clone https://&amp;lt;username&amp;gt;:&amp;lt;password&amp;gt;@bitbucket.org/&amp;lt;project-name&amp;gt;/&amp;lt;repo-name&amp;gt;.git

cd repo-name

## 9. Add .env file and the necessary environment variables
tee -a .env &amp;lt;&amp;lt;EOF
NODE_ENV=development

PORT=3000
EOF

npm install

npm run build

## 10. Use pm2 to start the application
pm2 start npm --name "repo-name" -- run start

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Now your server is initialized, configured, the code is pulled to the latest changes and even up and running&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To check go EC2 Dashboard and launch and instance, but this time from a launch template&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr3oogxsmsnsuwi03s2en.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr3oogxsmsnsuwi03s2en.png" alt="Launch instance from launch template" width="702" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should count from 2 to 5 minutes and viola you have your own new instance, use the public IP or the public dns -provided in the instance info- in the browser. Now you should see the response from your application.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Microservices with express.js and rabbitmq</title>
      <dc:creator>Omar Elwakeel</dc:creator>
      <pubDate>Fri, 29 Apr 2022 13:07:25 +0000</pubDate>
      <link>https://dev.to/omardiaa48/microservices-with-expressjs-and-rabbitmq-34dk</link>
      <guid>https://dev.to/omardiaa48/microservices-with-expressjs-and-rabbitmq-34dk</guid>
      <description>&lt;h2&gt;
  
  
  This article is to simplify and do a step by step tutorial to make a &lt;strong&gt;microservices app&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this tutorial, I'm going to use&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Node.js as runtime environment.&lt;/li&gt;
&lt;li&gt;Typescript instead of Javascript for better development experience.&lt;/li&gt;
&lt;li&gt;Express.js for the backend.&lt;/li&gt;
&lt;li&gt;Rabbitmq as a message broker.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To find the final code, you can find it on &lt;a href="https://github.com/omar-diaa-48/online-ordering-warehouse" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Before typing code, why Microservices?
&lt;/h2&gt;

&lt;p&gt;Let's say we have to services, In a &lt;em&gt;Monolithic Architecture&lt;/em&gt; you would have only one repository and all your services interact through the same instance, if any service caused the instance to crash, the whole application will crash. &lt;/p&gt;

&lt;p&gt;While in a &lt;em&gt;Microservices Architecture&lt;/em&gt; each will work a whole unit and on interacting with other services, it uses message brokers like &lt;em&gt;Rabbitmq&lt;/em&gt; to send a message to other services.&lt;/p&gt;

&lt;p&gt;Now consider a warehouse service (consumer) that really depends on an order service (publisher), where whenever an order is submitted the warehouse is notified and starts the shipping process, in this architecture, if the order service caused a crash, the warehouse won't be affected and will keep working, even if the warehouse service was out when an order is submitted, the message broker will keep the message and on the startup of the warehouse service, it will assert that in knows about this message.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to implement it?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;First&lt;/strong&gt;, the folder structure, consider making a directory called online-ordering-microservices, with two folders inside [order, warehouse]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftbunkhwqoqezq2vrzm05.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftbunkhwqoqezq2vrzm05.png" alt="Folder structure" width="286" height="117"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The .gitingore file to ignore the node_modules inside each service&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second&lt;/strong&gt;, setup rabbitmq as a message broker&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;docker container run --name rabbitmq --detach -p 5672:5672 rabbitmq&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will run a container from the image rabbitmq, on a detached mode and expose the port 5672 which is the default port for rabbitmq and give this container a name rabbitmq&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Third&lt;/strong&gt;, setup each service.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;npm install express @types/express amqplib @types/amqplib&lt;/code&gt; to install the necessary dependencies.&lt;/p&gt;

&lt;p&gt;order/index.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
import amqplib, { Channel, Connection } from 'amqplib'
import express, { Request, Response } from 'express'

const app = express()

// parse the request body
app.use(express.json())

// port where the service will run
const PORT = 9005

// rabbitmq to be global variables
let channel: Channel, connection: Connection

connect()

// connect to rabbitmq
async function connect() {
  try {
      // rabbitmq default port is 5672
    const amqpServer = 'amqp://localhost:5672'
    connection = await amqplib.connect(amqpServer)
    channel = await connection.createChannel()

    // make sure that the order channel is created, if not this statement will create it
    await channel.assertQueue('order')
  } catch (error) {
    console.log(error)
  }
}

app.post('/orders', (req: Request, res: Response) =&amp;gt; {
  const data = req.body

  // send a message to all the services connected to 'order' queue, add the date to differentiate between them
  channel.sendToQueue(
    'order',
    Buffer.from(
      JSON.stringify({
        ...data,
        date: new Date(),
      }),
    ),
  )

  res.send('Order submitted')
})

app.get('*', (req: Request, res: Response) =&amp;gt; {
  res.status(404).send('Not found')
})

app.listen(PORT, () =&amp;gt; {
  console.log(`Server running on ${PORT}`)
})


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;warehouse/index.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
import amqplib, { Channel, Connection } from 'amqplib'
import express, { Request, Response } from 'express'

const app = express()

// parse the request body
app.use(express.json())

// port where the service will run
const PORT = 9005

// rabbitmq to be global variables
let channel: Channel, connection: Connection

connect()

async function connect() {
  try {
    const amqpServer = 'amqp://localhost:5672'
    connection = await amqplib.connect(amqpServer)
    channel = await connection.createChannel()

    // consume all the orders that are not acknowledged
    await channel.consume('order', (data) =&amp;gt; {
      console.log(`Received ${Buffer.from(data!.content)}`)
      channel.ack(data!);
    })
  } catch (error) {
    console.log(error)
  }
}

app.get('*', (req: Request, res: Response) =&amp;gt; {
  res.status(404).send('Not found')
})

app.listen(PORT, () =&amp;gt; {
  console.log(`Server running on ${PORT}`)
})


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if you run both apps and made a post request to &lt;a href="http://localhost:9005/orders" rel="noopener noreferrer"&gt;http://localhost:9005/orders&lt;/a&gt;, you will get a message in the warehouse service, more importantly, if you made a request while the warehouse service is not running and started the warehouse service, it will receive that message, and actually will keep receiving it untill it acknowledges it.&lt;/p&gt;

&lt;p&gt;I hope you liked this tutorial, and see you in another ones.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>microservices</category>
      <category>beginners</category>
    </item>
    <item>
      <title>CI/CD pipeline, easy steps.</title>
      <dc:creator>Omar Elwakeel</dc:creator>
      <pubDate>Wed, 16 Mar 2022 16:35:07 +0000</pubDate>
      <link>https://dev.to/omardiaa48/cicd-pipeline-easy-steps-ocm</link>
      <guid>https://dev.to/omardiaa48/cicd-pipeline-easy-steps-ocm</guid>
      <description>&lt;h2&gt;
  
  
  This article to demonstrate how to build your own CI/CD pipeline.
&lt;/h2&gt;

&lt;p&gt;The next steps and procedures can be used on other code repo management systems and other deployment platforms, So &lt;em&gt;Bitbucket&lt;/em&gt; and &lt;em&gt;Heroku&lt;/em&gt; are just examples.&lt;/p&gt;

&lt;p&gt;First of all you should have the following or similar:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A code repo that is attached to &lt;em&gt;Bitbucket&lt;/em&gt; or any similar code management system&lt;/li&gt;
&lt;li&gt;A platform to deploy code on, in my case I'm going to use &lt;em&gt;Heroku&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;First to access your Heroku App you should have an API Key like any other platform, In case of &lt;em&gt;AWS&lt;/em&gt; you have to have Access keys, You have to put this or these keys in the repository settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw10ciw6vzk529v82hbpj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw10ciw6vzk529v82hbpj.png" alt="Image description" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Second if you have variables that are related to the environment itself like the &lt;em&gt;Heroku&lt;/em&gt; app name, you can state them in the deployment section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F87f4fmh75ox792xjwjea.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F87f4fmh75ox792xjwjea.png" alt="Image description" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In your code base you should have a file with the following name &lt;code&gt;bitbucket-pipelines.yml&lt;/code&gt;, the name of the file will differ based on the code repo managamenet system you are using, however this file should contain code similar to this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;image: node:10.15.3 
pipelines:
  default:
    - step:
         script:
          - echo $BITBUCKET_BRANCH
  branches:
    dev:
       - step:
           name: Create artifact
           script: 
             - git archive --format=tar.gz $BITBUCKET_BRANCH -o application.tar.gz 
           artifacts: 
             - application.tar.gz
       - step:
           name: Deploy to heroku
           deployment: dev
           caches:
             - node
           script:
             - pipe: atlassian/heroku-deploy:1.1.4
               variables:
                 HEROKU_API_KEY: $HEROKU_API_KEY
                 HEROKU_APP_NAME: &amp;lt;App-Name&amp;gt;
                 ZIP_FILE: 'application.tar.gz'
                 WAIT: 'true'
    stage:
       - step:
           name: Create artifact
           script: 
             - git archive --format=tar.gz $BITBUCKET_BRANCH -o application.tar.gz 
           artifacts: 
             - application.tar.gz
       - step:
           name: Deploy to heroku
           deployment: dev
           caches:
             - node
           script:
             - pipe: atlassian/heroku-deploy:1.1.4
               variables:
                 HEROKU_API_KEY: $HEROKU_API_KEY
                 HEROKU_APP_NAME: &amp;lt;App-Name&amp;gt;
                 ZIP_FILE: 'application.tar.gz'
                 WAIT: 'true'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;All line of codes pre-fixed with $&lt;/strong&gt; are variables that will be determined in runtime. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BITBUCKET_BRANCH&lt;/strong&gt; is the current branch that had the currect change.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;image&lt;/strong&gt; is the image of the container responsible for deploying the code and doing the following steps, in here will be node version 10.15.3&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;default pipeline&lt;/strong&gt; is a pipeline that will execute no matter what branch is active.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;branches&lt;/strong&gt; will define the code and steps to take place based on the active branch&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;App-Name&lt;/strong&gt; this will be your application name that will depend on the environment your are building on, testing, dev, staging, production.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whenever your trigger this pipeline by pushing the code to branch or trigger it manually, this will happen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzqjt1i05cuvkncei2lb8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzqjt1i05cuvkncei2lb8.png" alt="Image description" width="800" height="44"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flsfpst1srajfzkjvb5ff.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flsfpst1srajfzkjvb5ff.png" alt="Image description" width="800" height="50"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fetg5fgmcmayvj5fomcvi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fetg5fgmcmayvj5fomcvi.png" alt="Image description" width="648" height="196"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And viola your code is deployed automatically, This can be better and more efficient if you have a testing phase before building the code, then you will add the script responsible for running the test cases before the build script, and the build script will only run if the test step is successful.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>automatio</category>
    </item>
    <item>
      <title>How to create your website landing logo with framer-motion</title>
      <dc:creator>Omar Elwakeel</dc:creator>
      <pubDate>Sat, 26 Feb 2022 17:24:20 +0000</pubDate>
      <link>https://dev.to/omardiaa48/how-to-create-your-website-landing-logo-with-framer-motion-2bhf</link>
      <guid>https://dev.to/omardiaa48/how-to-create-your-website-landing-logo-with-framer-motion-2bhf</guid>
      <description>&lt;p&gt;&lt;strong&gt;Are you building your own website, or working on a project where you want to make a robust landing page?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This article is for this purpose, where we will go through very minimal and easy steps to do a logo that will show, animate and fade with a cinematic way.&lt;/p&gt;

&lt;p&gt;In this tutorial we will work with react and with the support of framer-motion package, everything will go smooth and easy.&lt;/p&gt;

&lt;p&gt;In your App.js component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Form from "./components/Form";
import Header from "./components/Header";

function App() {
    return (
        &amp;lt;div className="h-screen flex justify-center items-center"&amp;gt;
            &amp;lt;Header /&amp;gt;
            &amp;lt;Form /&amp;gt;
        &amp;lt;/div&amp;gt;
    );
}

export default App;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the form component is not important, because it could be anything, one of the possible things is the rest of your app.&lt;/p&gt;

&lt;p&gt;In Header.js component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useEffect, useState } from "react";
import Logo from "./Logo";

export default function Header() {
    const [isVisible, setIsVisible] = useState(true);

    useEffect(() =&amp;gt; {
        setTimeout(() =&amp;gt; {
            setIsVisible(false)
        }, 4000);
    }, [])

    return (
        &amp;lt;div&amp;gt;
            {isVisible &amp;amp;&amp;amp; &amp;lt;Logo /&amp;gt;}
        &amp;lt;/div&amp;gt;
    )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the settimeout will assure that the logo will only appear once, which is on the first load of the page.&lt;/p&gt;

&lt;p&gt;In Logo.js component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { AnimatePresence, motion } from "framer-motion";

const svgVariants = {
    initial: {
        rotate: -360
    },
    animate: {
        rotate: 0,
        transition: {
            duration: 1
        }
    },
    exit: {
        rotate: -180
    }
}

const pathOneVariants = {
    initial: {
        opacity: 0,
        pathLength: 0
    },
    animate: {
        opacity: 1,
        pathLength: 1,
        transition: {
            duration: 2,
            ease: 'easeInOut'
        }
    }
}

const pathTwoVariants = {
    initial: {
        opacity: 1,
        pathLength: 1
    },
    animate: {
        opacity: 0,
        pathLength: 0,
        transition: {
            duration: 2,
            delay: 2,
            ease: 'easeInOut'
        }
    }
}



export default function Logo() {
    return (
        &amp;lt;AnimatePresence&amp;gt;
            &amp;lt;motion.div className="fixed top-0 left-0 w-full h-full bg-slate-300 flex justify-center items-center"&amp;gt;
                &amp;lt;motion.svg xmlns="http://www.w3.org/2000/svg" width="250" height="250" viewBox="0 0 192.755 192.756"
                    className="rounded-3xl"
                    variants={svgVariants}
                    initial="initial"
                    animate="animate"
                    exit="exit"
                &amp;gt;
                    &amp;lt;motion.g fill-rule="evenodd" clip-rule="evenodd"&amp;gt;
                        &amp;lt;motion.path fill="#fff" d="M0 0h192.755v192.756H0V0z"
                            variants={pathOneVariants}
                        /&amp;gt;
                        &amp;lt;motion.path d="M127.986 70.51v7.505l-63.217 28.846v-7.743l54.357-24.873L64.769 49.4v-7.744l63.217 28.854zM64.769 122.25v-7.495l63.217-28.852v7.74L73.654 118.5l54.332 24.859v7.741l-63.217-28.85z"
                            variants={pathTwoVariants}
                        /&amp;gt;
                    &amp;lt;/motion.g&amp;gt;
                &amp;lt;/motion.svg&amp;gt;
            &amp;lt;/motion.div&amp;gt;
        &amp;lt;/AnimatePresence&amp;gt;
    )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here i just used a free svg I found online, framer-motion package with the variants that specify the animation on enter and on exit as well as the transition between both.&lt;/p&gt;

&lt;p&gt;Refresh your page, and on every refresh you will find the landing logo, Viola!&lt;/p&gt;

&lt;p&gt;I hope you found this article beneficial, and I advice you to look more in the docs of the great framer-motion.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>webdev</category>
      <category>animation</category>
    </item>
    <item>
      <title>How to make a self-controlled button in react</title>
      <dc:creator>Omar Elwakeel</dc:creator>
      <pubDate>Thu, 20 Jan 2022 10:18:08 +0000</pubDate>
      <link>https://dev.to/omardiaa48/how-to-make-a-self-controlled-button-in-react-26od</link>
      <guid>https://dev.to/omardiaa48/how-to-make-a-self-controlled-button-in-react-26od</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fonpih01i9mqex5wrj59z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fonpih01i9mqex5wrj59z.png" alt="Button image" width="191" height="177"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Controlling how the buttons in your app can be sometimes redundant and you find yourself writing the same code to do the same stuff many times, what if you can have your own component that can decide for itself, how to render and how to behave. &lt;/p&gt;

&lt;p&gt;In this tutorial I will show you how to have a generic button that can take care of itself according to the variables around it, like the current authenticated user and upon it decides how will it look and whether it will be enabled or disabled.&lt;/p&gt;

&lt;p&gt;For this tutorial and for the sake of having a good insight on how helpful its, I'm going to build a slightly complicated app, I will use redux for the local state management, you will know why shortly.&lt;/p&gt;

&lt;p&gt;If you want to follow along, please be my guest. But if you want to see the code you can go to the &lt;a href="https://github.com/omar-diaa-48/auth-btn" rel="noopener noreferrer"&gt;github repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;let's create an app with &lt;code&gt;create-react-app&lt;/code&gt; and name it as you like, after that we need to install some packages like &lt;code&gt;react-redux @reduxjs/toolkit&lt;/code&gt; and optionally you can install &lt;code&gt;@mui/material @mui/styles @emotion/react @emotion/styled&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Inside the src directory we can have 2 folders one for the components and the other for the redux store&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside src/store/authSlice.js&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';

export const login = createAsyncThunk(
    'app/auth/login',
    async (credentials) =&amp;gt; {
        return credentials;
    }
);

export const logout = createAsyncThunk(
    'app/auth/logout',
    async () =&amp;gt; {
        return null;
    }
);

const authSlice = createSlice({
    name: 'app/auth',
    initialState: null,
    extraReducers:{
        [login.fulfilled] : (state, action) =&amp;gt; action.payload,
        [logout.fulfilled] : (state, action) =&amp;gt; action.payload
    }
});

export default authSlice.reducer;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;inside src/store/index.js&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { combineReducers, configureStore } from '@reduxjs/toolkit';
import auth from './authSlice';

const reducer = combineReducers({
    auth
})

const store = configureStore({
    reducer,
    middleware: getDefaultMiddleware =&amp;gt;
        getDefaultMiddleware({
            immutableCheck: false,
            serializableCheck: false
        }),
    devTools: process.env.NODE_ENV === 'development'
});

export default store;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;these couple of files to configure the store for local state management, specifically the auth and current user signed in. we will wrap the application with the redux provider component and pass the store as props.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside src/App.js&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState } from "react";
import { Provider } from 'react-redux';

import store from './store/index'

import Toolbar from "./components/Toolbar";
import AuthButton from "./components/AuthButton";

function App() {
  const [auth, setAuth] = useState('');

  return (
    &amp;lt;Provider store={store}&amp;gt;
      &amp;lt;div className="App"&amp;gt;
        &amp;lt;Toolbar setAuth={setAuth}/&amp;gt;
        &amp;lt;AuthButton auth={auth}/&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/Provider&amp;gt;
  );
}

export default App;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;for the Toolbar and the AuthButton components&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside src/components/Toolbar.js&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Button, TextField } from "@mui/material";
import { makeStyles } from "@mui/styles";
import React, { useState } from "react";
import { useDispatch } from "react-redux";
import { login, logout } from "../store/authSlice";

const useStyles = makeStyles(() =&amp;gt; ({
    container:{
        display:'flex',
        justifyContent:'center',
        alignItems:'center'
    }
}))

const employees = [
    {username:'marie', role:'ceo'}, 
    {username:'jack', role:'manager'}, 
    {username:'laila', role:'employee'}, 
    {username:'sam', role:'guest'}
]

export default function Toolbar({ setAuth }){
    const classes = useStyles();
    const dispatch = useDispatch();

    const [username, setUsername] = useState('')

    const handleLogin = () =&amp;gt; {
        const credentials = employees.find(employee =&amp;gt; employee.username === username)

        if(!credentials) return;

        dispatch(login(credentials))
    }

    const handleLogout = () =&amp;gt; {
        dispatch(logout())
    }

    return (
        &amp;lt;div className={classes.container}&amp;gt;
            &amp;lt;TextField 
                onChange={(e) =&amp;gt; setUsername(e.target.value)}
            /&amp;gt;
            &amp;lt;Button onClick={(e) =&amp;gt; handleLogin()}&amp;gt;Login&amp;lt;/Button&amp;gt;
            &amp;lt;Button onClick={(e) =&amp;gt; handleLogout()}&amp;gt;Logout&amp;lt;/Button&amp;gt;
        &amp;lt;/div&amp;gt;
    )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now whenever we logout or login the button will be notified with the current authenticated user, and will fetch the role of the user and update itself, whether the color, disabled, etc.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside src/components/AuthButton.js&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react";
import { makeStyles } from "@mui/styles";
import { blue, green, orange, red } from "@mui/material/colors";
import { useSelector } from "react-redux";

const useStyles = makeStyles(() =&amp;gt; {
    return {
        btn: {
            backgroundColor:({auth}) =&amp;gt; {
                if(auth){
                    switch (auth) {
                        case "ceo":
                            return green[700]
                        case "manager":
                            return orange[700]
                        case "employee":
                            return blue[700]
                        default:
                            return red[700]
                    }
                }

                return red[700]
            },
            width:'20em',
            height:'5em',
            borderRadius:'5px',
            color:'white'
        }
    }
})

export default function AuthButton({ unauthorizedRoles }){
    const auth = useSelector(({auth}) =&amp;gt; auth);
    const classes = useStyles({auth: auth?.role || ''});

    const isDisabled = unauthorizedRoles.includes(auth?.role)

    const renderMessage = () =&amp;gt; {
        if(auth){
            if(!isDisabled){
                return `Hi, ${auth?.username} Want to do something cool`
            }
            else{
                return `Hi, ${auth?.username}, Sorry but you are not authorized for the cool stuff`
            }
        }

        return 'Why dont you login'
    }

    return (
        &amp;lt;button 
            variant="contained" 
            disabled={isDisabled} 
            className={classes.btn}
            &amp;gt;
            {renderMessage()}
        &amp;lt;/button&amp;gt;    
    )
}

AuthButton.defaultProps = {
    unauthorizedRoles : ["guest"]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;once you login or logout, the button will adjust itself accordingly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frg3rxzcjobdgogao2nn4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frg3rxzcjobdgogao2nn4.gif" alt="Result" width="360" height="203"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>webdev</category>
      <category>redux</category>
    </item>
    <item>
      <title>How to make a robust form validation in react with material ui fields.</title>
      <dc:creator>Omar Elwakeel</dc:creator>
      <pubDate>Sat, 01 Jan 2022 13:41:45 +0000</pubDate>
      <link>https://dev.to/omardiaa48/how-to-make-a-robust-form-validation-in-react-with-material-ui-fields-1kb0</link>
      <guid>https://dev.to/omardiaa48/how-to-make-a-robust-form-validation-in-react-with-material-ui-fields-1kb0</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkj4nfwxaofoo3idhrm9u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkj4nfwxaofoo3idhrm9u.png" alt="Form validation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Form validation is one of the main task that a developer mainly or a web developer specificaly faces from time to time.&lt;/p&gt;

&lt;p&gt;There are many ways to validate a form, and many modules to make use of it to help us to validate the form data.&lt;/p&gt;

&lt;p&gt;But, what I want to do, Is validating our form on our own to know what goes on under the hood packages like react-hook-form and other modules that do the same job.&lt;/p&gt;

&lt;p&gt;You can clone the code from the &lt;a href="https://github.com/omar-diaa-48/-robust-input-validation" rel="noopener noreferrer"&gt;repo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To start we need a react app, which we will have by using &lt;code&gt;npx create-react-app &amp;lt;your app name&amp;gt;&lt;/code&gt;, besides that we need to &lt;code&gt;npm install material-ui/core&lt;/code&gt;, after doing both those steps we are then ready to code.&lt;/p&gt;

&lt;p&gt;First we need to have a structure of the form, where I'm going to use material-ui helper components to build it&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

function App() {
 &amp;lt;Some code is going to be written here in the next steps for validation&amp;gt;

return (
  &amp;lt;Container className={classes.container} &amp;gt;
      &amp;lt;form noValidate onSubmit={handleSubmit} &amp;gt;
          &amp;lt;Typography 
            variant="h6"&amp;gt;
              Please enter your data
          &amp;lt;/Typography&amp;gt;

          &amp;lt;TextField 
            placeholder="Enter your name"
            label="Name"
            name="name"
            variant="outlined"
            fullWidth
            required
            className={classes.field}
            value={formValues.name.value}
            onChange={handleChange}
            error={formValues.name.error}
            helperText={formValues.name.error &amp;amp;&amp;amp; formValues.name.errorMessage}
          /&amp;gt;

          &amp;lt;TextField 
            placeholder="Enter your age"
            label="Age"
            name="age"
            variant="outlined"
            fullWidth
            required
            type="number"
            className={classes.field}
            value={formValues.age.value}
            onChange={handleChange}
            error={formValues.age.error}
            helperText={formValues.age.error &amp;amp;&amp;amp; formValues.age.errorMessage}
            /&amp;gt;

          &amp;lt;TextField 
            placeholder="Describe the best tech stack you worked with and you like most?"
            label="Likes"
            name="likes"
            variant="outlined"
            fullWidth
            required
            className={classes.field}
            value={formValues.likes.value}
            multiline
            rows={4}
            onChange={handleChange}
            error={formValues.likes.error}
            helperText={formValues.likes.error &amp;amp;&amp;amp; formValues.likes.errorMessage}
          /&amp;gt;

          &amp;lt;FormControl className={classes.field} &amp;gt;
            &amp;lt;FormLabel&amp;gt;Job title&amp;lt;/FormLabel&amp;gt;
            &amp;lt;RadioGroup name="jobTitle" value={formValues.jobTitle.value} onChange={handleChange} &amp;gt;
              &amp;lt;FormControlLabel value="full-stack" control={&amp;lt;Radio /&amp;gt;} label="Full stack" /&amp;gt;
              &amp;lt;FormControlLabel value="backend" control={&amp;lt;Radio /&amp;gt;} label="Backend" /&amp;gt;
              &amp;lt;FormControlLabel value="frontend" control={&amp;lt;Radio /&amp;gt;} label="Frontend" /&amp;gt;
            &amp;lt;/RadioGroup&amp;gt;
          &amp;lt;/FormControl&amp;gt;

          &amp;lt;Button
            type="submit"
            variant="outlined"
            color="secondary"
            endIcon={&amp;lt;KeyboardArrowRight /&amp;gt;}
          &amp;gt;
              Submit
          &amp;lt;/Button&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/Container&amp;gt;
)

}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;So, what are we missing so far? 3 things actualy like so:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Where are the classes, this is a thing that is not in out interest right now, and you can clone the code from the repo and see more about makeStyles hook&lt;/li&gt;
&lt;li&gt;handleChange function&lt;/li&gt;
&lt;li&gt;handleSubmit function&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For 2 &amp;amp; 3 we are going to discuss deeply right now, first before handling any change we need to have the form state saved.&lt;/p&gt;

&lt;p&gt;so inside our App component&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

const [formValues, setFormValues] = useState({
    name:{
      value:'',
      error:false,
      errorMessage:'You must enter a name'
    },
    age:{
      value:21,
      error:false,
      errorMessage:'You must enter an age'
    },
    likes:{
      value:'',
      error:false,
      errorMessage:'You must enter your liked tech stacks'
    },
    jobTitle:{
      value:'full-stack',
      error:false,
      errorMessage:'You must choose your job title'
    }
  })


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;where for &lt;strong&gt;every field we need to have a key that matches the name property of the field&lt;/strong&gt; and we can store the default value in it or the value that is going to be stored on input field change, also whether there is an error and maybe the error message we need to use.&lt;/p&gt;

&lt;p&gt;Then the user will start typing and we need to handle that change like so &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

const handleChange = (e) =&amp;gt; {
    const {name, value} = e.target;
    setFormValues({
      ...formValues,
      [name]:{
        ...formValues[name],
        value
      }
    })
  }


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;where we match the object inside form values by the field name, and that's why it was quite important for them to match.&lt;/p&gt;

&lt;p&gt;After the user finishes, the user of the form will try to submit it, and here comes the handleSubmit function into the game.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

const handleSubmit = (e) =&amp;gt; {
    e.preventDefault();

    const formFields = Object.keys(formValues);
    let newFormValues = {...formValues}

    for (let index = 0; index &amp;lt; formFields.length; index++) {
      const currentField = formFields[index];
      const currentValue = formValues[currentField].value;

      if(currentValue === ''){
        newFormValues = {
          ...newFormValues,
          [currentField]:{
            ...newFormValues[currentField],
            error:true
          }
        }
      }

    }

    setFormValues(newFormValues)
  }


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We get all the form fields values and check if any of them is empty, if so we destruct the old state and just replace the current one that is empty with error set to true so the TextField component show an error message.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbzjlszu7w8cxkfa9vrr9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbzjlszu7w8cxkfa9vrr9.png" alt="Errors in form"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Custom pagination decorator in Nestjs, Pagination has never been easier!!</title>
      <dc:creator>Omar Elwakeel</dc:creator>
      <pubDate>Tue, 23 Nov 2021 20:23:51 +0000</pubDate>
      <link>https://dev.to/omardiaa48/custom-pagination-decorator-in-nestjs-pagination-has-never-been-easier-3bl6</link>
      <guid>https://dev.to/omardiaa48/custom-pagination-decorator-in-nestjs-pagination-has-never-been-easier-3bl6</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgy7ohpzqyr2rvq9xu6yj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgy7ohpzqyr2rvq9xu6yj.png" alt="Pagination"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This tutorial will teach you a good way to make pagination making good use of &lt;a href="https://docs.nestjs.com/custom-decorators" rel="noopener noreferrer"&gt;Nestjs decorators&lt;/a&gt;. If you have never read about Nestjs framework, I think it's time, once you read the documentation, you would love to use it, Here you can find the &lt;a href="https://nestjs.com/" rel="noopener noreferrer"&gt;official page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's not take too much in the introduction and get along with the code!!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside terminal&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

nest new pagination-app


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;this will create a new fresh nestjs app for you, it will ask you for your favorite package module (npm, yarn, ...etc) choose whatever you prefer.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside pagination.ts (src/types/)&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

export interface Pagination {
    skip?:number;
    limit?:number;
    sort?:{ field:string, by:"ASC" | "DESC" }[];
    search?:{ field:string, value:string }[];
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here we create the pagination interface we expect from the client, these are the most important query parameters that can be sent for pagination.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside get-pagination.ts (src/decorators/)&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

import { createParamDecorator, ExecutionContext } from "@nestjs/common";
import { Request } from "express";
import { Pagination } from "../types/pagination";

export const GetPagination = createParamDecorator((data, ctx:ExecutionContext) : Pagination =&amp;gt; {
    const req : Request = ctx.switchToHttp().getRequest();

    const paginationParams : Pagination = {
        skip:0,
        limit:10,
        sort:[],
        search:[]
    };

    paginationParams.skip = req.query.skip ? parseInt(req.query.skip.toString()) : 0;
    paginationParams.limit = req.query.limit ? parseInt(req.query.limit.toString()) : 10;

    // create array of sort
    if(req.query.sort){
        const sortArray = req.query.sort.toString().split(',')
        paginationParams.sort = sortArray.map(sortItem =&amp;gt; {
            const sortBy = sortItem[0]
            switch (sortBy) {
                case "-":
                    return{
                        field:sortItem.slice(1),
                        by:'ASC'
                    }
                case "+":
                    return{
                        field:sortItem.slice(1),
                        by:'ASC'
                    }
                default:
                    return{
                        field:sortItem.trim(),
                        by:'DESC'
                    }
            }
        })
    }

    // create array of search
    if(req.query.search){
        const searchArray = req.query.search.toString().split(',')
        paginationParams.search = searchArray.map(searchItem =&amp;gt; {
            const field = searchItem.split(":")[0]
            const value = searchItem.split(":")[1]
            return {
                field,
                value
            }
        })
    }

    return paginationParams;
})


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Here we get the request from the current context, it's very the same as express request object with the same properties it had.&lt;br&gt;
*paginationParams is will contain the default values for the pagination.&lt;br&gt;
*we set the pagination skip and limit based on the query, the ternary operator to check if the limit and skip query parameters can be parsed into numbers.&lt;br&gt;
*for sort, there is many ways to have the field to sort by along with sort order, for me I use *&lt;/em&gt;+ for "DESC"** and &lt;strong&gt;- for "ASC"&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;for search, we can separate between the field and the value with a *&lt;/em&gt;:**&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside app-controller.ts (src/)&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

...
@Get('/cats')
  getCats(@GetPagination() pagination : Pagination): string {
    return this.appService.getCats(pagination);
  }
...


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;inside app-service.ts (src/)&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

...
getCats(pagination:Pagination){
    return pagination;
  }
...


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;instead of just returning it, you can have this service connected to the database and query the db according to the values you have, but for simplicity we will just log it to the console.&lt;/p&gt;

&lt;p&gt;let's try it, run the app with &lt;code&gt;npm run start:dev&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;let's hit this url &amp;gt; &lt;code&gt;http://localhost:3000/cats?skip=2&amp;amp;limit=1&amp;amp;search=name:my,age:12&amp;amp;sort=+age&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm16vluri34we2mdt3fjd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm16vluri34we2mdt3fjd.png" alt="Pagination result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you liked this tutorial, I really advice you to use Nestjs framework, and moreover go read it's documentation! &lt;/p&gt;

&lt;p&gt;Have a nice day :)&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Microservices, express-react app (Part 2) End it with the backend!</title>
      <dc:creator>Omar Elwakeel</dc:creator>
      <pubDate>Sat, 20 Nov 2021 15:34:26 +0000</pubDate>
      <link>https://dev.to/omardiaa48/microservices-express-react-app-part-2-end-it-with-the-backend-2dbo</link>
      <guid>https://dev.to/omardiaa48/microservices-express-react-app-part-2-end-it-with-the-backend-2dbo</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl0c5i7boxf5iz5ivpbt0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl0c5i7boxf5iz5ivpbt0.png" alt="Microservices" width="800" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the second article of a series of posts discussing &lt;strong&gt;Micro-services, how to use Docker, Kubernetes and make your own CI/CD Workflow to deploy your app with cool automation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/omardiaa48/micro-services-express-react-app-part-1-let-the-journey-begin-2k8k"&gt;Part 1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can clone the app from &lt;a href="https://github.com/omar-diaa-48/posts-app" rel="noopener noreferrer"&gt;here&lt;/a&gt;, or as I strongly recommend, go along step by step&lt;/p&gt;

&lt;p&gt;We previously discussed the required folder structure for the posts service, to have a complete backend we will need some authentication also, we need the user model who will be the owner of the post. I don't want this article to go long, So I will cut corners on the parts that I have covered previously.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside user.ts (posts-app/auth/models)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import mongoose from "mongoose";

interface UserAttributes {
    username:string;
    password:string;
}

interface UserDocument extends mongoose.Document{
    username:string;
    password:string;   
}

interface UserModel extends mongoose.Model&amp;lt;UserDocument&amp;gt;{
    build(attributes:UserAttributes):UserDocument;
}

const userSchema = new mongoose.Schema({
    username:{
        type:String,
        required:true,
        unique:true
    },
    password:{
        type:String,
        required:true
    }
}, {
    toJSON:{
        transform(doc, ret){
          ret.id = ret._id;
          delete ret._id;
          delete ret.password;
          delete ret.__v;
       }
    }
})


userSchema.statics.build = (attributes:UserAttributes) =&amp;gt; {
    return new User(attributes);
}

const User = mongoose.model&amp;lt;UserDocument, UserModel&amp;gt;('User', userSchema)

export default User;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;inside signup.ts (posts-app/auth/routes)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import express, { Request, Response } from 'express';
import { body } from 'express-validator';
import jwt from 'jsonwebtoken';
import { validateRequest } from '../middlewares/validate-request';
import { BadRequestError } from "../errors/bad-request-error";

import { User } from '../models/user';

const router = express.Router();

router.post(
  '/api/users/signup',
  [
    body('username').isString().withMessage('Username must be valid'),
    body('password')
      .trim()
      .isLength({ min: 4, max: 20 })
      .withMessage('Password must be between 4 and 20 characters'),
  ],
  validateRequest,
  async (req: Request, res: Response) =&amp;gt; {
    const { username, password } = req.body;

    const existingUser = await User.findOne({ username });

    if (existingUser) {
      throw new BadRequestError('Username in use');
    }

    const user = User.build({ username, password });
    await user.save();

    // Generate JWT
    const userJwt = jwt.sign(
      {
        id: user.id,
        username: user.username,
      },
      process.env.JWT_KEY!
    );

    // Store it on session object
    req.session = {
      jwt: userJwt,
    };

    res.status(201).send(user);
  }
);

export { router as signupRouter };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;inside signin.ts (posts-app/auth/routes)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import express, { Request, Response } from 'express';
import { body } from 'express-validator';
import jwt from 'jsonwebtoken';
import { validateRequest } from '../middlewares/validate-request';
import { BadRequestError } from "../errors/bad-request-error";

import { Password } from '../services/password';
import { User } from '../models/user';

const router = express.Router();

router.post(
  '/api/users/signin',
  [
    body('email').isEmail().withMessage('Email must be valid'),
    body('password')
      .trim()
      .notEmpty()
      .withMessage('You must supply a password'),
  ],
  validateRequest,
  async (req: Request, res: Response) =&amp;gt; {
    const { email, password } = req.body;

    const existingUser = await User.findOne({ email });
    if (!existingUser) {
      throw new BadRequestError('Invalid credentials');
    }

    const passwordsMatch = await Password.compare(
      existingUser.password,
      password
    );
    if (!passwordsMatch) {
      throw new BadRequestError('Invalid Credentials');
    }

    // Generate JWT
    const userJwt = jwt.sign(
      {
        id: existingUser.id,
        username: existingUser.username,
      },
      process.env.JWT_KEY!
    );

    // Store it on session object
    req.session = {
      jwt: userJwt,
    };

    res.status(200).send(existingUser);
  }
);

export { router as signinRouter };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;inside currentuser.ts (posts-app/auth/routes)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import express from 'express';
import { currentUser } from '../middlewares/current-user';

const router = express.Router();

router.get('/api/users/currentuser', currentUser, (req, res) =&amp;gt; {
  res.send({ currentUser: req.currentUser || null });
});

export { router as currentUserRouter };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now with some docker as promised, in each service (auth and posts) we create a Dockerfile&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside Dockerfile (posts-app/(posts AND auth))&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:alpine

WORKDIR /app
COPY package.json .
RUN npm install --only=prod
COPY . .

CMD ["npm", "start"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*first line we say that we need to build an image for the current service but we don't want to start from scratch, so we start it from a node js image, where alpine is the tag of that image.&lt;br&gt;
*then we specify the working directory in the newly created pod to be /app.&lt;br&gt;
*in the third step we only copy package.json into that directory.&lt;br&gt;
*we run npm install to install the required dependencies.&lt;br&gt;
*we copy everything into the working directory.&lt;br&gt;
*we run the script in the package.json responsible for running the app.&lt;/p&gt;

&lt;p&gt;we create a folder in the root directory called infra inside we create another folder called k8s which is short for Kubernetes, Kubernetes will be the master mind for the services to work all together. Inside k8s we create 5 files with extension .yaml, all as follows:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside auth-depl.yaml (posts-app/infra/k8s)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: socialapp-auth-depl
spec:
  replicas: 1
  selector:
    matchLabels:
      app: socialapp-auth
  template:
    metadata:
      labels:
        app: socialapp-auth
    spec:
      containers:
        - name: socialapp-auth
          image: omar48/socialapp-auth
          env:
            - name: MONGO_URI
              value: 'mongodb://socialapp-auth-mongo-srv:27017/socialapp-auth'
            - name: JWT_KEY
              valueFrom:
                secretKeyRef:
                  name: jwt-secret
                  key: JWT_KEY
---
apiVersion: v1
kind: Service
metadata:
  name: socialapp-auth-srv
spec:
  selector:
    app: socialapp-auth
  ports:
    - name: socialapp-auth
      protocol: TCP
      port: 3000
      targetPort: 3000

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*we specify the purpose of this configuration which will be a deployment, its name and the environment variables required as mentioned the above snippet of code. &lt;br&gt;
*The deployment needs a network service for the requests incoming, we make it in the same file, separated by the three hyphens in the middle of the file. The type is service, we specify the name and the port numbers it will listen to.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside auth-mongo-depl.yaml (posts-app/infra/k8s)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: socialapp-auth-mongo-depl
spec:
  replicas: 1
  selector:
    matchLabels:
      app: socialapp-auth-mongo
  template:
    metadata:
      labels:
        app: socialapp-auth-mongo
    spec:
      containers:
        - name: socialapp-auth-mongo
          image: mongo
---
apiVersion: v1
kind: Service
metadata:
  name: socialapp-auth-mongo-srv
spec:
  selector:
    app: socialapp-auth-mongo
  ports:
    - name: db
      protocol: TCP
      port: 27017
      targetPort: 27017
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*Microservices separates services, and puts them to work each on its own, considering the database as well. so we make a deployment for the db also for each service, we also specify the port in the service, the default for mongo is 27017&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside posts-depl.yaml (posts-app/infra/k8s)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: socialapp-posts-depl
spec:
  replicas: 1
  selector:
    matchLabels:
      app: socialapp-posts
  template:
    metadata:
      labels:
        app: socialapp-posts
    spec:
      containers:
        - name: socialapp-posts
          image: omar48/socialapp-posts
          env:
            - name: NATS_CLIENT_ID
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: NATS_URL
              value: 'http://nats-srv:4222'
            - name: NATS_CLUSTER_ID
              value: ticketing
            - name: MONGO_URI
              value: 'mongodb://socialapp-posts-mongo-srv:27017/socialapp-posts'
            - name: JWT_KEY
              valueFrom:
                secretKeyRef:
                  name: jwt-secret
                  key: JWT_KEY
---
apiVersion: v1
kind: Service
metadata:
  name: socialapp-posts-srv
spec:
  selector:
    app: socialapp-posts
  ports:
    - name: socialapp-posts
      protocol: TCP
      port: 3000
      targetPort: 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;inside posts-mongo-depl.yaml (posts-app/infra/k8s)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: socialapp-posts-mongo-depl
spec:
  replicas: 1
  selector:
    matchLabels:
      app: socialapp-posts-mongo
  template:
    metadata:
      labels:
        app: socialapp-posts-mongo
    spec:
      containers:
        - name: socialapp-posts-mongo
          image: mongo
---
apiVersion: v1
kind: Service
metadata:
  name: socialapp-posts-mongo-srv
spec:
  selector:
    app: socialapp-posts-mongo
  ports:
    - name: db
      protocol: TCP
      port: 27017
      targetPort: 27017
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For these services to communicate together we need to communication master mind to know about them, who is the master mind? Nginx so the fifth configuration file will be for ingress-nginx&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside ingress-srv.yaml (posts-app/infra/k8s)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-service
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/use-regex: 'true'
spec:
  rules:
    - host: posts.dev
      http:
        paths:
          - path: /api/posts/?(.*)
            pathType: Prefix
            backend:
              service:
                name: socialapp-posts-srv
                port: 
                  number: 3000
          - path: /api/users/?(.*)
            pathType: Prefix
            backend:
              service:
                name: socialapp-auth-srv
                port: 
                  number: 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are almost done, the last thing to do is the config file that will listen to any change that will take place inside our app.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside skaffold.yaml (posts-app)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: skaffold/v2alpha3
kind: Config
deploy:
  kubectl:
    manifests:
      - ./infra/k8s/*
build:
  local:
    push: false
  artifacts:
    - image: omar48/socialapp-auth
      context: auth
      docker:
        dockerfile: Dockerfile
      sync:
        manual:
          - src: 'src/**/*.ts'
            dest: .
    - image: omar48/socialapp-posts
      context: posts
      docker:
        dockerfile: Dockerfile
      sync:
        manual:
          - src: 'src/**/*.ts'
            dest: .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can give it a try, inside the root directory run &lt;code&gt;skaffold dev&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I hope it's working with you, in the next article, I will build the client app that will make use of this backend logic, then will use a service called NATS streaming service to communicate between services.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>docker</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Microservices, express-react app (Part 1) Let the journey begin!</title>
      <dc:creator>Omar Elwakeel</dc:creator>
      <pubDate>Sat, 13 Nov 2021 12:34:34 +0000</pubDate>
      <link>https://dev.to/omardiaa48/micro-services-express-react-app-part-1-let-the-journey-begin-2k8k</link>
      <guid>https://dev.to/omardiaa48/micro-services-express-react-app-part-1-let-the-journey-begin-2k8k</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7vjelu4dbsq8ay6rft87.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7vjelu4dbsq8ay6rft87.png" alt="Handle errors" width="221" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Micro-services, I promise! but step by step, stay with me and I promise you won't regret it!!
&lt;/h1&gt;

&lt;p&gt;This is the start of a series of posts discussing &lt;strong&gt;Micro-services, how to use Docker, Kubernetes and make your own CI/CD Workflow to deploy your app with cool automation.&lt;/strong&gt; So the title is confusing, I know!!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/omardiaa48/microservices-express-react-app-part-2-end-it-with-the-backend-2dbo"&gt;Part 2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can clone the app from &lt;a href="https://github.com/omar-diaa-48/posts-app" rel="noopener noreferrer"&gt;here&lt;/a&gt;, or as I strongly recommend, go along step by step&lt;/p&gt;

&lt;p&gt;But why not take it easy and see all the cool things we can discuss along the way, so I decided to take this big article and divide it into small articles for two reasons&lt;/p&gt;

&lt;p&gt;First to discuss all the small code features in a more focused way, and the second reason is to give you a chance to build the app with me and go along this articles smoothly.&lt;/p&gt;

&lt;p&gt;So this part will only discuss how to build a simple typescript express app, handle errors and use appropriate middlewares.&lt;/p&gt;

&lt;p&gt;If you are ready, please seat belts and let's type some code!!&lt;/p&gt;

&lt;p&gt;First make a directory with the app name, &lt;strong&gt;we are going to make a posts app&lt;/strong&gt; so folder with name posts. This directory will have all our services at the end. Here's how we want to end.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn4ywwk6uk2jtas0y8dmq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn4ywwk6uk2jtas0y8dmq.png" alt="Folder structure" width="628" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;let's setup our app structure&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside the root directory terminal (posts-app)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to initialize a git repository, after a while we will connect to our github account&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside the terminal (posts-app/posts)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init --y

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to initialize npm and generate our package.json file&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside posts service (posts-app/posts)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install express @types/express express-validator typescript ts-node-dev  mongoose 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;these are the required dependencies for now, what for ?&lt;/p&gt;

&lt;p&gt;express and @types/express for the app server instance&lt;br&gt;
express-validator for validation of request body&lt;br&gt;
typescript ts-node-dev to use typescript in code and compile on development&lt;br&gt;
mongoose for connection to db as we are going to use mongodb&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside the terminal (posts-app/posts)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tsc --init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;this will generate the tsconfig file which is responsible for the typescript configuration, you have to do it!&lt;/p&gt;

&lt;p&gt;lets create some files and folders, here how we want to end&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1wj4sef9zqgxv2oakt1c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1wj4sef9zqgxv2oakt1c.png" alt="Folder structure" width="661" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside .env (posts-app/posts)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PORT=3000
MONGO_URI=mongodb://localhost:27017/posts-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some variables we will need, port to listen to and a mongo url to use on db connection&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside app.ts (posts-app/posts)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import express, { Request, Response } from "express";
import { json } from "body-parser"
import { errorHandler } from "./middlewares/error-handler";
import { newPostRouter } from "./routes/new";

const app = express();

app.use(json())

app.use(newPostRouter)

app.all('*', (req:Request, res:Response) =&amp;gt; {
    return res.status(404).send([{message:'Not found'}])
})

app.use(errorHandler)

export default app;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*we create an app instance from express&lt;br&gt;
*use json body parser for json objects in request body to be parsed&lt;br&gt;
*we use a router which we will know about shortly&lt;br&gt;
*app.all uses a wild card to say that if the request is not handled by any of the previous handlers then return a 404 response&lt;br&gt;
*we use an error handler so any error that is thrown inside the app is handled by this handler, also we will see shortly&lt;br&gt;
*export this instance to be used in index.ts, the start of our app&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside index.ts (posts-app/posts)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import express, { Request, Response } from "express";
import app from './app'
import mongoose from "mongoose";

import dotenv from 'dotenv'
dotenv.config();

const start = async () =&amp;gt; {

    if(!process.env.MONGO_URI){
        throw new Error('MONGO_URI must be defined')
    }

    try {
        await mongoose.connect(process.env.MONGO_URI)
        console.log('Mongo db is connected');
    } catch (error) {
        console.error(error);
    }

    const port = process.env.PORT || 3000

    app.listen(port, () =&amp;gt; {
        console.log('Posts service started....');
    });

}

start();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*we use dotenv to config our variables in .env&lt;br&gt;
*we connect to db using mongoose&lt;br&gt;
*we use imported app instance to listen to the required port&lt;br&gt;
*we do all that in a start function in a modest fashion way&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside post.ts (posts-app/posts/models)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import mongoose from "mongoose";

interface PostAttributes {
    title:string;
    content:string;
    owner:string;
}

interface PostDocument extends mongoose.Document{
    title:string;
    content:string;
    owner:string;   
}

interface PostModel extends mongoose.Model&amp;lt;PostDocument&amp;gt;{
    build(attributes:PostAttributes):PostDocument;
}

const postSchema = new mongoose.Schema({
    title:{
        type:String,
        required:true
    },
    content:{
        type:String,
        required:true
    },
    owner:{
        type:String,
        required:true
    },
}, {
    timestamps:true,
    toJSON:{
        transform(doc, ret){
            ret.id = ret._id
        }
    }
})


postSchema.statics.build = (attributes:PostAttributes) =&amp;gt; {
    return new Post(attributes);
}

const Post = mongoose.model&amp;lt;PostDocument, PostModel&amp;gt;('Post', postSchema)

export default Post;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*we define the attributes used to define a post document in db &lt;br&gt;
*we define a build function to return a new post &lt;br&gt;
*we adjust some configs before export the Post model&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside error-handler.ts (posts-app/posts/middlewares)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import express, { NextFunction, Request, Response } from "express";
import { CustomError } from "../errors/custom-error";

export const errorHandler = (
    error:Error,
    req:Request,
    res:Response,
    next:NextFunction
    ) =&amp;gt; {
        if(error instanceof CustomError){
            return res.status(error.statusCode).send({errors:error.generateErrors()})
        }

        console.error(error);
        res.status(400).send({
            errors:[{message:"Something went wrong"}]
        })
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*we define a function that will be responsible for handling errors, how express will know, by convention it will search for a function that has 4 input parameters, their order is very important, the error instance comes first!! &lt;br&gt;
*we check if the error is one of the instances we will create soon or not and return the response&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside validate-request.ts (posts-app/posts/middlewares)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { NextFunction, Request, Response } from "express";
import { validationResult } from "express-validator";
import { RequestValidationError } from "../errors/request-validation-error";

export const validateRequest = (
    req:Request,
    res:Response,
    next:NextFunction
    )=&amp;gt;{
        const errors = validationResult(req);

        if(!errors.isEmpty()){
            throw new RequestValidationError(errors.array())
        }

        next();
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*we define a function that will be responsible for validating the body of the incoming request, if not valid it will throw an error that will then handled by the error handler we just created, if now it will call the next function that will pass the request to the next handler.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside custom-error.ts (posts-app/posts/errors)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export abstract class CustomError extends Error{
    abstract statusCode:number;

    constructor(message:string){
        super(message)
        Object.setPrototypeOf(this, CustomError.prototype);
    }

    abstract generateErrors():{message:string, field?:string}[];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*we define a custom error class to be extended by all the error classes we are going to use, why do so? To have a stable error response body and make it easy to catch and handle errors inside our app.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside request-validation-error.ts (posts-app/posts/errors)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { ValidationError } from "express-validator";
import { CustomError } from './custom-error'

export class RequestValidationError extends CustomError{
    statusCode = 400;
    constructor(public errors:ValidationError[]){
        super('Invalid request parameters');
        Object.setPrototypeOf(this, RequestValidationError.prototype);
    }

    generateErrors(){
        return this.errors.map(error =&amp;gt; {
            return { message:error.msg, field:error.value }
        })
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*we define an error class taking control of the validation of request body, extending the custom error class&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside new.ts (posts-app/posts/routes)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import express, { Request, Response } from "express";
import { body } from "express-validator";
import { validateRequest } from "../middlewares/validate-request";
import Post from "../models/post";

const router = express.Router();

router.post(
    '/api/posts', 
    [
        body('title').not().isEmpty().withMessage('Title must be provided').isString().withMessage('Title must be text'),
        body('content').not().isEmpty().withMessage('Content must be provided').isString().withMessage('Content must be text'),
        body('owner').not().isEmpty().withMessage('Owner of the post must be provided').isString().withMessage('Owner must be text'),
    ],
    validateRequest,
    async (req:Request, res:Response) =&amp;gt; {

    const {title, content, owner} = req.body;        

    const post = Post.build({
        title,
        content,
        owner
    });

    await post.save();

    res.status(201).send(post)
})

export {router as newPostRouter};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*we add a router instance to listen to a specific path on our app, in our case '/api/posts' and the method is POST&lt;br&gt;
*validate request using the middleware we just created, but for the middleware to work we need to let it know what to validate, so before validateRequest function we add an array of the parameters we want to validate with the set of rules &lt;br&gt;
*if not valid, again an error will be thrown and handled, if not the request will continue and reach the body of the function, where we create a post and return it to the user&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside the package.json (posts-app/posts)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
 "scripts": {
    "start": "ts-node-dev src/index",
    "test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1"
  },
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;add the start script to use it in starting the app&lt;/p&gt;

&lt;p&gt;Viola, that's it! Let's try it? Maybe POSTMAN is a good idea&lt;/p&gt;

&lt;p&gt;&lt;em&gt;inside the terminal (posts-app/posts)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go to postman and make two requests, one is valid and one is invalid and check the response, if all goes well you should get such responses&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkw5li0q152tbmu7nf35s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkw5li0q152tbmu7nf35s.png" alt="Success request" width="733" height="696"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsujblbgcj7fkvym0q0hr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsujblbgcj7fkvym0q0hr.png" alt="Fail request" width="667" height="831"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you reached this part! This is only the start, Please in the comments, I'd like to know how you think of the article length, is it too long?? and for the way of explaining is it good or I need to adjust??&lt;/p&gt;

&lt;p&gt;Your opinion will have an effect on the next part, I'll make sure of that!! I hope you liked this article and I hope we meet again in another article, remember keep the seat belt, the journey to the knowledge starts anytime :)&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>docker</category>
      <category>kubernetes</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Docker, easy start with nodejs-express app</title>
      <dc:creator>Omar Elwakeel</dc:creator>
      <pubDate>Wed, 13 Oct 2021 18:36:06 +0000</pubDate>
      <link>https://dev.to/omardiaa48/docker-easy-start-with-nodejs-express-app-part-1-1ien</link>
      <guid>https://dev.to/omardiaa48/docker-easy-start-with-nodejs-express-app-part-1-1ien</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm3mzhgiakhspdknm7fdc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm3mzhgiakhspdknm7fdc.jpg" alt="Hello Docker" width="720" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Docker, what is it? how is it beneficial? how to easily use it?
&lt;/h1&gt;

&lt;h3&gt;
  
  
  This is going to be a series of posts, this will be the first of them to explain some easy steps to start using docker containers and deploy apps with it, in this very step we are going to use &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;nodejs&lt;/a&gt; with &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;express&lt;/a&gt; framework to host a hello world app.
&lt;/h3&gt;

&lt;h3&gt;
  
  
  So what is docker?
&lt;/h3&gt;

&lt;p&gt;Docker is lovely developer tool that makes it easy to install and run software without worrying about setup and dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  How is it beneficial?
&lt;/h3&gt;

&lt;p&gt;This is because it makes containers, imagine a multi layer cake where you take a verticle slice of it, so you take from each layer a portion but you don't care about the rest of the slices. Here is an illustration for it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy5kocawlk41qq7h27grz.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy5kocawlk41qq7h27grz.JPG" alt="Docker containers" width="797" height="595"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Which makes it easy for microservices, one example that we will be seeing soon is deploying multiple services with different environemnts or maybe different versions of the very same dependency, like different nodejs versions.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to use it?
&lt;/h3&gt;

&lt;p&gt;This is my favorite part, where it's enough with the talking and we start to write some code!!&lt;/p&gt;

&lt;h5&gt;
  
  
  Pre-requirements:
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Installed &lt;strong&gt;NodeJs&lt;/strong&gt;, any version and that's what is cool with docker!!&lt;/li&gt;
&lt;li&gt;Installed &lt;strong&gt;npm&lt;/strong&gt;, which usually comes with Nodejs.&lt;/li&gt;
&lt;li&gt;Installed &lt;strong&gt;Docker&lt;/strong&gt; for windows,linux,...etc&lt;/li&gt;
&lt;li&gt;Registered &lt;strong&gt;Dockerhub account&lt;/strong&gt;, it's for free ;)
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First lets setup our server we start by initializing the folder structure&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So you get a package.json file with initial setup.&lt;/p&gt;

&lt;p&gt;now for express&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm add express
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;add the script to the scripts part in package.json&lt;br&gt;
&lt;code&gt;package.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;....
  "scripts": {
    "start": "node index.js",
  },
....
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;create index.js file in the root directory&lt;/p&gt;

&lt;p&gt;&lt;code&gt;index.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express')

const app = express()

app.get('/', (req,res) =&amp;gt; {
  res.send('Hello World!!')
})

server.listen(3000, () =&amp;gt; {
  console.log(`Listening on port 3000`);
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in the terminal type, &lt;code&gt;npm run start&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;go to the browser and hit localhost:3000 and here it's there, 'Hello world!!'&lt;/p&gt;

&lt;h4&gt;
  
  
  So Where is docker??? Here it comes in the next steps ;)
&lt;/h4&gt;

&lt;p&gt;in the root directory create a file &lt;strong&gt;with no extension with the name Dockerfile&lt;/strong&gt; with the following content&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Dockerfile&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:alpine

WORKDIR /app
COPY package.json .
RUN npm install
COPY . .

CMD ["npm", "start"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  So What is going on???
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FROM node:alpine&lt;/code&gt; -&amp;gt; is you saying to docker you want to start from an initial image that exists publicly on dockerhub, because once you go with docker you have no nodejs runtime that you have on your machine so you need this dependency.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;WORKDIR /app&lt;/code&gt; -&amp;gt; this is the work directory inside the container you are making.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;COPY package.json .&lt;/code&gt;-&amp;gt; here you are copying the package.json file to the work directory, please take notice the '.' context which means to copy in the context directory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;RUN npm install&lt;/code&gt; -&amp;gt; to install the required packages, in our case it's expressjs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;COPY . .&lt;/code&gt; -&amp;gt; here we copy everything else to the work directory, which is the source code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;CMD ["npm", "start"]&lt;/code&gt; -&amp;gt; our start script that much match the one in the package.json&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Right now you should be having a question, why did we copy twice, why not only one time at the end??
&lt;/h4&gt;

&lt;p&gt;To answer this, I need you to wait for a second an start make use of this docker image. At this moment you have an image but you cant really use it, we need to do two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build it&lt;/li&gt;
&lt;li&gt;Push it to dockerhub&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After that we can run it.&lt;/p&gt;

&lt;p&gt;So in you terminal run the following code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -t &amp;lt;your docker id&amp;gt;/&amp;lt;name of the image(eg. hello-world)&amp;gt; .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;again notice the . context&lt;/p&gt;

&lt;p&gt;now you should be seeing something like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbnwjuffjscxr9yzyv228.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbnwjuffjscxr9yzyv228.png" alt="Docker build" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;now you have this image locally, to view all your images&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker image ls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faibgoefn3lv19k94t260.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faibgoefn3lv19k94t260.png" alt="Docker images" width="800" height="216"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;now we need to make this image have its way to your hub, So in you terminal run the following code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker push &amp;lt;your docker id&amp;gt;/&amp;lt;name of the image(eg. hello-world)&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now to answer the question about copying twice in the Dockerfile configuration, this was because each command makes a layer, so we:&lt;br&gt;
1.Copy the package.json file which has all the dependencies in the project&lt;br&gt;
2.Install them using npm install&lt;br&gt;
3.We copy the rest of the files which is the code&lt;br&gt;
So whenever we make a change in the source code, only the layer that copies the code is affected and we dont install the packages again, in other words the rest of the layers are cahced.&lt;/p&gt;

&lt;p&gt;after that you can got to your docker hub after signing in and you will find it there &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0fsx477bnyg7tl1fsqh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0fsx477bnyg7tl1fsqh.png" alt="Docker hub" width="800" height="74"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Atlast, let's run this image, but notice something while running docker you can adjust the port it's listening on, so this app should be listening to &lt;strong&gt;port 3000&lt;/strong&gt;, but we can adjust the port where it should take requests from, think of it as an &lt;strong&gt;outside port&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;So in you terminal run the following code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -p 3005:3000 &amp;lt;your docker id&amp;gt;/&amp;lt;name of the image(eg. hello-world)&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Voila!!!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr2iibt7kffd89ozhpps1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr2iibt7kffd89ozhpps1.png" alt="Image running" width="251" height="74"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;go and hit &lt;code&gt;localhost:3005/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and you should be seeing the following&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnhdxwb2c3phj3ac8hmr7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnhdxwb2c3phj3ac8hmr7.png" alt="Hello world response" width="517" height="145"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  I hope you liked this post, I'm intending the post some other related posts (actually other parts of this series where we take it a bit harder and a bit more advanced), I'm a starter myself, so if you noticed anything that you recommend against, I'm happy to hear from you, Thanks again!!
&lt;/h3&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>docker</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
