<?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: Kelvin</title>
    <description>The latest articles on DEV Community by Kelvin (@vousmeevoyez).</description>
    <link>https://dev.to/vousmeevoyez</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%2F353129%2Fe4043302-8b64-4731-8fd5-06d4e8d7c120.jpg</url>
      <title>DEV Community: Kelvin</title>
      <link>https://dev.to/vousmeevoyez</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vousmeevoyez"/>
    <language>en</language>
    <item>
      <title>New Standards for the Agent-Readable Website</title>
      <dc:creator>Kelvin</dc:creator>
      <pubDate>Thu, 19 Feb 2026 00:51:25 +0000</pubDate>
      <link>https://dev.to/vousmeevoyez/new-standards-for-the-agent-readable-website-bi6</link>
      <guid>https://dev.to/vousmeevoyez/new-standards-for-the-agent-readable-website-bi6</guid>
      <description>&lt;p&gt;Saw Garry Tan’s post.&lt;/p&gt;

&lt;p&gt;Then ended up here:&lt;br&gt;&lt;br&gt;
&lt;a href="https://x.com/flynnjamm/status/2023465136204419096?s=46" rel="noopener noreferrer"&gt;https://x.com/flynnjamm/status/2023465136204419096?s=46&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And I couldn’t stop thinking about one thing:&lt;/p&gt;

&lt;p&gt;How do you sell to agents?&lt;/p&gt;

&lt;p&gt;Not humans.&lt;br&gt;&lt;br&gt;
Not people clicking blue links.&lt;br&gt;&lt;br&gt;
Agents.&lt;/p&gt;




&lt;h2&gt;
  
  
  The shift is real
&lt;/h2&gt;

&lt;p&gt;Search clicks are dropping.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gartner says traditional search volume could fall ~25% by 2026.&lt;/li&gt;
&lt;li&gt;Ahrefs saw ~34% lower CTR when Google AI Overviews show up.&lt;/li&gt;
&lt;li&gt;Publisher referrals from Google are down ~30%+ globally.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;People are getting answers without visiting sites.&lt;/p&gt;

&lt;p&gt;SEO was built for clicks.&lt;br&gt;&lt;br&gt;
Agents are built for extraction.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bots are everywhere
&lt;/h2&gt;

&lt;p&gt;AI bot traffic is up 300%+ (Akamai).&lt;/p&gt;

&lt;p&gt;More machines reading your site than humans.&lt;/p&gt;

&lt;p&gt;But your site?&lt;br&gt;&lt;br&gt;
Still written for humans.&lt;/p&gt;




&lt;h2&gt;
  
  
  The actual problem
&lt;/h2&gt;

&lt;p&gt;It’s never been easier to launch a site.&lt;/p&gt;

&lt;p&gt;It’s also never been easier to launch one agents can’t understand.&lt;/p&gt;

&lt;p&gt;We have pieces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;robots.txt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;schema.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OpenAPI&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;llms.txt&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But no unified “AI-ready” standard.&lt;/p&gt;

&lt;p&gt;No Lighthouse for agents.&lt;/p&gt;




&lt;h2&gt;
  
  
  The idea: ART
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Agent Readiness Toolkit (ART)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Think Lighthouse, but for AI discoverability.&lt;/p&gt;

&lt;p&gt;It would:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Audit how legible your site is to agents&lt;/li&gt;
&lt;li&gt;Standardize a clean “agent contract”&lt;/li&gt;
&lt;li&gt;Simulate what an LLM would extract&lt;/li&gt;
&lt;li&gt;Give you an Agent Readiness Score&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because soon:&lt;/p&gt;

&lt;p&gt;Your customer might never visit your site.&lt;br&gt;&lt;br&gt;
Your pricing page might be summarized somewhere else.&lt;br&gt;&lt;br&gt;
Your product might be recommended by a model.&lt;/p&gt;

&lt;p&gt;In that world, ranking doesn’t matter.&lt;/p&gt;

&lt;p&gt;Being extractable does.&lt;/p&gt;

&lt;p&gt;SEO shaped the last 20 years.&lt;/p&gt;

&lt;p&gt;Agent readiness might shape the next 20.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>marketing</category>
      <category>web</category>
    </item>
    <item>
      <title>Integrate Automated AI Code Reviews to Raise Quality (and Morale)</title>
      <dc:creator>Kelvin</dc:creator>
      <pubDate>Sun, 19 Oct 2025 10:16:27 +0000</pubDate>
      <link>https://dev.to/vousmeevoyez/integrate-automated-ai-code-reviews-to-raise-quality-and-morale-2l2b</link>
      <guid>https://dev.to/vousmeevoyez/integrate-automated-ai-code-reviews-to-raise-quality-and-morale-2l2b</guid>
      <description>&lt;p&gt;Manual code reviews are crucial, but they can be slow and repetitive. Automated AI reviews handle the first pass — catching logic issues, style inconsistencies, and performance risks — so human reviewers can focus on design and intent.&lt;/p&gt;




&lt;h2&gt;
  
  
  🤖 What AI Code Review Does
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Understands context&lt;/strong&gt;, not just syntax&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Goes beyond linting&lt;/strong&gt;: spots logic errors, inefficiencies, and security pitfalls&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explains suggestions&lt;/strong&gt; with inline comments and reasoning&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learns your codebase&lt;/strong&gt; over time to match your standards&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Result: faster reviews, consistent feedback, and happier developers.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Typical Workflow
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Trigger&lt;/strong&gt; – A pull request opens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analyze&lt;/strong&gt; – AI examines diffs, logic flow, and conventions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comment&lt;/strong&gt; – Inline feedback appears (e.g. readability, test coverage, security).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iterate&lt;/strong&gt; – The system adapts to your coding style and improves over time.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🧩 Integrating with Bitbucket
&lt;/h2&gt;

&lt;p&gt;You can integrate automated AI review using either &lt;strong&gt;&lt;a href="https://bitbucket.org/" rel="noopener noreferrer"&gt;Rovo Dev&lt;/a&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;a href="https://github.com/Codium-ai/pr-agent" rel="noopener noreferrer"&gt;Qodo (formerly Codium PR Agent)&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option A — Rovo Dev for Bitbucket
&lt;/h3&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%2F8570d758chiozzkkzqcf.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%2F8570d758chiozzkkzqcf.png" alt="Rovo Dev" width="800" height="624"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://bitbucket.org/" rel="noopener noreferrer"&gt;Rovo Dev&lt;/a&gt;&lt;/strong&gt; adds contextual inline comments directly in pull requests — for example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“The validation logic could be simplified by extracting the early access check into a separate condition for better readability.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These insights help maintain clarity and consistency while catching potential issues early.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setup:&lt;/strong&gt;&lt;br&gt;
Enable Rovo Dev for your Bitbucket workspace. Configure permissions so it can read pull requests and post inline comments.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Note:&lt;/strong&gt; Bitbucket currently has limited API and integration features compared to GitHub or GitLab. If your team is on those platforms, you’ll have access to richer automation hooks, inline comment threading, and workflow triggers.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h3&gt;
  
  
  Option B — Qodo PR Agent (Formerly Codium)
