<?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>Forem: namuan</title>
    <description>The latest articles on Forem by namuan (@namuan).</description>
    <link>https://forem.com/namuan</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%2F202419%2F92c36277-988a-46c2-8e00-2671a4f38ab4.png</url>
      <title>Forem: namuan</title>
      <link>https://forem.com/namuan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/namuan"/>
    <language>en</language>
    <item>
      <title>Bash/Zsh function to export SVG diagrams using PlantUML</title>
      <dc:creator>namuan</dc:creator>
      <pubDate>Sun, 07 Jun 2020 11:56:52 +0000</pubDate>
      <link>https://forem.com/namuan/bash-zsh-function-to-export-svg-diagrams-using-plantuml-1in9</link>
      <guid>https://forem.com/namuan/bash-zsh-function-to-export-svg-diagrams-using-plantuml-1in9</guid>
      <description>&lt;p&gt;In this short clip, we'll look at creating a simple Bash/Zsh function to export SVG diagrams using PlantUML.&lt;/p&gt;

&lt;h4&gt;
  
  
  Requirements:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;PlantUML: &lt;a href="http://sourceforge.net/projects/plantuml/files/plantuml.jar/download"&gt;Direct Download&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Place it where you can easily refer to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;nmn&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;$TOOLS_HOME&lt;/span&gt;/plantuml/plantuml.jar
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;@ 1 nmn  staff  7985304  9 Nov  2019 /Users/nmn/tools/plantuml/plantuml.jar
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, we'll create a function and put that in bash/zsh profile so that it can be loaded automatically on each session.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;plantsvg&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; | java &lt;span class="nt"&gt;-DPLANTUML_LIMIT_SIZE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8192 &lt;span class="nt"&gt;-jar&lt;/span&gt; &lt;span class="nv"&gt;$TOOLS_HOME&lt;/span&gt;/plantuml/plantuml.jar &lt;span class="nt"&gt;-tsvg&lt;/span&gt; &lt;span class="nt"&gt;-pipe&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.svg
    open &lt;span class="nt"&gt;-a&lt;/span&gt; Firefox.app &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.svg
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once you have it setup, this will export the provided plantuml file to an SVG image and open it up using Firefox.&lt;br&gt;
You can change the application used to open this SVG by replacing &lt;code&gt;Firefox.app&lt;/code&gt; with the another application.&lt;/p&gt;

&lt;p&gt;Here it is in action&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/ytSB-cjAKzA"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;📝:&lt;/p&gt;

&lt;p&gt;👉 Tested on MacOS but should work on earlier versions and all flavours of Linux&lt;/p&gt;

</description>
      <category>plantuml</category>
      <category>svg</category>
      <category>bash</category>
    </item>
    <item>
      <title>Handy Bash/Zsh function to generate PlantUML diagrams</title>
      <dc:creator>namuan</dc:creator>
      <pubDate>Sat, 06 Jun 2020 20:56:11 +0000</pubDate>
      <link>https://forem.com/namuan/handy-bash-zsh-function-to-generate-plantuml-diagrams-4l3g</link>
      <guid>https://forem.com/namuan/handy-bash-zsh-function-to-generate-plantuml-diagrams-4l3g</guid>
      <description>&lt;p&gt;In this short clip, we'll look at creating a simple Bash/Zsh function wrapping PlantUML so that we can use it from anywhere.&lt;/p&gt;

&lt;h4&gt;
  
  
  Requirements:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;PlantUML: &lt;a href="http://sourceforge.net/projects/plantuml/files/plantuml.jar/download"&gt;Direct Download&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Download it where you can easily refer to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;nmn&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;$TOOLS_HOME&lt;/span&gt;/plantuml/plantuml.jar
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;@ 1 nmn  staff  7985304  9 Nov  2019 /Users/nmn/tools/plantuml/plantuml.jar
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, we'll create a function and put that in bash/zsh profile so that it can be loaded automatically on each session.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;plantuml&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
    &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="nv"&gt;$NAME&lt;/span&gt; | java &lt;span class="nt"&gt;-DPLANTUML_LIMIT_SIZE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8192 &lt;span class="nt"&gt;-jar&lt;/span&gt; &lt;span class="nv"&gt;$TOOLS_HOME&lt;/span&gt;/plantuml/plantuml.jar &lt;span class="nt"&gt;-pipe&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$NAME&lt;/span&gt;.png
    open &lt;span class="nv"&gt;$NAME&lt;/span&gt;.png
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then you can call this function with the file name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;plantuml sample.png
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once you have it setup, this will convert the provided plantuml file to a PNG image and open it up using the default PNG viewer.&lt;/p&gt;

&lt;p&gt;Here it is in action&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Wy02jNNkhIE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;📝:&lt;/p&gt;

&lt;p&gt;👉 Tested on MacOS but should work on earlier versions and all flavours of Linux&lt;/p&gt;