&lt;/h3&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%2Ffichtc4givlsgc43l3nt.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%2Ffichtc4givlsgc43l3nt.png" alt="Qodo PR Agent" width="800" height="563"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use &lt;strong&gt;&lt;a href="https://github.com/Codium-ai/pr-agent" rel="noopener noreferrer"&gt;Qodo PR Agent&lt;/a&gt;&lt;/strong&gt; for automated reviews directly inside your CI/CD workflow. It supports multiple providers including Bitbucket, GitHub, and GitLab — with the latter two offering more advanced review capabilities and analytics.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;pipelines&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull-requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;**'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;step&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;pr-agent&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PR Agent using Qodo&lt;/span&gt;
          &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker&lt;/span&gt;
          &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker run \&lt;/span&gt;
                &lt;span class="s"&gt;-e CONFIG.GIT_PROVIDER=bitbucket \&lt;/span&gt;
                &lt;span class="s"&gt;-e OPENAI.KEY=$OPENAI_API_KEY \&lt;/span&gt;
                &lt;span class="s"&gt;-e OPENAI.API_TYPE=azure \&lt;/span&gt;
                &lt;span class="s"&gt;-e OPENAI.API_VERSION=$OPEN_AI_API_VERSION \&lt;/span&gt;
                &lt;span class="s"&gt;-e OPENAI.API_BASE=$OPEN_AI_BASE \&lt;/span&gt;
                &lt;span class="s"&gt;-e CONFIG.MODEL=$MODEL \&lt;/span&gt;
                &lt;span class="s"&gt;-e BITBUCKET.BEARER_TOKEN=$BITBUCKET_BEARER_TOKEN \&lt;/span&gt;
                &lt;span class="s"&gt;codiumai/pr-agent:latest \&lt;/span&gt;
                &lt;span class="s"&gt;--pr_url=https://bitbucket.org/$BITBUCKET_WORKSPACE/$BITBUCKET_REPO_SLUG/pull-requests/$BITBUCKET_PR_ID review&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🧠 Use scoped Bitbucket tokens (read/write PRs and comments). Keep your API keys secure.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ✅ What to Automate
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Automate:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Readability and style suggestions&lt;/li&gt;
&lt;li&gt;Dead code detection&lt;/li&gt;
&lt;li&gt;Simple refactors&lt;/li&gt;
&lt;li&gt;Security or null checks&lt;/li&gt;
&lt;li&gt;Missing tests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Keep Human:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architecture and performance trade-offs&lt;/li&gt;
&lt;li&gt;API design and UX decisions&lt;/li&gt;
&lt;li&gt;Privacy and compliance issues&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧠 Tips for Effective Use
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ignore generated or vendor code&lt;/li&gt;
&lt;li&gt;Feed your &lt;strong&gt;style guides&lt;/strong&gt; and &lt;strong&gt;lint rules&lt;/strong&gt; into the model context&lt;/li&gt;
&lt;li&gt;Use PR labels to control rule sets (e.g. &lt;code&gt;security&lt;/code&gt;, &lt;code&gt;refactor&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Encourage developers to upvote/downvote AI feedback for tuning&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📈 Rollout Plan
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Week&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Goal&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Pilot on a small repo&lt;/td&gt;
&lt;td&gt;Gather noise/accuracy feedback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Tune rules and thresholds&lt;/td&gt;
&lt;td&gt;&amp;lt;10 AI comments/PR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Expand organization-wide&lt;/td&gt;
&lt;td&gt;Track metrics&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Metrics to Watch&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PR lead time ↓ 30%&lt;/li&gt;
&lt;li&gt;Post-merge fixes ↓&lt;/li&gt;
&lt;li&gt;Reviewer fatigue ↓&lt;/li&gt;
&lt;li&gt;Merge speed ↑&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧩 Example Comment
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- .refine((data) =&amp;gt; Object.values(data).includes(true), { message: 'At least one tour must be true' });
&lt;/span&gt;&lt;span class="gi"&gt;+ .refine((data) =&amp;gt; {
+   // Allow early access updates without requiring tour completion
+   if (data.earlyAccessEnabled !== undefined) { ... }
+ });
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 &lt;em&gt;“Extract the early-access check into a named condition to improve readability.”&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚠️ Common Pitfalls
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Don’t let AI merge code automatically&lt;/li&gt;
&lt;li&gt;Avoid full write access tokens&lt;/li&gt;
&lt;li&gt;Periodically retrain or tune rules&lt;/li&gt;
&lt;li&gt;Don’t ignore false positives — feed them back for model improvement&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💬 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Automated AI reviews aren’t about replacing humans — they’re about &lt;strong&gt;amplifying them&lt;/strong&gt;.&lt;br&gt;
Integrate &lt;strong&gt;&lt;a href="https://bitbucket.org/" rel="noopener noreferrer"&gt;Rovo Dev&lt;/a&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;a href="https://github.com/Codium-ai/pr-agent" rel="noopener noreferrer"&gt;Qodo (formerly Codium)&lt;/a&gt;&lt;/strong&gt; into your Bitbucket workflow to get instant, consistent feedback and spend more time writing great code instead of repetitive review comments.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 On &lt;strong&gt;GitHub&lt;/strong&gt; or &lt;strong&gt;GitLab&lt;/strong&gt;, you’ll unlock even more advanced integration options — deeper context analysis, comment threads, and richer analytics — making AI-assisted code review a seamless part of your DevOps pipeline.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;🔗 Affiliate Support&lt;/p&gt;

&lt;p&gt;Looking to collaborate or hire top independent developers?&lt;br&gt;
Join me on &lt;a href="https://contra.com/invite/kelvin_desman_boqbvhq2" rel="noopener noreferrer"&gt;Contra&lt;/a&gt;&lt;br&gt;
 — a network built for professionals who value flexibility and quality work.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Deploying cookiecutter-flask for free using pythonanywhere</title>
      <dc:creator>Kelvin</dc:creator>
      <pubDate>Mon, 18 Dec 2023 04:56:50 +0000</pubDate>
      <link>https://dev.to/vousmeevoyez/deploying-cookiecutter-flask-for-free-using-pythonanywhere-500m</link>
      <guid>https://dev.to/vousmeevoyez/deploying-cookiecutter-flask-for-free-using-pythonanywhere-500m</guid>
      <description>&lt;p&gt;Welcome! You are about to start on a journey about and how to deploy your cookiecutter-flask project for free in pythonanywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Content
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;Project&lt;/li&gt;
&lt;li&gt;
How

&lt;ul&gt;
&lt;li&gt;Setup pythonanywhere&lt;/li&gt;
&lt;li&gt;Zip project&lt;/li&gt;
&lt;li&gt;Upload project&lt;/li&gt;
&lt;li&gt;Unpack zip&lt;/li&gt;
&lt;li&gt;Install dependencies&lt;/li&gt;
&lt;li&gt;Edit WSGI&lt;/li&gt;
&lt;li&gt;Virtualenv&lt;/li&gt;
&lt;li&gt;Environment Variables&lt;/li&gt;
&lt;li&gt;Install Node.js&lt;/li&gt;
&lt;li&gt;Install Npm packages&lt;/li&gt;
&lt;li&gt;Running flask command&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Support&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;In this articles, i won't talk to much about why choose flask framework over other framework. IMHO flask good enough for most project because of lightweight and easy to scale based on our requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before jumping to how, you need to make sure you have: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flask project ready to be deployed, you can create one here &lt;a href="https://github.com/cookiecutter-flask/cookiecutter-flask" rel="noopener noreferrer"&gt;cookiecutter-flask&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pythonanywhere.com/login/?next=/pricing/" rel="noopener noreferrer"&gt;Pythonanywhere account&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Project
&lt;/h2&gt;

&lt;p&gt;For demonstration purpose i'll be using my own project that generated directly from &lt;code&gt;cookiecutter-flask&lt;/code&gt; without any modification, you can check it &lt;a href="https://github.com/vousmeevoyez/cookiecutter-flask-pythonanywhere" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How
&lt;/h2&gt;

&lt;p&gt;PythonAnywhere makes it easy to create and run Python programs in the cloud. To make it easier to understand we just treat pythonanywhere as another computer or server that we have limited access. &lt;/p&gt;

&lt;p&gt;Here are the high level step by step on how to run our flask project in pythonanywhere:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Setup pythonanywhere web application&lt;/li&gt;
&lt;li&gt;Zip the project&lt;/li&gt;
&lt;li&gt;Upload zip.&lt;/li&gt;
&lt;li&gt;Unzip project.&lt;/li&gt;
&lt;li&gt;Install dependencies&lt;/li&gt;
&lt;li&gt;Edit wsgi file&lt;/li&gt;
&lt;li&gt;Virtualenv&lt;/li&gt;
&lt;li&gt;Environment variable&lt;/li&gt;
&lt;li&gt;Broken styling + Setup node.js&lt;/li&gt;
&lt;li&gt;Execute necessary flask command.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Setup pythonanywhere &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;You need go to pythonanwhere dashboard and create web app&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%2Fjqzlbvs60l6neb6flm3z.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%2Fjqzlbvs60l6neb6flm3z.png" alt="create web app in pythonanywhere" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should seen something like this.&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%2Fdldgljl6q722fdyh43lu.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%2Fdldgljl6q722fdyh43lu.png" alt="you have no web application" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you can click add new web app&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%2F38pp33ux2bbnsdg7ugic.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%2F38pp33ux2bbnsdg7ugic.png" alt="Add new web app" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select python web framework&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%2Fcfk3aefj0ybhgjfmsbz8.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%2Fcfk3aefj0ybhgjfmsbz8.png" alt="Select python web framework" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select python version, any version would be fine i think but for this article i'll just choose python 3.10&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%2Fud45876ciji11qdssd7k.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%2Fud45876ciji11qdssd7k.png" alt="Select python version" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No specific configuration required here, pythonanwhere will automatically bootstrap the flask project in the default directory.&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%2Fzeing0n537jzuf08xars.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%2Fzeing0n537jzuf08xars.png" alt="Flask setup" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that you will be redirected to web application page &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%2Flu159ux68ax8s74c4wzn.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%2Flu159ux68ax8s74c4wzn.png" alt="web application" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now if you click the generated url you should be able to see 'hello from flask!'&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%2Fc1fehmlvp4e26qmkj11e.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%2Fc1fehmlvp4e26qmkj11e.png" alt="hello from flask" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we are ready to prepare to upload our code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Zip project &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;To make the whole project portable and easier to access in pythonanywhere server it's better to zip the project.&lt;/p&gt;

&lt;p&gt;You could do it from cli but i prefer to push all my code into github repository and download the zip from there.&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%2Fj1ezxn7w5683athq67t7.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%2Fj1ezxn7w5683athq67t7.png" alt="download zip from github" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Upload the zip &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;After we have zip file to upload we can go straight to pythonanywhere dashboard. Go to files, you will see something like this.&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%2Fsagyq24sbrxb1pvz3ybj.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%2Fsagyq24sbrxb1pvz3ybj.png" alt="files" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;you can click &lt;code&gt;mysite&lt;/code&gt; and upload your zip file from there.&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%2Fjf0x9ml3kf5p8tv8po89.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%2Fjf0x9ml3kf5p8tv8po89.png" alt="upload zip here" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After succesfully uploading your zip you will see your file in the list.&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%2Fve1bjqvzql68akarle9s.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%2Fve1bjqvzql68akarle9s.png" alt="succesfully upload the zip" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Unpack the zip &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Still in the same screen, you can click open the bash console here button. &lt;/p&gt;

&lt;p&gt;After few second you should be able to see the console screen.&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%2Flr12t8hqkihc5le7g2mk.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%2Flr12t8hqkihc5le7g2mk.png" alt="bash console" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;now we can unzip the file using the following shell command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mv cookiecutter-flask-pythonanywhere-main.zip .. 
mv flask_app.py ..
cd ..
rm -rf mysite
unzip cookiecutter-flask-pythonanywhere-main.zip
mv cookiecutter-flask-pythonanywhere-main mysite
mv flask_app.py mysite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the command above basically unzip the project into mysite directory&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%2F7yudvllyiusdt47iuoxx.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%2F7yudvllyiusdt47iuoxx.png" alt="Unzipped project" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Quick tips: ensure your website still up and showing hello from flask!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Installing dependencies &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Open bash console again and go to my site&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%2F3m0zcctt22cpmt0q9pj1.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%2F3m0zcctt22cpmt0q9pj1.png" alt="bash console" width="800" height="473"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;virtualenv venv
source venv/bin/activate
pip install -r requirements.txt 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the installation process should be downloading.&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%2Fkds3zw20sk5lhbuofkl4.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%2Fkds3zw20sk5lhbuofkl4.png" alt="Installing requirements.txt" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Edit WSGI &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Since now we have the code uploaded and python dependencies installed we can update or wsgi script to connect with our flask entrypoint file instead of the one created by pythonanywhere.&lt;/p&gt;

&lt;p&gt;You can go to your web app and click WSGI configuration file&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%2Fuy4jt7bf2dbsedvr9j25.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%2Fuy4jt7bf2dbsedvr9j25.png" alt="WSGI Configuration file" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you can comment the last line so it look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#from flask_app import app as application  # noqa
from autoapp import app as application
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can save and reload file.&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%2F56xbei9dpa35e19j982n.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%2F56xbei9dpa35e19j982n.png" alt="Edit WSGI configuration file" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;you can try access the project url, but you will receive error &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Something went wrong :-(&lt;/p&gt;
&lt;/blockquote&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%2Fjrmaqqzzajsdfy7y2cfj.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%2Fjrmaqqzzajsdfy7y2cfj.png" alt="first 500 error" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Where going to debug it in the next step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Virtualenv &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Go back to web application dashboard &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%2F3bx4m65xlomc02597o09.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%2F3bx4m65xlomc02597o09.png" alt="error log dashboard" width="800" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click error log.&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%2F1iaedvzrji7z3bhcb2fb.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%2F1iaedvzrji7z3bhcb2fb.png" alt="ModuleNotFoundError" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Looks like pythonanywhere unable to locate our installed dependencies that we install before through virtualenv&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To fix this we just need to setup virtualenv on our web application.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to web application and look for virtualenv&lt;/li&gt;
&lt;li&gt;Enter the path where we install our project dependencies through virtualenv
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/home/kelvinswarna/mysite/venv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fpy2ekd99i40lnyqwsd3v.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%2Fpy2ekd99i40lnyqwsd3v.png" alt="virtualenv" width="800" height="203"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you can try access the project website again and you should see different error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2023-12-18 03:55:01,806: Error running WSGI application
2023-12-18 03:55:01,814: environs.EnvError: Environment variable "DATABASE_URL" not set
2023-12-18 03:55:01,814:   File "/var/www/kelvinswarna_pythonanywhere_com_wsgi.py", line 16, in &amp;lt;module&amp;gt;
2023-12-18 03:55:01,814:     from autoapp import app as application
2023-12-18 03:55:01,814: 
2023-12-18 03:55:01,815:   File "/home/kelvinswarna/mysite/autoapp.py", line 5, in &amp;lt;module&amp;gt;
2023-12-18 03:55:01,815:     app = create_app()
2023-12-18 03:55:01,815: 
2023-12-18 03:55:01,815:   File "/home/kelvinswarna/mysite/cookiecutterflask/app.py", line 27, in create_app
2023-12-18 03:55:01,815:     app.config.from_object(config_object)
2023-12-18 03:55:01,815: 
2023-12-18 03:55:01,815:   File "/home/kelvinswarna/mysite/venv/lib/python3.10/site-packages/flask/config.py", line 231, in from_object
2023-12-18 03:55:01,815:     obj = import_string(obj)
2023-12-18 03:55:01,816: 
2023-12-18 03:55:01,816:   File "/home/kelvinswarna/mysite/venv/lib/python3.10/site-packages/werkzeug/utils.py", line 595, in import_string
2023-12-18 03:55:01,816:     __import__(import_name)
2023-12-18 03:55:01,816: 
2023-12-18 03:55:01,816:   File "/home/kelvinswarna/mysite/cookiecutterflask/settings.py", line 16, in &amp;lt;module&amp;gt;
2023-12-18 03:55:01,816:     SQLALCHEMY_DATABASE_URI = env.str("DATABASE_URL")
2023-12-18 03:55:01,816: 
2023-12-18 03:55:01,816:   File "/home/kelvinswarna/mysite/venv/lib/python3.10/site-packages/environs/__init__.py", line 116, in method
2023-12-18 03:55:01,816:     raise EnvError('Environment variable "{}" not set'.format(proxied_key or parsed_key))
2023-12-18 03:55:01,816: ***************************************************
2023-12-18 03:55:01,817: If you're seeing an import error and don't know why,
2023-12-18 03:55:01,817: we have a dedicated help page to help you debug: 
2023-12-18 03:55:01,817: https://help.pythonanywhere.com/pages/DebuggingImportError/
2023-12-18 03:55:01,817: ***************************************************
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's related to environment variable, where going to fix it in the next step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Environment Variable  &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;There are some things we just shouldn’t share with our code. These are often configuration values that depend on the environment such as debugging flags or access tokens for APIs. Environment variables are a good solution and they are easy to consume in most programming languages.&lt;/p&gt;

&lt;p&gt;To fix this we need open the bash console again and go to &lt;code&gt;mysite&lt;/code&gt; we have environment variable template that we can use&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cp .env.example .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fm8mcg47kuowpvsp4ecno.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%2Fm8mcg47kuowpvsp4ecno.png" alt="environment variable copied" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can try access the project website again and you should able to see the actual website now.&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%2F10yoa759wc126v1hzc8f.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%2F10yoa759wc126v1hzc8f.png" alt="Broken styling" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However the ui is not looking good since the styling is broken.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Node.js &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The cookiecutter-project is running using &lt;a href="https://github.com/nickjj/flask-static-digest" rel="noopener noreferrer"&gt;Flask-Static-Digest&lt;/a&gt; so we need node.js and webpack to generate our static asset.&lt;/p&gt;

&lt;p&gt;Luckily pythonanywhere provide some &lt;a href="https://help.pythonanywhere.com/pages/Node/" rel="noopener noreferrer"&gt;quickstart&lt;/a&gt; guide if we want to install node to our server &lt;/p&gt;

&lt;p&gt;We need open a new bash console and go to our root directory.&lt;br&gt;
Will be something look like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;04:26 ~ $ ls
README.txt  cookiecutter-flask-pythonanywhere-main.zip  mysite
04:26 ~ $ 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;now we can paste the command to download and install NVM&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone --depth 1 https://github.com/creationix/nvm.git
source ~/nvm/nvm.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our server should have access to &lt;code&gt;nvm&lt;/code&gt; and we can install node 18&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%2Ft6ssineoklv2oricffue.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%2Ft6ssineoklv2oricffue.png" alt="nvm installed" width="800" height="473"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nvm install 18
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F1wv2dpmwmjflpmzifsav.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%2F1wv2dpmwmjflpmzifsav.png" alt="install node18 using nvm" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can move on to the next step which actually install our npm packages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Npm packages &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Open a new bash console and go to &lt;code&gt;mysite&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;npm install
npm run-script build

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running flask command &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Open a new bash console and go to &lt;code&gt;mysite&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;flask db init
flask db migrate
flask db upgrade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Troubleshoot
&lt;/h2&gt;

&lt;p&gt;Coming Soon!&lt;/p&gt;

</description>
      <category>flask</category>
      <category>python</category>
      <category>cookiecutter</category>
      <category>pythonanywhere</category>
    </item>
    <item>
      <title>My first Node.js and GraphQL Course</title>
      <dc:creator>Kelvin</dc:creator>
      <pubDate>Tue, 22 Nov 2022 01:03:46 +0000</pubDate>
      <link>https://dev.to/vousmeevoyez/my-first-nodejs-and-graphql-course-39g3</link>
      <guid>https://dev.to/vousmeevoyez/my-first-nodejs-and-graphql-course-39g3</guid>
      <description>&lt;p&gt;Today, I'm delighted to announce that my first coding course, Getting started with GraphQL using Node.js officially been released and is available at Educative, Inc. I've spent a few months working on this on and off. Countless Fridays and Saturdays, here it is!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.educative.io/collection/10370001/4741596194537472" rel="noopener noreferrer"&gt;https://www.educative.io/collection/10370001/4741596194537472&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The course is a beginner-friendly introduction to backend development using #graphql and #Nodejs. It's useful for anyone who wants do the extra mile from tutorials and get their hands dirty by making something practical. The course breakdown important concepts into uncomplicated and easy-to-digest pieces, often aided by illustrations and code playground.&lt;/p&gt;

&lt;p&gt;Happy learning!&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>node</category>
      <category>codenewbie</category>
      <category>course</category>
    </item>
    <item>
      <title>Write COBOL in 2020</title>
      <dc:creator>Kelvin</dc:creator>
      <pubDate>Sat, 02 May 2020 03:11:37 +0000</pubDate>
      <link>https://dev.to/vousmeevoyez/write-cobol-in-2020-3p9c</link>
      <guid>https://dev.to/vousmeevoyez/write-cobol-in-2020-3p9c</guid>
      <description>&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;Recently i've read article about &lt;a href="https://edition.cnn.com/2020/04/08/business/coronavirus-cobol-programmers-new-jersey-trnd/index.html" rel="noopener noreferrer"&gt;Urgent need of Cobol Programmers&lt;/a&gt; in the midst of COVID-19. I've surfed the internet to know more about the language. Based on the answer from internet a lot of people said ancient language like COBOL, PASCAL is bad. I decide to found out what's writing COBOL program looks like from developer who usually wrote program using much modern language (Python or Javascript). &lt;/p&gt;

&lt;h2&gt;
  
  
  What is COBOL?
&lt;/h2&gt;

&lt;p&gt;COBOL is abbrevation for 'Common Business Oriented Language'. It was introduced since 1959 (61 Years Ago). COBOL was designed by &lt;a href="https://en.wikipedia.org/wiki/CODASYL" rel="noopener noreferrer"&gt;CODASYL&lt;/a&gt;. It was created as part of a US Department of Defense effort to create a portable programming language for data processing. In the late 1950s, computer users and manufacturers were becoming concerned about the rising cost of programming. A 1959 survey had found that in any data processing installation, the programming cost US$800,000 on average and that translating programs to run on new hardware would cost $600,000. At a time when new programming languages were proliferating at an ever-increasing rate, the same survey suggested that if a common business-oriented language were used, conversion would be far cheaper and faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evolution of COBOL
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;In 1959, COBOL was developed by CODASYL (Conference on Data Systems Language).&lt;/li&gt;
&lt;li&gt;COBOL-61 was released in 1961 with some revisions.&lt;/li&gt;
&lt;li&gt;In 1968, COBOL was approved by ANSI as a standard language for commercial use (COBOL-68).&lt;/li&gt;
&lt;li&gt;It was again revised in 1974 and 1985 to develop subsequent versions named COBOL-74 and COBOL-85 respectively.&lt;/li&gt;
&lt;li&gt;In 2002, Object-Oriented COBOL was released, which could use encapsulated objects as a normal part of COBOL programming.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where COBOL is used?
&lt;/h2&gt;

&lt;p&gt;Most of the system in US like Financial System, Social Security Administration, Department of Defense, Internal Revenue Service, the Majority of State Financial / Unemployment Systems and Numerous other Critical Systems is developed using COBOL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your first program
&lt;/h2&gt;

&lt;p&gt;I think that's enough introduction about COBOL background and history. Let's start the real code.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to install
&lt;/h3&gt;

&lt;p&gt;To run COBOL on your local machine. You need GNU-COBOL. In this article I'll be showing how to install it on Mac OS. First you need &lt;a href="https://brew.sh" rel="noopener noreferrer"&gt;homebrew&lt;/a&gt; installed. After that you can just execute&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;gnu-cobol
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To check whether the installation succeed or not, try run this command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cobc &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it should shown something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cobc (GnuCOBOL) 2.2.0
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later &amp;lt;http://gnu.org/licenses/gpl.html&amp;gt;
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Keisuke Nishida, Roger While, Ron Norman, Simon Sobisch, Edward Hart
Built     Apr 29 2020 00:06:51
Packaged  Sep 06 2017 18:48:43 UTC
C version "4.2.1 Compatible Apple LLVM 11.0.3 (clang-1103.0.32.59)"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Prepare your Text Editor
&lt;/h3&gt;

&lt;p&gt;There's few different text-editor you can use to wrote COBOL Program like, &lt;a href="https://pypi.org/project/hackedit/" rel="noopener noreferrer"&gt;HackEdit&lt;/a&gt;, &lt;a href="https://github.com/OpenCobolIDE/OpenCobolIDE" rel="noopener noreferrer"&gt;OpenCobolIDE&lt;/a&gt;, etc. For the sake of simplicity, i'll just use Visual Studio Code. &lt;/p&gt;

&lt;h3&gt;
  
  
  Install COBOL Extension
&lt;/h3&gt;

&lt;p&gt;Using Visual Studio Code you can just go to Extension Marketplace and install &lt;a href="https://github.com/spgennard/vscode_cobol" rel="noopener noreferrer"&gt;COBOL Plugin&lt;/a&gt;. The extension provide Syntax highlighting for COBOL, JCL, PL/I and MF directive files, this help us a lot understanding COBOL program.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing your first program in COBOL
&lt;/h3&gt;

&lt;p&gt;Let's write some code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;       IDENTIFICATION DIVISION.
       PROGRAM-ID. hello.
       AUTHOR. KELVIN.
       PROCEDURE DIVISION.
           DISPLAY "Hello World".
        STOP RUN.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and to run it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cobc -x hello.cob
./hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output should looks like this.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Yes, this is your Hello World program using COBOL :).&lt;/p&gt;