</description>
      <category>tooltips</category>
      <category>plantuml</category>
      <category>bash</category>
    </item>
    <item>
      <title>Using EasyRandom with Spring Framework</title>
      <dc:creator>namuan</dc:creator>
      <pubDate>Sat, 06 Jun 2020 20:52:08 +0000</pubDate>
      <link>https://forem.com/namuan/using-easyrandom-with-spring-framework-1pnf</link>
      <guid>https://forem.com/namuan/using-easyrandom-with-spring-framework-1pnf</guid>
      <description>&lt;p&gt;Tired of creating objects in tests. Try using EasyRandom library. Here is how easily you can add it to a Spring Java project&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Add gradle/maven dependency
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://mvnrepository.com/artifact/org.jeasy/easy-random"&gt;https://mvnrepository.com/artifact/org.jeasy/easy-random&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_1YMwxxJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.deskriders.dev/images/20200514225404481_20190134.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_1YMwxxJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.deskriders.dev/images/20200514225404481_20190134.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2: Declare it in test
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aTI8LYWG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.deskriders.dev/images/20200514230728850_1337135243.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aTI8LYWG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.deskriders.dev/images/20200514230728850_1337135243.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3: Use it to generate random data objects
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EtkWLNN4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.deskriders.dev/images/20200514230800345_1963146893.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EtkWLNN4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.deskriders.dev/images/20200514230800345_1963146893.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 4: 😍
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b4Qq9Pdf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.deskriders.dev/images/20200514230639150_1516619298.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b4Qq9Pdf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.deskriders.dev/images/20200514230639150_1516619298.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Tips:
&lt;/h4&gt;

&lt;h4&gt;
  
  
  Random initial seed
&lt;/h4&gt;

&lt;p&gt;In the default setup, EasyRandom uses a default seed value to generate randam data.&lt;br&gt;
Although it is quite simple to initiate EasyRandom with a random seed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--e-WB7brE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.deskriders.dev/images/20200514231839075_671078143.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--e-WB7brE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.deskriders.dev/images/20200514231839075_671078143.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Enforcing javax.validation rules:
&lt;/h4&gt;

&lt;p&gt;If an object is using javax.validation then there is an extension which enforces those rules when generating random objects.&lt;/p&gt;

&lt;p&gt;Include &lt;a href="https://github.com/j-easy/easy-random/wiki/bean-validation-support"&gt;https://github.com/j-easy/easy-random/wiki/bean-validation-support&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AB4m5ZaJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.deskriders.dev/images/20200514232418213_226235357.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AB4m5ZaJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.deskriders.dev/images/20200514232418213_226235357.png" alt=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_KvS1YPg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.deskriders.dev/images/20200514232450020_1291589909.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_KvS1YPg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.deskriders.dev/images/20200514232450020_1291589909.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Github: &lt;a href="https://github.com/namuan/dev-rider-codesnippets/tree/master/spring-boot-snippets"&gt;https://github.com/namuan/dev-rider-codesnippets/tree/master/spring-boot-snippets&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>springframework</category>
    </item>
    <item>
      <title>January 2020 Progress Report</title>
      <dc:creator>namuan</dc:creator>
      <pubDate>Mon, 03 Feb 2020 17:59:42 +0000</pubDate>
      <link>https://forem.com/namuan/january-2020-progress-report-5fbe</link>
      <guid>https://forem.com/namuan/january-2020-progress-report-5fbe</guid>
      <description>&lt;p&gt;Hopefully first of many as January was the most productive month in terms of Github commits. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MfA884jT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.deskriders.dev/images/022/jan2020-github.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MfA884jT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.deskriders.dev/images/022/jan2020-github.png" alt="Github"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a brief summary of the things&lt;/p&gt;

&lt;p&gt;🚀 Started &lt;a href="https://www.deskriders.dev/projects/dev-rider/"&gt;DevRider&lt;/a&gt;. Please consider contributing if you are interested in Python and PyQt. Contributions for other languages needed as well. See &lt;a href="https://www.deskriders.dev/posts/010-introducing-devrider/"&gt;this&lt;/a&gt; post on my motivation behind building it.&lt;/p&gt;

&lt;p&gt;🚀 Created Windows Release Package for &lt;a href="https://www.httprider.com"&gt;HttpRider&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🚀 Started &lt;a href="https://mindbooks.club"&gt;MindBooks&lt;/a&gt; - A collection of thought provoking books.&lt;/p&gt;

&lt;p&gt;🚀 Started new series on Tooltips (Currently posting on twitter but website coming soon)&lt;/p&gt;

&lt;p&gt;February Goals:&lt;/p&gt;

&lt;p&gt;📝 Add links to MindBook to buy books&lt;/p&gt;

&lt;p&gt;📝 Promote Mindbooks on ProductHunt, IndieHackers and other channels&lt;/p&gt;

&lt;p&gt;📝 Publish around 30 tooltips&lt;/p&gt;

&lt;p&gt;📝 Move tooltips to its own website&lt;/p&gt;

&lt;p&gt;I usually post more frequently on &lt;a href="https://twitter.com/deskriders_twt"&gt;https://twitter.com/deskriders_twt&lt;/a&gt; so please consider following there for updates 🙏&lt;/p&gt;

</description>
      <category>motivation</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Simple setup to remember one-liners/code snippets</title>
      <dc:creator>namuan</dc:creator>
      <pubDate>Mon, 27 Jan 2020 10:43:04 +0000</pubDate>
      <link>https://forem.com/namuan/simple-setup-to-remember-one-liners-code-snippets-986</link>
      <guid>https://forem.com/namuan/simple-setup-to-remember-one-liners-code-snippets-986</guid>
      <description>&lt;p&gt;Here is a simple setup explaining a comment I made on &lt;a href="https://www.reddit.com/r/datascience/comments/euad2v/how_do_you_make_sure_a_tool_you_learned_in_the/ffo9bvt"&gt;Reddit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6kIlIahQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/omjttnhmwdd0fsk4zztf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6kIlIahQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/omjttnhmwdd0fsk4zztf.png" alt="Notes file"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All I have is a notes.txt under my home directory where the snippets (one-liners) are stored in the following format. &lt;br&gt;