&lt;h2&gt;
  
  
  Program Structure
&lt;/h2&gt;

&lt;p&gt;Let's discuss about what's happening on our program. First take a look at this image.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2F3ovyg21t17l11k49tk1oma21-wpengine.netdna-ssl.com%2Fwp-content%2Fuploads%2F2018%2F02%2Ffigure-04.jpeg" 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%2F3ovyg21t17l11k49tk1oma21-wpengine.netdna-ssl.com%2Fwp-content%2Fuploads%2F2018%2F02%2Ffigure-04.jpeg" alt="cobol program structure" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A brief introduction of these image is given below −&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sections are the logical subdivision of program logic. A section is a collection of paragraphs.&lt;/li&gt;
&lt;li&gt;Paragraphs are the subdivision of a section or division. It is either a user-defined or a predefined name followed by a period, and consists of zero or more sentences/entries.&lt;/li&gt;
&lt;li&gt;Sentences are the combination of one or more statements. Sentences appear only in the Procedure division. A sentence must end with a period.&lt;/li&gt;
&lt;li&gt;Statements are meaningful COBOL statements that perform some processing.&lt;/li&gt;
&lt;li&gt;Characters are the lowest in the hierarchy and cannot be divisible.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Division
&lt;/h2&gt;
&lt;h4&gt;
  
  
  Identification Division
&lt;/h4&gt;

&lt;p&gt;First and only the mandatory division of every COBOL program. The programmer and the compiler use this division to identify the program. In this division, PROGRAM-ID is the only mandatory paragraph. PROGRAM-ID specifies the program name that can consist 1 to 30 characters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;       IDENTIFICATION DIVISION.
       PROGRAM-ID. hello.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Procedure Division
&lt;/h4&gt;

&lt;p&gt;In short, procedure division is used to include the logic of the program. It consists of executable statements that written by the progammer.&lt;br&gt;
There must be at least one statement in the procedure division. The last statement to end the execution in this division is either STOP RUN or EXIT PROGRAM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      PROCEDURE DIVISION.
           DISPLAY "Hello World".
        STOP RUN.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclussion
&lt;/h2&gt;

&lt;p&gt;I've only tried wrote simple program in COBOL and saw other people code on internet. But here's few things i found compare to language that i used nowadays.&lt;/p&gt;

&lt;p&gt;Bad Part:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A lot of reserved words, COBOL has over 300 keywords while Python only has 33 keywords. This lead to long list of reserved words to memorize.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Invent the wheel. Because there's no library concept in COBOL most of time you need to write your own libraries to do something you want. Also because of this everything is implemented as a keyword. for example when you want to support XML they introduce keywords like PARSE and RENDER.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Over-verbose syntax, when COBOL designed this kind of syntax was intended to make the code itself self documenting by using english like syntax so it readable for non-tecnical person but it ends up unmaintainable and uncomfortable for real programmer.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good Part:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Less code to type, because a lot of reserved words, you only wrote data you're going to need and logic you're going to execute.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Performance. For many years COBOL compilers have been producing very high performance executables. Only native C and native Assembler beat COBOL on an IBM mainframe.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;references:&lt;br&gt;
&lt;a href="https://softwareengineering.stackexchange.com/questions/112911/why-the-scorn-for-cobol" rel="noopener noreferrer"&gt;https://softwareengineering.stackexchange.com/questions/112911/why-the-scorn-for-cobol&lt;/a&gt;&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/COBOL#Criticism_and_defense" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/COBOL#Criticism_and_defense&lt;/a&gt;&lt;br&gt;
&lt;a href="https://devops.com/the-beauty-of-the-cobol-programming-language-v2/" rel="noopener noreferrer"&gt;https://devops.com/the-beauty-of-the-cobol-programming-language-v2/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cobol</category>
      <category>todayilearned</category>
      <category>retro</category>
    </item>
    <item>
      <title>[Python] Beautify your code using Auto-Formatter</title>
      <dc:creator>Kelvin</dc:creator>
      <pubDate>Fri, 01 May 2020 02:25:35 +0000</pubDate>
      <link>https://dev.to/vousmeevoyez/python-beautify-your-code-using-auto-formatter-2mo8</link>
      <guid>https://dev.to/vousmeevoyez/python-beautify-your-code-using-auto-formatter-2mo8</guid>
      <description>&lt;h2&gt;
  
  
  What is Code Formatting?