Note that I don't store block of code or longer text here as they'll become difficult to search.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;find . -type f -name '*.txt' -exec sed -i '' s/this/that/g {} + # search and replace sed find
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It starts with the command then # and a brief comment on what it does.&lt;/p&gt;

&lt;p&gt;The notes.txt file is just a soft link to a file stored in a Dropbox shared folder so that it can be synced across devices.&lt;/p&gt;

&lt;p&gt;Here are a couple of bash helpers to work with the notes file.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;fnote&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;fnote=find note&lt;/p&gt;

&lt;p&gt;A simple function defined in a bash profile to search within the notes file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function fnote() { grep "$@" ~/notes.txt }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then I can do the following to filter out any lines.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ fnote epoch
*  date +%s # epoch time
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;en&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;en=edit notes&lt;/p&gt;

&lt;p&gt;A bash alias to open up notes.txt file in your favourite editor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alias en='code ~/notes.txt'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then just typing &lt;code&gt;en&lt;/code&gt; will open up the notes.txt file for me to edit.&lt;/p&gt;

&lt;p&gt;So, that's it. Pretty simple but very effective.&lt;/p&gt;

&lt;p&gt;Let me know what you think and share if you have anything similar in your daily workflow.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>discuss</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Introducing DevRider :: One Desktop App for Common Development Tools</title>
      <dc:creator>namuan</dc:creator>
      <pubDate>Sun, 26 Jan 2020 10:14:04 +0000</pubDate>
      <link>https://forem.com/namuan/introducing-devrider-one-desktop-app-for-common-development-tools-3nkd</link>
      <guid>https://forem.com/namuan/introducing-devrider-one-desktop-app-for-common-development-tools-3nkd</guid>
      <description>&lt;p&gt;There is a serious problem with the state of simple development tools on the internet. &lt;/p&gt;

&lt;p&gt;Most of the websites providing simple encoders/decoders/formatters/prettifiers are filled with ads and popups which makes it annoying and risky to use. &lt;/p&gt;

&lt;p&gt;And then there is also a huge problem with privacy and leaking any private data that is used on any of these websites.&lt;/p&gt;

&lt;p&gt;Although it is impossible to replace them altogether, let me introduce you to &lt;a href="https://www.deskriders.dev/projects/dev-rider/"&gt;DevRider&lt;/a&gt;, a new open source to provide some of the common tools in an extensible desktop application. &lt;/p&gt;

&lt;p&gt;Which means no tracking and it guarantees data safety as everything stays on your machine.&lt;/p&gt;

&lt;p&gt;Along with these tools, there is also a curated code snippets repository with multiple supported languages. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VPrxSyoQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/hl27b7dj5anlyhpd6avl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VPrxSyoQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/hl27b7dj5anlyhpd6avl.gif" alt="DevRider Demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please checkout the &lt;a href="https://www.deskriders.dev/projects/dev-rider/"&gt;project page&lt;/a&gt; to download application package for Mac or Windows.&lt;/p&gt;

&lt;h5&gt;
  
  
  🚨 Call for Help 🚨
&lt;/h5&gt;

&lt;p&gt;The list of things that we can add is huge so appreciate anyone willing to contribute. I'm available to guide you through the application architecture and what is involved in making appropriate changes. Hopefully we'll learn something useful in the process 🙌.&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Add more languages for code snippets&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;DevRider supports curated code snippets for a tool. For eg, if you are using Base64 Encoder then it'll show you the source code to do base64 encoding in different languages.&lt;/p&gt;

&lt;p&gt;So if you are looking to learn a new language then please don't hesitate to provide code samples for some of the tools already exists.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://github.com/namuan/dev-rider/issues"&gt;https://github.com/namuan/dev-rider/issues&lt;/a&gt; for picking up a task as a first time contributor.&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Add more tools&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you are thinking about learning Python/PyQt then consider adding a new tool. Here is a page where I described the process of adding a Markdown Viewer &lt;a href="https://github.com/namuan/dev-rider/blob/master/docs/devrider-adding-tool.md"&gt;https://github.com/namuan/dev-rider/blob/master/docs/devrider-adding-tool.md&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also see the current list &lt;a href="https://github.com/namuan/dev-rider/blob/master/docs/more-tools.md"&gt;here&lt;/a&gt; but you are welcome to add anything missing from that list.&lt;/p&gt;

&lt;p&gt;Please like the &lt;a href="https://github.com/namuan/dev-rider"&gt;Github Project&lt;/a&gt; and follow &lt;a href="https://twitter.com/deskriders_twt/"&gt;https://twitter.com/deskriders_twt/&lt;/a&gt; for development updates and spreading the word out.&lt;/p&gt;

</description>
      <category>python</category>
      <category>utilities</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Percent/URI Encoding - Step by Step example</title>
      <dc:creator>namuan</dc:creator>
      <pubDate>Tue, 21 Jan 2020 12:10:22 +0000</pubDate>
      <link>https://forem.com/namuan/percent-uri-encoding-step-by-step-example-31g3</link>
      <guid>https://forem.com/namuan/percent-uri-encoding-step-by-step-example-31g3</guid>
      <description>&lt;p&gt;Percent encoding is used to encode some reserved characters in the URI. See &lt;a href="https://en.wikipedia.org/wiki/Percent-encoding"&gt;Wikipedia&lt;/a&gt; for more details. &lt;/p&gt;

&lt;p&gt;As part of adding URL encoder in &lt;a href="https://github.com/namuan/dev-rider"&gt;DevRider&lt;/a&gt;, I put together some notes which may be useful for others so publishing it here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jCWDJRZt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/uj3y0942ebldp864k6dl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jCWDJRZt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/uj3y0942ebldp864k6dl.png" alt="DevRider URL Encoder"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here we'll take a single character &lt;code&gt;:&lt;/code&gt; and convert it to &lt;code&gt;%3A&lt;/code&gt; which is the equivalent encoded character. This is a very simple example and don't cover unicode characters but it is similar in principle.&lt;/p&gt;

&lt;p&gt;We start with finding the ASCII value of &lt;code&gt;:&lt;/code&gt; which is &lt;code&gt;58&lt;/code&gt;. &lt;br&gt;
See &lt;a href="https://theasciicode.com.ar/ascii-printable-characters/colon-ascii-code-58.html"&gt;ASCII table&lt;/a&gt; for the mapping table.&lt;/p&gt;

&lt;p&gt;Convert &lt;code&gt;58&lt;/code&gt; to binary using Short division by Two with Reminder. &lt;br&gt;
i.e. Divide the answer by &lt;code&gt;2&lt;/code&gt; and keeping the reminder aside which will become the binary form.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;58/2 = 29 =&amp;gt; Reminder 0
29/2 = 14 =&amp;gt; Reminder 1
14/2 = 7  =&amp;gt; Reminder 0
7/2  = 3  =&amp;gt; Reminder 1
3/2  = 1  =&amp;gt; Reminder 1
1/2  = na =&amp;gt; Reminder 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So the binary form is &lt;code&gt;111010&lt;/code&gt; if we line up all the reminders.&lt;br&gt;
Padding the output will make it &lt;code&gt;00111010&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, we split the binary into two parts of 4 bits each.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;0011&lt;/code&gt; &lt;code&gt;1010&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then using the following Hex table conversion, we map &lt;code&gt;0011&lt;/code&gt; =&amp;gt; 3 and &lt;code&gt;1010&lt;/code&gt; to A which becomes &lt;code&gt;3A&lt;/code&gt;. &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Decimal&lt;/th&gt;
&lt;th&gt;Binary&lt;/th&gt;
&lt;th&gt;Hex&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;0001&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0010&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;0011&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0100&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;0101&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;0110&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;0111&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;1001&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;1010&lt;/td&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;1011&lt;/td&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;1100&lt;/td&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;1101&lt;/td&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;1110&lt;/td&gt;
&lt;td&gt;E&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;1111&lt;/td&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The final part is to prefix it with &lt;code&gt;%&lt;/code&gt; (which is the escape character) making it &lt;code&gt;%3A&lt;/code&gt; which is the output we are expecting. 🎉&lt;/p&gt;

</description>
      <category>tutorial</category>
    </item>
    <item>
      <title>Overlay button on a PyQt5 widget</title>
      <dc:creator>namuan</dc:creator>
      <pubDate>Thu, 02 Jan 2020 10:33:51 +0000</pubDate>
      <link>https://forem.com/namuan/overlay-button-on-a-pyqt5-widget-572c</link>
      <guid>https://forem.com/namuan/overlay-button-on-a-pyqt5-widget-572c</guid>
      <description>&lt;p&gt;This is a short post on how to add a floating button on top of a widget in PyQt5.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F6tpq07fmmwo1rt4gadry.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F6tpq07fmmwo1rt4gadry.gif" alt="pyqt5_floating_widget"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, we'll define the button and the relative positioning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FloatingButtonWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QtWidgets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QPushButton&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="c1"&gt;#1