&lt;/h2&gt;

&lt;p&gt;Code formatting is effort to makes code easier to read by human by applying specific rules and conventions for line spacing, indents, spacing around operators, and so on &lt;a href="https://www.python.org/dev/peps/pep-0008/" rel="noopener noreferrer"&gt;see more details here&lt;/a&gt;. Formatting shouldn't affect the functionality of the code itself. &lt;/p&gt;

&lt;h2&gt;
  
  
  Linting vs Formatting?
&lt;/h2&gt;

&lt;p&gt;On the other hand, linting is made to analyzes code for common syntactical, stylistic, and functional errors as well as unconventional programming practices that can lead to errors. Although there is a little overlap between formatting and linting, the two capabilities are complementary.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Auto Formatter
&lt;/h2&gt;

&lt;p&gt;An auto formatter is a tool to automatically format your code in a way it complies to the tool or any other standard it set. Normally there's 2 option when we want to integrate this tool on our workflow. First is through your favourite text-editor and second is using pre-commit hook. In this article i will explain more about the first option which integrate auto formatter in our text-editor for better code standard. Advantage of using auto formatter are :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You don't worry about low-level problems since it's fixed automatically&lt;/li&gt;
&lt;li&gt;Reduces number of discussions or debate about code style so developer can focus writing actual code&lt;/li&gt;
&lt;li&gt;Help new developers more familiar with the code base because the style is consistent&lt;/li&gt;
&lt;li&gt;Less merge conflicts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have experience writing Golang and Javascript there's chance you're already using auto formatters like &lt;a href="https://golang.org/cmd/gofmt/" rel="noopener noreferrer"&gt;gofmt&lt;/a&gt; for Golang or &lt;a href="https://prettier.io" rel="noopener noreferrer"&gt;prettier&lt;/a&gt; for JavaScript. Now the question, how we can do the same thing in Python?&lt;/p&gt;

&lt;p&gt;In Python there are three auto-formatter available:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/hhatto/autopep8" rel="noopener noreferrer"&gt;autopep8&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;autopep8 is an open source auto formatter built and made by several developers. It uses pycodestyle to analyze which parts of your code do not fit to the pep-guidelines and will try to fix them. As of the time of writing the project had around 3.3K stars (April 2020).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/google/yapf" rel="noopener noreferrer"&gt;yapf&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Yet another Python formatter is tool produced and maintained by Google. It has ~10.5K stars (April 2020) on GitHub. Yapf follow different approach compare with other auto formatter tools.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In essence, the algorithm takes the code and reformats it to the best formatting that conforms to the style guide, even if the original code didn't violate the style guide. Style remains consistent throughout the project and there's no point arguing about style in every code review.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/psf/black" rel="noopener noreferrer"&gt;black&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The most popular auto formatter in Python. It has around ~15K stars on GitHub (April 2020). Black is loved because you don't need to configure anything in order to format your code. Javascript Prettier also follow this approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;

&lt;p&gt;In order to get started you just need to install one of package above.&lt;/p&gt;

&lt;h3&gt;
  
  
  autopep8
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install autopep8
autopep8 --in-place --aggressive --aggressive &amp;lt;filename&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  yapf
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install yapf
yapf &amp;lt;filename&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  black
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install black
black &amp;lt;filename&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What is your favourite Python Auto-Formatter?. Let me know by adding comment below :)&lt;/p&gt;

</description>
      <category>python</category>
      <category>autoformatter</category>
    </item>
    <item>
      <title>Setup (Kong + Konga) as API Gateway</title>
      <dc:creator>Kelvin</dc:creator>
      <pubDate>Thu, 09 Apr 2020 07:57:11 +0000</pubDate>
      <link>https://dev.to/vousmeevoyez/setup-kong-konga-part-2-dan</link>
      <guid>https://dev.to/vousmeevoyez/setup-kong-konga-part-2-dan</guid>
      <description>&lt;p&gt;Welcome! You are about to start on a journey about and how to setup kong as an API Gateway for your infrastructure. In this second chapter, We are going to learn how to setup Kong and Konga. By the end of this series you are going to have your Kong and Konga running.&lt;/p&gt;

&lt;h1&gt;
  
  
  Table of Content
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Api Gateway Series&lt;/li&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;Kong&lt;/li&gt;
&lt;li&gt;Konga&lt;/li&gt;
&lt;li&gt;Repository&lt;/li&gt;
&lt;li&gt;Support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this articles, i won't talk to much about why choose kong compare to another product. Tl;dr is because kong is open-source, has good community thanks to &lt;a href="https://docs.konghq.com/hub/" rel="noopener noreferrer"&gt;Kong Hub&lt;/a&gt; and it can be easily run using Docker because they have prebuilt &lt;a href="https://hub.docker.com/_/kong" rel="noopener noreferrer"&gt;image&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before jumping to how, you need to make sure you have this installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.docker.com/get-started" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;Docker Compose&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Kong
&lt;/h2&gt;

&lt;p&gt;To run kong via docker-compose we need to prepare docker-compose (Kong + DB) because we want to run kong using database. There's 2 database that currently supported by kong (PostgreSQL + Cassandra). In this articles i'm going to configure it using PostgreSQL. First let's configure Postgres services. &lt;/p&gt;

&lt;p&gt;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 postgres:9.6

COPY docker-entrypoint.sh /usr/local/bin/

ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["postgres"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're wondering why would we create our own postgres dockerfile instead directly using prebuilt images is because we need to load custom docker-entrypoint.sh which support create multiple initial user + database that later going to be used by (Kong + Konga), compare to prebuilt images where you can only create one user + one database. With this now our postgres can set environment like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;POSTGRES_USERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;username:password | username2:password&lt;/span&gt; 
 &lt;span class="na"&gt;POSTGRES_DATABASES&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dbname:username | dbname2:username2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's continue wrote our docker-compose.yml, let's create services called db and kong-migrations. In db we build from context instead of images, to make all of our container portable and prevent &lt;em&gt;hardcoded&lt;/em&gt; config we make environment to refer our own defined variable called KONG_DB_USERNAME, KONG_DB_PASSWORD, KONGA_DB_USERNAME and KONGA_DB_PASSWORD.&lt;/p&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 yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.7'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;POSTGRES_USERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONG_DB_USERNAME}:${KONG_DB_PASSWORD}|${KONGA_DB_USERNAME}:${KONGA_DB_PASSWORD}&lt;/span&gt;
          &lt;span class="na"&gt;POSTGRES_DATABASES&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONG_DB_NAME}:${KONG_DB_USERNAME}|${KONGA_DB_NAME}:${KONGA_DB_USERNAME}&lt;/span&gt;
        &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;persist_volume:/var/lib/postgresql/data&lt;/span&gt;
        &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;kong-net&lt;/span&gt;

    &lt;span class="na"&gt;kong-migrations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kong:latest&lt;/span&gt;
      &lt;span class="na"&gt;entrypoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sh -c "sleep 10 &amp;amp;&amp;amp; kong migrations bootstrap -v"&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;KONG_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONG_DATABASE}&lt;/span&gt;
        &lt;span class="na"&gt;KONG_PG_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONG_DB_HOST}&lt;/span&gt;
        &lt;span class="na"&gt;KONG_PG_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONG_DB_NAME}&lt;/span&gt;
        &lt;span class="na"&gt;KONG_PG_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONG_DB_USERNAME}&lt;/span&gt;
        &lt;span class="na"&gt;KONG_PG_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONG_DB_PASSWORD}&lt;/span&gt;
      &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db&lt;/span&gt;
      &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;kong-net&lt;/span&gt;
      &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;on-failure&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before we run the actual kong we need to run kong migrations command first. Also if you're wondering why we add sleep on entrypoint it's because i encounter some issue before when i tried to follow tutorial from &lt;a href="https://github.com/Kong/docker-kong/tree/master/compose" rel="noopener noreferrer"&gt;kong&lt;/a&gt;. Apparently this is because we tried to run migrations command but postgres container is not ready yet, to make it works i just add delay before executing migrations.&lt;/p&gt;

&lt;p&gt;Don't forget to define network and volume at bottom or top part of docker-compose&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;persist_volume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;kong-net&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before run we need to set required environment by postgres and kong&lt;/p&gt;

&lt;p&gt;.env&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# KONG SETTING&lt;/span&gt;
&lt;span class="s"&gt;KONG_DB_NAME=db_kong&lt;/span&gt;
&lt;span class="s"&gt;KONG_DB_USERNAME=konguser&lt;/span&gt;
&lt;span class="s"&gt;KONG_DB_PASSWORD=kongpassword&lt;/span&gt;
&lt;span class="s"&gt;KONG_DB_HOST=db&lt;/span&gt;
&lt;span class="s"&gt;KONG_DB_PORT=5432&lt;/span&gt;

&lt;span class="c1"&gt;# KONGA SETTING&lt;/span&gt;
&lt;span class="s"&gt;KONGA_DB_NAME=db_konga&lt;/span&gt;
&lt;span class="s"&gt;KONGA_DB_USERNAME=kongauser&lt;/span&gt;
&lt;span class="s"&gt;KONGA_DB_PASSWORD=kongapassword&lt;/span&gt;
&lt;span class="s"&gt;KONGA_DB_HOST=db&lt;/span&gt;
&lt;span class="s"&gt;KONGA_DB_PORT=5432&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can try run both container&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network create kong-net
docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's add more stuff, this time we add services called kong. &lt;br&gt;
docker-compose.yml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="na"&gt;kong&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kong:latest&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;KONG_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONG_DATABASE}&lt;/span&gt;
        &lt;span class="na"&gt;KONG_PG_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONG_DB_HOST}&lt;/span&gt;
        &lt;span class="na"&gt;KONG_PG_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONG_DB_NAME}&lt;/span&gt;
        &lt;span class="na"&gt;KONG_PG_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONG_DB_USERNAME}&lt;/span&gt;
        &lt;span class="na"&gt;KONG_PG_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONG_DB_PASSWORD}&lt;/span&gt;
        &lt;span class="na"&gt;KONG_PROXY_ACCESS_LOG&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONG_PROXY_ACCESS_LOG}&lt;/span&gt;
        &lt;span class="na"&gt;KONG_ADMIN_ACCESS_LOG&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONG_ADMIN_ACCESS_LOG}&lt;/span&gt;
        &lt;span class="na"&gt;KONG_PROXY_ERROR_LOG&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONG_PROXY_ERROR_LOG}&lt;/span&gt;
        &lt;span class="na"&gt;KONG_ADMIN_ERROR_LOG&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONG_ADMIN_ERROR_LOG}&lt;/span&gt;
        &lt;span class="c1"&gt;#KONG_ADMIN_LISTEN: ${KONG_ADMIN_LISTEN}&lt;/span&gt;
      &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;on-failure&lt;/span&gt;
      &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;$KONG_PROXY_PORT:8000&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;$KONG_PROXY_SSL_PORT:8443&lt;/span&gt;
        &lt;span class="s"&gt;#- $KONG_PROXY_ADMIN_API_PORT:8001&lt;/span&gt;
        &lt;span class="s"&gt;#- $KONG_PROXY_ADMIN_SSL_API_PORT:8444&lt;/span&gt;
      &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;kong-net&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't forget to add more variable to our environment variable&lt;br&gt;
.env&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;KONG_DATABASE=postgres&lt;/span&gt;
&lt;span class="s"&gt;KONG_PROXY_ACCESS_LOG=/dev/stdout&lt;/span&gt;
&lt;span class="s"&gt;KONG_ADMIN_ACCESS_LOG=/dev/stdout&lt;/span&gt;
&lt;span class="s"&gt;KONG_PROXY_ERROR_LOG=/dev/stderr&lt;/span&gt;
&lt;span class="s"&gt;KONG_ADMIN_ERROR_LOG=/dev/stderr&lt;/span&gt;
&lt;span class="s"&gt;KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl&lt;/span&gt;