&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paddingLeft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paddingTop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_position&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;viewport&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;parent_rect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;viewport&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;parent_rect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;parent_rect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;

        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parent_rect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;width&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;width&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paddingLeft&lt;/span&gt;
        &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paddingTop&lt;/span&gt; &lt;span class="c1"&gt;#3
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setGeometry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;width&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;height&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;resizeEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="c1"&gt;#2
&lt;/span&gt;        &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;resizeEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_position&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;mousePressEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="c1"&gt;#4
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;floatingButtonClicked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Inheriting from QPushButton.&lt;/li&gt;
&lt;li&gt;Overriding &lt;code&gt;resizeEvent&lt;/code&gt; and updating position of the this button based on the parent position.&lt;/li&gt;
&lt;li&gt;This will add the button to the top. If you need to place it at the button then use something like &lt;code&gt;parent_rect.height() - self.paddingLeft&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Catching the mouse pressed event and calling an signal on the parent widget.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With the button defined, we'll embed it in a custom &lt;code&gt;QPlainTextEdit&lt;/code&gt; and define appropriate interfaces for the caller to work with the floating button.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OverlayedPlainTextEdit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QtWidgets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QPlainTextEdit&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="c1"&gt;#1
&lt;/span&gt;    &lt;span class="n"&gt;floatingButtonClicked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pyqtSignal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;#2
&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;floating_button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FloatingButtonWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_floating_button_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;txt&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;floating_button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#3
&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;resizeEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;resizeEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;floating_button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_position&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;#4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Inheriting from QPlainTextEdit although this could be any widget.&lt;/li&gt;
&lt;li&gt;Defining a custom signal which is triggered when a mouse pressed event is captured in the floating button as we saw earlier.&lt;/li&gt;
&lt;li&gt;Updating the text of the button which we'll see later.&lt;/li&gt;
&lt;li&gt;Overriding &lt;code&gt;resizeEvent&lt;/code&gt; so that we can update the position of the floating button.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now we can use this class instead of &lt;code&gt;QPlainTextEdit&lt;/code&gt; and update the floating button.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plainTextEdit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;floatingButtonClicked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;on_test&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plainTextEdit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_floating_button_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Edit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is it. Here is the full source code. &lt;a href="https://gist.github.com/namuan/e34387e53e62b52c6aea2146108a92c7" rel="noopener noreferrer"&gt;Github Gist&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;PyQt5&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;QtCore&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;PyQt5&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;QtWidgets&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FloatingButtonWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QtWidgets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QPushButton&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paddingLeft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paddingTop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_position&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;viewport&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;parent_rect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;viewport&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;parent_rect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;parent_rect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;

        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parent_rect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;width&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;width&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paddingLeft&lt;/span&gt;
        &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paddingTop&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setGeometry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;width&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;height&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;resizeEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;resizeEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_position&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;mousePressEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;floatingButtonClicked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OverlayedPlainTextEdit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QtWidgets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QPlainTextEdit&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;floatingButtonClicked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pyqtSignal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;floating_button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FloatingButtonWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_floating_button_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;txt&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;floating_button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;resizeEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;resizeEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;floating_button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_position&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="c1"&gt;# NOTE: This class is generated from QtDesigner
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Ui_DebugWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setupUi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DebugWindow&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;DebugWindow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setObjectName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DebugWindow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;DebugWindow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;622&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;498&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;centralwidget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtWidgets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;QWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DebugWindow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;centralwidget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setObjectName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;centralwidget&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verticalLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtWidgets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;QVBoxLayout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;centralwidget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verticalLayout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setObjectName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verticalLayout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plainTextEdit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OverlayedPlainTextEdit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;centralwidget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plainTextEdit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setObjectName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;plainTextEdit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verticalLayout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plainTextEdit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;DebugWindow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setCentralWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;centralwidget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;menubar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtWidgets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;QMenuBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DebugWindow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;menubar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setGeometry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;QRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;622&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;menubar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setObjectName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;menubar&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;DebugWindow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setMenuBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;menubar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statusbar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtWidgets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;QStatusBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DebugWindow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statusbar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setObjectName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statusbar&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;DebugWindow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setStatusBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statusbar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;retranslateUi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DebugWindow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QMetaObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connectSlotsByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DebugWindow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;retranslateUi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DebugWindow&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;_translate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QCoreApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;translate&lt;/span&gt;
        &lt;span class="n"&gt;DebugWindow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setWindowTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;_translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DebugWindow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MainWindow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DebugWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QtWidgets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QMainWindow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Ui_DebugWindow&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;edit_mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DebugWindow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setupUi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# ui events
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plainTextEdit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;floatingButtonClicked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;on_test&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_floating_button_text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;edit_mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;edit_mode&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plainTextEdit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendPlainText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Button Clicked - Mode: {}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Edit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;edit_mode&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Preview&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_floating_button_text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_floating_button_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;edit_mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plainTextEdit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_floating_button_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Edit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plainTextEdit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_floating_button_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Preview&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtWidgets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;QApplication&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;
    &lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DebugWindow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec_&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>python</category>
      <category>ux</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Developing API exchange sharing service - Part II</title>
      <dc:creator>namuan</dc:creator>
      <pubDate>Wed, 01 Jan 2020 14:07:21 +0000</pubDate>
      <link>https://forem.com/namuan/developing-api-exchange-sharing-service-part-ii-5f51</link>
      <guid>https://forem.com/namuan/developing-api-exchange-sharing-service-part-ii-5f51</guid>
      <description>&lt;p&gt;Please check the &lt;a href="https://dev.to/namuan/developing-api-exchange-sharing-service-part-i-nhp"&gt;previous part&lt;/a&gt; to know the background of this project.&lt;/p&gt;

&lt;p&gt;In this part, we'll dive into code and deploy a simple API to AWS Lambda and Api Gateway. &lt;/p&gt;

&lt;p&gt;I'll be using Python &lt;a href="https://palletsprojects.com/p/flask/"&gt;Flask&lt;/a&gt; framework for defining the APIs and &lt;a href="https://serverless.com"&gt;Serverless framework&lt;/a&gt; to manage the infrastructure and deployment.&lt;/p&gt;

&lt;p&gt;Please make sure you have Python3 and relatively newer version of nodejs installed and working to follow along.&lt;/p&gt;

&lt;p&gt;The first step is to create a new project folder and initialise package.json file which will be used to define and install Serverless plugins.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;api-exchange-server
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;api-exchange-server