&lt;span class="s"&gt;KONG_PROXY_PORT=8000&lt;/span&gt;
&lt;span class="s"&gt;KONG_PROXY_SSL_PORT=8443&lt;/span&gt;
&lt;span class="s"&gt;KONG_PROXY_ADMIN_API_PORT=8001&lt;/span&gt;
&lt;span class="s"&gt;KONG_PROXY_ADMIN_SSL_API_PORT=8444&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's run the whole compose (Postgres + Kong migrations + Kong)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's check our kong&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://localhost:8001/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should get some JSON response.&lt;/p&gt;

&lt;h2&gt;
  
  
  Konga
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Add Konga to Compose&lt;/li&gt;
&lt;li&gt;Setup Kong LoopBack&lt;/li&gt;
&lt;li&gt;Enable Key Auth Plugin&lt;/li&gt;
&lt;li&gt;Add Konga as Consumer&lt;/li&gt;
&lt;li&gt;Create API Key for Konga&lt;/li&gt;
&lt;li&gt;Setup Connection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some people might prefer interact with &lt;a href="https://docs.konghq.com/2.0.x/admin-api/" rel="noopener noreferrer"&gt;Kong Admin API&lt;/a&gt; through curl or Postman. But i'm more comfortable interacting through UI. &lt;a href="https://pantsel.github.io/konga/" rel="noopener noreferrer"&gt;Konga&lt;/a&gt; basically done this, they provide GUI for interacting with Kong Admin API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add Konga to Docker Compose
&lt;/h3&gt;

&lt;p&gt;To setup Konga with Kong we need few more step, first we need to add Konga in our docker-compose and later we need to configure Kong Admin LoopBack.&lt;/p&gt;

&lt;p&gt;Let's do the first step, add konga to our docker-compose.yml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="na"&gt;konga&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pantsel/konga&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;TOKEN_SECRET&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONGA_TOKEN_SECRET}&lt;/span&gt;
        &lt;span class="na"&gt;DB_ADAPTER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONG_DATABASE}&lt;/span&gt;
        &lt;span class="na"&gt;DB_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONGA_DB_HOST}&lt;/span&gt;
        &lt;span class="na"&gt;DB_PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONGA_DB_PORT}&lt;/span&gt;
        &lt;span class="na"&gt;DB_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONGA_DB_NAME}&lt;/span&gt;
        &lt;span class="na"&gt;DB_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONGA_DB_USERNAME}&lt;/span&gt;
        &lt;span class="na"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONGA_DB_PASSWORD}&lt;/span&gt;
        &lt;span class="na"&gt;NODE_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KONGA_ENV}&lt;/span&gt;
        &lt;span class="na"&gt;KONGA_HOOK_TIMEOUT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10000&lt;/span&gt;
      &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;on-failure&lt;/span&gt;
      &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;$KONGA_PORT:1337&lt;/span&gt;
      &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db&lt;/span&gt;
      &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;kong-net&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And also don't forget to add more variable to .env&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;KONGA_TOKEN_SECRET=some-secret-token
KONGA_ENV=development
KONGA_PORT=9000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After everything configured now let's run our docker-compose again&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can go to your browser and open &lt;a href="http://localhost:9000/" rel="noopener noreferrer"&gt;http://localhost:9000/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Konga would ask you to configure some credentials (Username + Password) that required to access Konga Web. After that they going to prompt how we want to communicate with Kong there's 3 available option:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Default (Not Recommended): Konga would access the Kong Admin API directly&lt;/li&gt;
&lt;li&gt;Key Auth (Recommended): Konga would access Kong Admin API that run behind Kong (Loop-Back API) using configured Api Key.&lt;/li&gt;
&lt;li&gt;JWT (Recommended): Konga would access Kong Admin API that run behind Kong (Loop-Back API) using JWT by using shared key and secrets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article i would use the second method using Key Auth. Before we setup connection let's go back to access our Kong Admin API. Currently Kong Admin API is publicly accessible for those anyone who has access to the url which is dangerous for production environment. Now we need to protect Kong Admin API by running it behind Kong using &lt;a href="https://docs.konghq.com/2.0.x/secure-admin-api/#kong-api-loopback" rel="noopener noreferrer"&gt;LoopBack&lt;/a&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Setup Kong LoopBack
&lt;/h3&gt;

&lt;p&gt;Thanks to Kong's routing design it's possible to serve Admin API itself behind Kong proxy.&lt;/p&gt;

&lt;p&gt;To configure this we need to following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add Kong Admin API as services:
You can import &lt;a href="https://github.com/vousmeevoyez/kong-konga-example/blob/master/Kong%20Admin%20API.postman_collection.json" rel="noopener noreferrer"&gt;postman collection&lt;/a&gt; that i already create before or simply copy-paste following commands:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="s1"&gt;'http://localhost:8001/services/'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--data-raw&lt;/span&gt; &lt;span class="s1"&gt;'{
    "name": "admin-api",
    "host": "localhost",
    "port": 8001
}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add Admin API route: 
To register route on Admin API Services we need either service name or service id, you can replace the following command below:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="s1"&gt;'http://localhost:8001/services/{service_id|service_name}/routes'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--data-raw&lt;/span&gt; &lt;span class="s1"&gt;'{
    "paths": ["/admin-api"]
}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our Kong Admin API is running behind Kong Proxy, so in order to access it you need to :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl localhost:8000/admin-api/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enable Key Auth Plugin
&lt;/h3&gt;

&lt;p&gt;Our Admin API already run behind kong, but is not secured yet. In order to protect Kong Admin API we need to enable key auth plugin at service level by doing this commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8001/services/&lt;span class="o"&gt;{&lt;/span&gt;service_id|service_name&lt;span class="o"&gt;}&lt;/span&gt;/plugins &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s2"&gt;"name=key-auth"&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add Konga as Consumer
&lt;/h3&gt;

&lt;p&gt;Our Admin API already run behind kong, but is not secured yet. In order to protect Kong Admin API we need to enable key auth plugin at service level by doing this commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="s1"&gt;'http://localhost:8001/consumers/'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--form&lt;/span&gt; &lt;span class="s1"&gt;'username=konga'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--form&lt;/span&gt; &lt;span class="s1"&gt;'custom_id=cebd360d-3de6-4f8f-81b2-31575fe9846a'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create API Key for Konga
&lt;/h3&gt;

&lt;p&gt;Using Consumer ID that generated when we're adding consumer, we will use that Consumer ID and generate API Key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl --location --request POST 'http://localhost:8001/consumers/e7b420e2-f200-40d0-9d1a-a0df359da56e/key-auth'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setup Connection
&lt;/h3&gt;

&lt;p&gt;Now we're already have all required component to setup Konga connection&lt;br&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%2Fbcww6nqgatixcw6ir1rd.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%2Fbcww6nqgatixcw6ir1rd.png" alt="Konga Connection" width="602" height="575"&gt;&lt;/a&gt;&lt;br&gt;
Remember in picture above, because Kong and Konga are in the same network they can simply reach each other by using container name. &lt;/p&gt;
&lt;h2&gt;
  
  
  Repository
&lt;/h2&gt;

&lt;p&gt;For those whose want simply clone it you can access this &lt;a href="https://github.com/vousmeevoyez/kong-konga-example" rel="noopener noreferrer"&gt;repository&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;For those who encounter error below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Failed to seed User Error (E_UNKNOWN) :: Encountered an unexpected error
error: relation "public.konga_users" does not exist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;this is due to failed migration of konga container, to fix this, run following instruction below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stop all containers
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose down
docker system prune --volumes ## optional!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Modify .env and look for KONGA_ENV
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;/div&gt;



&lt;p&gt;If it's configured using production, Konga will not perform db migrations which the cause of the error above. So development should work and will trigger user migration for Konga. Now you should able to access it on localhost:9000 if you still use the default configuration.&lt;br&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%2Fw6n2g84cs27vuou57q9c.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%2Fw6n2g84cs27vuou57q9c.png" alt="konga-login" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Support
&lt;/h2&gt;

&lt;p&gt;If you find my articles or project is useful please support me through:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/vousmeevoyez" rel="noopener noreferrer"&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%2Ftwve1hh3j8ewl5aowo7r.png" alt="Buy Me A Coffee" width="434" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you very much&lt;/p&gt;

&lt;h2&gt;
  
  
  Api Gateway series
&lt;/h2&gt;

&lt;p&gt;if you like to know other series please check out below:&lt;br&gt;
*&lt;a href="https://dev.to/vousmeevoyez/introduction-api-gateway-part-1-3n66"&gt;Introduction&lt;/a&gt;&lt;br&gt;
*&lt;a href="https://dev.to/vousmeevoyez/setup-kong-konga-part-2-dan#api-gateway-series"&gt;Setup Kong&lt;/a&gt; (This Articles)&lt;/p&gt;

</description>
      <category>kong</category>
      <category>docker</category>
      <category>tutorial</category>
      <category>konga</category>
    </item>
    <item>
      <title>Introduction: API Gateway (Part 1)</title>
      <dc:creator>Kelvin</dc:creator>
      <pubDate>Thu, 09 Apr 2020 01:14:23 +0000</pubDate>
      <link>https://dev.to/vousmeevoyez/introduction-api-gateway-part-1-3n66</link>
      <guid>https://dev.to/vousmeevoyez/introduction-api-gateway-part-1-3n66</guid>
      <description>&lt;p&gt;Welcome! You are about to start on a journey about and how to setup kong as an API Gateway for your infrastructure. In this first chapter, you are going to learn what and why we need API Gateway. By the end of this chapter you are going know why API Gateway is important in Microservices Architecture.&lt;/p&gt;

&lt;h1&gt;
  
  
  Table of Content
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Api Gateway Series&lt;/li&gt;
&lt;li&gt;What is API Gateway&lt;/li&gt;
&lt;li&gt;Why need API Gateway&lt;/li&gt;
&lt;li&gt;API Gateway&lt;/li&gt;
&lt;li&gt;API Gateway Solution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may have heard the terms "API Gateways" or maybe the popular api gateway solution like Tyk, Apigee, Kong or Amazon AWS API Gateway. These come up a lot nowadays because a lot of company started adopting or migrating towards microservices architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is API Gateway?
&lt;/h2&gt;

&lt;p&gt;API Gateway is middleware that sit between your client application and your server side application so all incoming request from client must be done through API Gateway. When you think about it, isn't API Gatway exactly like how reverse proxy works? Yes you could say API Gateway has some similiarity. &lt;a href="https://www.nginx.com/resources/glossary/reverse-proxy-server/" rel="noopener noreferrer"&gt;Reverse Proxy&lt;/a&gt; is responsible to routing request from client to right server but API Gateway is operating at different layer, API Gateway is responsible to routing request from client to right application / services on the server. API Gateway also have other benefit that will we discussed later.&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%2F62k3a2h49bil75qty3zc.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%2F62k3a2h49bil75qty3zc.png" alt="API Gateway" width="800" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why need API Gateway?
&lt;/h2&gt;

&lt;p&gt;Before answering this question, let's take a look at this architecture. &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbits.theorem.co%2Fimages%2Fposts%2F2015-08-24-microservices-monolith.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%2Fbits.theorem.co%2Fimages%2Fposts%2F2015-08-24-microservices-monolith.png" alt="Monolith Architecture" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
This is represent how most monolith architecture works, you have client application it can be web or mobile and then you have one server side application serve as REST API containing all business logic and connected to database. These would be fine untill you introduce another REST API.&lt;/p&gt;

&lt;p&gt;Now let's take a look another architecture. &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.wp.nginx.com%2Fwp-content%2Fuploads%2F2016%2F04%2FRichardson-microservices-part2-2_microservices-client.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%2Fcdn.wp.nginx.com%2Fwp-content%2Fuploads%2F2016%2F04%2FRichardson-microservices-part2-2_microservices-client.png" alt="Without API Gateway" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Direct Client‑to‑Microservice Communication
&lt;/h3&gt;

&lt;p&gt;In theory, a client could make requests to each of the microservices directly. Unfortunately, there are challenges and limitations with this option. &lt;/p&gt;

&lt;h4&gt;
  
  
  Inefficiency
&lt;/h4&gt;

&lt;p&gt;When you have more than one REST API, the client start getting confused because now they need to know, if they need fetch list of shopping cart they need to request it from Shopping Cart Services, and repeat the same step for another functionality. This would make client application need to execute multiple HTTP request to render certain page and also this approach make client application much more complex.&lt;/p&gt;

&lt;h4&gt;
  
  
  Protocol
&lt;/h4&gt;

&lt;p&gt;If you are working with REST API this would be fine untill you introduce server side application that use protocols that are not web‑friendly. Some might use Thrift binary RPC while another service might use the gRPC. Neither protocol is particularly web‑friendly.&lt;/p&gt;

&lt;h4&gt;
  
  
  Refactoring
&lt;/h4&gt;

&lt;p&gt;Good software is always evolve. Over time we might want to change how the system is partitioned into services. For example, we might merge two services into one or split a service into two or more services. If clients communicate directly with each services, then performing this kind of refactoring can be extremely difficult.&lt;/p&gt;

&lt;h2&gt;
  
  
  API Gateway
&lt;/h2&gt;

&lt;p&gt;To solve number of problem that might be happen using direct communication, we need a gateway.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.wp.nginx.com%2Fwp-content%2Fuploads%2F2016%2F04%2FRichardson-microservices-part2-3_api-gateway.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%2Fcdn.wp.nginx.com%2Fwp-content%2Fuploads%2F2016%2F04%2FRichardson-microservices-part2-3_api-gateway.png" alt="API Gateway" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
Now client application is communicating through API Gateway, we gain several benefit. &lt;/p&gt;

&lt;h4&gt;
  
  
  Decoupling
&lt;/h4&gt;

&lt;p&gt;By communicating through API Gateway, API gateways enable us to route based on path, hostname, headers, and other key information enabling us to decouple API used by client from actual services. With this renaming, reorganizing and splitting services is much easier especially if were dealing with client that we have no control over.&lt;/p&gt;

&lt;h4&gt;
  
  
  Performance
&lt;/h4&gt;

&lt;p&gt;Using API Gateway we gain better performance. Because instead client join data manually from multiple services, data that required by client can be aggregated by the API Gateway itself.&lt;/p&gt;

&lt;h4&gt;
  
  
  Translation
&lt;/h4&gt;

&lt;p&gt;When client request data to server through API Gateway. API Gateway will done something call protocol translation, so whatever protocol used by server (Thrift, gRPC, AMQP) it will endup translated before send to client, so client only dealing with understandable response.&lt;/p&gt;

&lt;h4&gt;
  
  
  Centralized
&lt;/h4&gt;

&lt;p&gt;Authentication Logging, Rate Limiting, CORS and many other things can easily configured at API Gateway level so underlying service doesn't need to implement their own way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Existing API Gateway Solution
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Kong
&lt;/h4&gt;

&lt;p&gt;Kong is an API gateway that is build on top of (NGINX). It has 2 type of product that is open source and enterprise. All essential features is available with the open-source version, while features like the Admin UI, Security, and developer portal only available on enterprise version.&lt;/p&gt;

&lt;h4&gt;
  
  
  Tyk.io
&lt;/h4&gt;

&lt;p&gt;Simillar with Kong, Tyk is also has open source version. Tyk is more of a batteries included API Gateway. Authentication schemes like OIDC, OAuth2, Bearer Token, Basic Auth, Mutual TLS, HMAC are all supported out of the box without requiring plugins. It also has support for XML-&amp;gt;JSON, JSON-&amp;gt;XML, JSON Schema Validation.&lt;/p&gt;

&lt;h4&gt;
  
  
  Apigee
&lt;/h4&gt;

&lt;p&gt;Oldest API Gateway listed here is Apigee. Founded in 2004 and acquired by Google in 2016. Apigee is not open source and is built on enterprise Java. Apigee focus was to turn legacy monoliths into APIs that can be consumed by third parties.&lt;/p&gt;

&lt;h4&gt;
  
  
  Amazon AWS API Gateway
&lt;/h4&gt;

&lt;p&gt;Amazon as the biggest cloud vendor provide AWS API Gateway. AWS API Gateway is fully managed and can be deployed with a few clicks in the AWS portal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Api Gateway series
&lt;/h2&gt;

&lt;p&gt;if you like to know other series please check out below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dev.to/vousmeevoyez/introduction-api-gateway-part-1-3n66"&gt;Introduction&lt;/a&gt; (This Articles)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/vousmeevoyez/setup-kong-konga-part-2-dan"&gt;Setup Kong&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tutorial</category>
      <category>microservices</category>
      <category>api</category>
      <category>infrastructure</category>
    </item>
  </channel>
</rss>