&lt;span class="nv"&gt;$ &lt;/span&gt;npm init
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="c"&gt;# Enter all the way to generate package.json file&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Installing Serverless CLI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; serverless &lt;span class="c"&gt;# Although better to install this globally&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If Serverless CLI is installed globally then you don't need to prefix the &lt;code&gt;serverless&lt;/code&gt; commands with &lt;code&gt;./nodes_modules/.bin/&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Let's create a new project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./node_modules/.bin/serverless
Name the project serverless-project. Ignore the project name as we&lt;span class="s1"&gt;'ll move the files to the current folder.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We'll just copy the files that we need from the generated project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mv &lt;/span&gt;serverless-project/serverless.yml &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mv &lt;/span&gt;serverless-project/.gitignore &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; serverless-project
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After removing the folder generated by the Serverless CLI, this is how the structure looks like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt;
total 336
drwxr-xr-x    7 nmn  staff     224  1 Jan 09:00 &lt;span class="nb"&gt;.&lt;/span&gt;
drwxr-xr-x   15 nmn  staff     480  1 Jan 08:53 ..
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;    1 nmn  staff     192  1 Jan 08:58 .gitignore
drwxr-xr-x  386 nmn  staff   12352  1 Jan 08:54 node_modules
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;    1 nmn  staff  156725  1 Jan 08:54 package-lock.json
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;    1 nmn  staff     271  1 Jan 08:54 package.json
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;    1 nmn  staff    3206  1 Jan 08:58 serverless.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let's open the folder in your &lt;a href="https://code.visualstudio.com"&gt;favourite&lt;/a&gt; text editor.&lt;/p&gt;

&lt;p&gt;To connect AWS Lambda to Flask handlers, we'll need to install &lt;a href="https://github.com/logandk/serverless-wsgi"&gt;serverless-wsgi&lt;/a&gt; plugin to do the necessary transformation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./node_modules/.bin/serverless plugin search &lt;span class="nt"&gt;-q&lt;/span&gt; wsgi
1 plugin&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt; found &lt;span class="k"&gt;for &lt;/span&gt;your search query &lt;span class="s2"&gt;"wsgi"&lt;/span&gt;

serverless-wsgi - Serverless plugin to deploy WSGI applications &lt;span class="o"&gt;(&lt;/span&gt;Flask/Django/Pyramid etc.&lt;span class="o"&gt;)&lt;/span&gt; and bundle Python package

To &lt;span class="nb"&gt;install &lt;/span&gt;a plugin run &lt;span class="s1"&gt;'serverless plugin install --name plugin-name-here'&lt;/span&gt;

It will be automatically downloaded and added to your package.json and serverless.yml file
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As stated by the really useful help message, we'll install this plugin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./node_modules/.bin/serverless plugin &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; serverless-wsgi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, we'll create a simple flask Api which will return the environment variables in json. As this code will run on Lambda, you'll be able to see all the environment variables available for the function.&lt;/p&gt;

&lt;p&gt;File -&amp;gt; New -&amp;gt; "api.py"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jsonify&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;jsonify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Just noticed that we haven't installed Flask yet so let's create a requirements file and install it in a new virtualenv.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate
&lt;span class="nv"&gt;$ &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;flask
&lt;span class="nv"&gt;$ &lt;/span&gt;pip freeze &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With the project completed, we can test the Api by running it locally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ FLASK_APP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;api.py flask run
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next we need to tell/configure Serverless framework to connect Lambda to Flask App. There are few ways to setup the integration. &lt;br&gt;
Here we'll be using &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html"&gt;AWS Lambda Proxy&lt;/a&gt; integration for the API handler.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;wsgi_handler.handler&lt;/span&gt;
    &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ANY /&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ANY {proxy+}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We also need to tell wsgi plugin where to find the Flask API, so let define a custom section for this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;wsgi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api.app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Although the wsgi plugin can manage python dependencies, I had better luck with using a different plugin &lt;a href="https://github.com/UnitedIncome/serverless-python-requirements"&gt;serverless-python-requirements&lt;/a&gt; so we'll install it as well&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./node_modules/.bin/serverless plugin &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; serverless-python-requirements
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now let's try packaging up the app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./node_modules/.bin/serverless package
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If successful, the generated zip file will be placed in &lt;code&gt;.serverless&lt;/code&gt; folder. If we examine that file, we'll find that it contains all the files in the current folder including the giant &lt;code&gt;venv&lt;/code&gt; and &lt;code&gt;node_modules&lt;/code&gt; folder 😱.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4nKPA-G_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/k1bftpwralpe20xx6p20.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4nKPA-G_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/k1bftpwralpe20xx6p20.jpg" alt="serverless package"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm sure python requirements folder is right up there as well.&lt;/p&gt;

&lt;p&gt;Luckily, we can configure what to include in the zip file so we'll exclude everything and just add the file that we need to run the application. Note that the plugin will still take care of all the python dependencies defined in requirements.txt file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**"&lt;/span&gt;
  &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api.py"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is what it looks like with the changes that we made in the serverless.yml file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rlviQP47--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/8kgmqgsu6khi6692eatb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rlviQP47--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/8kgmqgsu6khi6692eatb.png" alt="Serverless wsgi setup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also check the complete &lt;a href="https://github.com/namuan/api-exchange-server-guide/blob/master/serverless.yml"&gt;file&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That should be everything to deploy on AWS Lambda. The next step requires an AWS profile with appropriate permissions to deploy and create Lambda resources.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that this is where you may be charged.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ AWS_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;myprofile ./node_modules/.bin/serverless deploy &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It will take some time to create all the resources before printing out the endpoints that it generated for the Api Gateway.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oSe-Z2zh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/bs3nb0oxq24qlnix7bvh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oSe-Z2zh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/bs3nb0oxq24qlnix7bvh.png" alt="Serverless output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should be able to hit the above endpoint via curl or open it up directly in the browser. There you can see all the environment variables available to your lambda function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-v&lt;/span&gt; https://mcb1lbc2ti.execute-api.us-east-1.amazonaws.com/dev
&lt;span class="c"&gt;# or &lt;/span&gt;
open https://mcb1lbc2ti.execute-api.us-east-1.amazonaws.com/dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once you are done with it, don't forget to remove the setup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ AWS_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;myprofile ./node_modules/.bin/serverless remove &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>python</category>
      <category>tutorial</category>
      <category>showdev</category>
      <category>aws</category>
    </item>
    <item>
      <title>Developing API exchange sharing service - Part I</title>
      <dc:creator>namuan</dc:creator>
      <pubDate>Wed, 01 Jan 2020 13:55:36 +0000</pubDate>
      <link>https://forem.com/namuan/developing-api-exchange-sharing-service-part-i-nhp</link>
      <guid>https://forem.com/namuan/developing-api-exchange-sharing-service-part-i-nhp</guid>
      <description>&lt;p&gt;In this series of articles, I'll go through my experience of building a simple Serverless API using &lt;a href="https://palletsprojects.com/p/flask/"&gt;Flask&lt;/a&gt; python framework and deploying it on &lt;a href="https://aws.amazon.com/lambda/"&gt;AWS Lambda&lt;/a&gt; and API gateway. &lt;/p&gt;

&lt;p&gt;This API is used from &lt;a href="https://github.com/namuan/http-rider"&gt;HttpRider&lt;/a&gt; to save API exchanges (request+response). &lt;/p&gt;

&lt;p&gt;Here is a &lt;a href="https://printrider.bettercallbots.com/prints/9e4d91c5-4526-471f-8896-79543ccaeb6a"&gt;sample page&lt;/a&gt; generated from HttpRider.&lt;/p&gt;

&lt;h3&gt;
  
  
  Demo
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gmD-b3rN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0148au5ftxy2fby8qufj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gmD-b3rN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0148au5ftxy2fby8qufj.gif" alt="Quick Demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The service itself consists of two simple APIs.&lt;/p&gt;

&lt;h4&gt;
  
  
  POST /prints
&lt;/h4&gt;

&lt;p&gt;Saves the HTML encoded in base64 in dynamo database. Once it is saved, it returns the URL of the shared document in the Location header of the response.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /prints
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Headers&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Content-Type: application/json
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Body&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "document": "SHR0cFJpZGVy"
}

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



&lt;p&gt;&lt;em&gt;Response&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP 201
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Headers&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;location: http://localhost:8080/prints/025000cf-14ba-421b-a000-d2d043d4d90b
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  GET /prints/{print-id}
&lt;/h4&gt;

&lt;p&gt;This GET request uses the URL from the location header in the previous request and receives the HTML response with the document.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /prints/025000cf-14ba-421b-a000-d2d043d4d90b
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Headers&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Accept: text/html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Response&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP 200
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Headers&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;content-type: text/html; charset=utf-8
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Body&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;Deskriders :: API Print&amp;lt;/title&amp;gt;
    &amp;lt;style&amp;gt;
       .... removed to save space ...
    &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;div&amp;gt;HttpRider&amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

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



&lt;p&gt;In the next part, we will look at setting up a new Flask project and serverless framework configuration to deploy it to AWS Lambda.&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>showdev</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>HttpRider :: Using GitHub APIs</title>
      <dc:creator>namuan</dc:creator>
      <pubDate>Sun, 08 Dec 2019 18:22:19 +0000</pubDate>
      <link>https://forem.com/namuan/httprider-using-github-apis-3efd</link>
      <guid>https://forem.com/namuan/httprider-using-github-apis-3efd</guid>
      <description>&lt;p&gt;Here is a sneak preview of &lt;a href="https://github.com/namuan/http-rider"&gt;HttpRider&lt;/a&gt;, a Rest API client that I'm working on and using it as my primary Rest API client for a while.&lt;/p&gt;

&lt;p&gt;In future, I'm planning to write more about the different feature set and what makes it unique across the different products in the same space.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=jtoxr10SU6A"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hW5BMQRw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.youtube.com/vi/jtoxr10SU6A/0.jpg" alt="GitHub API Demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Interested? Have a look at the &lt;a href="https://github.com/namuan/http-rider/blob/master/README.md"&gt;README&lt;/a&gt; file for feature list and give it a try. &lt;/p&gt;

&lt;p&gt;Let me know if you have any &lt;a href="https://github.com/namuan/http-rider/issues"&gt;issues&lt;/a&gt; or any suggestions for improvement.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/namuan/http-rider/"&gt;HttpRider&lt;/a&gt; is open source and built using Python and PyQT5 so should work across platforms &lt;sup id="fnref1"&gt;1&lt;/sup&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;I'm mainly using it on Mac but there is nothing which should make it platform dependent. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>python</category>
      <category>api</category>
      <category>productivity</category>
      <category>testing</category>
    </item>
    <item>
      <title>Protecting applications with OAuth2 Proxy</title>
      <dc:creator>namuan</dc:creator>
      <pubDate>Sat, 23 Nov 2019 21:30:44 +0000</pubDate>
      <link>https://forem.com/namuan/protecting-applications-with-oauth2-proxy-3c4</link>
      <guid>https://forem.com/namuan/protecting-applications-with-oauth2-proxy-3c4</guid>
      <description>&lt;p&gt;Here is a simple guide on protecting a website with social logins supporting OAuth2. It uses an open source &lt;a href="https://pusher.github.io/oauth2_proxy/" rel="noopener noreferrer"&gt;OAuth2 Proxy&lt;/a&gt; (which is a fork from &lt;a href="https://github.com/bitly/oauth2_proxy" rel="noopener noreferrer"&gt;Bitly OAuth2 Proxy&lt;/a&gt;) to secure private applications without adding any authentication logic in the application itself. &lt;/p&gt;

&lt;p&gt;Here, we'll see how to secure the open source version of &lt;a href="https://httpbin.org" rel="noopener noreferrer"&gt;https://httpbin.org&lt;/a&gt;. Httpbin application itself is open and can be accessed without any authentication.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fi1zmqplvv8eq8pzsvfvt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fi1zmqplvv8eq8pzsvfvt.png" alt="Proxy configuration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this guide, we will setup a Github OAuth application but the same setup can be easily configured with any other provider. See &lt;a href="https://pusher.github.io/oauth2_proxy/auth-configuration" rel="noopener noreferrer"&gt;Providers&lt;/a&gt; for different config options.&lt;/p&gt;

&lt;h4&gt;
  
  
  Setting up Github Application:
&lt;/h4&gt;

&lt;p&gt;Login to your github account and navigate to &lt;a href="https://github.com/settings/developers" rel="noopener noreferrer"&gt;Developer Settings&lt;/a&gt;. Click on OAuth Apps and Register a new application.&lt;/p&gt;

&lt;p&gt;I'll call this application SocialBin and set the homepage as &lt;a href="http://localtest.me" rel="noopener noreferrer"&gt;http://localtest.me&lt;/a&gt;. &lt;a href="https://readme.localtest.me" rel="noopener noreferrer"&gt;Localtest.me&lt;/a&gt; is a DNS configured to point to 127.0.0.1 and makes it easy to do local testing.&lt;/p&gt;

&lt;p&gt;We will be running the application on port 8080 so the callback url is set as &lt;a href="http://localtest.me:8080/oauth2/callback" rel="noopener noreferrer"&gt;http://localtest.me:8080/oauth2/callback&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That is it for setting up the application. Note down the Client ID and Client Secret which will be used later.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ffozsrm840r7nu8wbia5o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ffozsrm840r7nu8wbia5o.png" alt="Github Client configuration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Running application with proxy:
&lt;/h4&gt;

&lt;p&gt;Clone this &lt;a href="https://github.com/namuan/oauth2-proxy-httpbin" rel="noopener noreferrer"&gt;Github project&lt;/a&gt; and then copy or move the example configuration file.&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;You can also run the following command to generate a random value which will be used for cookie secret.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;head -c32 /dev/urandom | base64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Edit the .env file and update the variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OAUTH2_PROXY_COOKIE_SECRET=&amp;lt;generated random value&amp;gt;
OAUTH2_PROXY_COOKIE_DOMAIN=http://localtest.me
OAUTH2_PROXY_CLIENT_ID=&amp;lt;github client id&amp;gt;
OAUTH2_PROXY_CLIENT_SECRET=&amp;lt;github client secret&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, switch over to docker-compose.yml which is setting up two docker containers. The &lt;a href="https://hub.docker.com/r/kennethreitz/httpbin" rel="noopener noreferrer"&gt;httpbin&lt;/a&gt; container is the service we are trying to protect so you can see that it is not exposing any ports. The &lt;code&gt;"--upstream=http://httpbin:80",&lt;/code&gt; configuration is telling the oauth2 proxy where to send the traffic once the login is successful.&lt;/p&gt;

&lt;p&gt;With everything in its place, we can bring up the containers using &lt;code&gt;docker-compose&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;docker-compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It'll take some time if it is running for the first time to pull any missing docker images. Once everything is running, you can visit &lt;code&gt;http://localtest.me:8080/&lt;/code&gt; in the browser which should show you a screen with a button to "Sign in with Github". Here is a brief sequence of the login flow and accessing httpbin.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fbr9iafvbj41srj5j7dxl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fbr9iafvbj41srj5j7dxl.gif" alt="oauth2_proxy_login_httpbin"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Conclusion:
&lt;/h4&gt;

&lt;p&gt;As we saw, OAuth2Proxy is a useful tool to protect any application without changing the code. The source code for this setup is available here &lt;a href="https://github.com/namuan/oauth2-proxy-httpbin" rel="noopener noreferrer"&gt;https://github.com/namuan/oauth2-proxy-httpbin&lt;/a&gt;. &lt;/p&gt;

&lt;h4&gt;
  
  
  References:
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://github.com/pusher/oauth2_proxy" rel="noopener noreferrer"&gt;https://github.com/pusher/oauth2_proxy&lt;/a&gt;&lt;br&gt;
&lt;a href="https://readme.localtest.me/" rel="noopener noreferrer"&gt;https://readme.localtest.me/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://hub.docker.com/r/kennethreitz/httpbin" rel="noopener noreferrer"&gt;https://hub.docker.com/r/kennethreitz/httpbin&lt;/a&gt;&lt;br&gt;
&lt;a href="https://hub.docker.com/r/bitnami/oauth2-proxy" rel="noopener noreferrer"&gt;https://hub.docker.com/r/bitnami/oauth2-proxy&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>oauth2</category>
      <category>security</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
