<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: george_pollock</title>
    <description>The latest articles on DEV Community by george_pollock (@george_pollock).</description>
    <link>https://dev.to/george_pollock</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%2F222451%2F79b3e221-a5a8-425d-8989-2a6b31831866.png</url>
      <title>DEV Community: george_pollock</title>
      <link>https://dev.to/george_pollock</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/george_pollock"/>
    <language>en</language>
    <item>
      <title>Use Python to translate text from images to any language</title>
      <dc:creator>george_pollock</dc:creator>
      <pubDate>Thu, 27 May 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/george_pollock/use-python-to-translate-text-from-images-to-any-language-1cmb</link>
      <guid>https://dev.to/george_pollock/use-python-to-translate-text-from-images-to-any-language-1cmb</guid>
      <description>&lt;h2&gt;
  
  
  Who is it for?
&lt;/h2&gt;

&lt;p&gt;Have you ever found yourself looking for one of those &lt;a href="https://clasicosbilingues.com/site/"&gt;bilingual books&lt;/a&gt; but none of them caught your interest? Maybe you thought that they re too expensive, after all - most of them are already on a public domain.&lt;/p&gt;

&lt;p&gt;Or maybe you were abroad, went to a book store and found a really interesting book available only in the local language?&lt;/p&gt;

&lt;p&gt;Scientific papers? That fits too!&lt;/p&gt;

&lt;p&gt;This post explains how to translate photos, pictures that have text within them so that consists photos, screenshots, images, etc.&lt;/p&gt;

&lt;p&gt;In order to initialize the project you will need a Google API key from Google Console which can take a bit to generate especially if you have never done it before. If you want to translate small batches or just a couple of images you may try to use other tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I love languages&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the following example you will see that we are going translate Siddhartha by Herman Hesse which is on public domain. The book we translate is in German and you can pick up just about any language google offers (one of 64). &lt;em&gt;That is something that could really ease a language learning!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Copyrights
&lt;/h2&gt;

&lt;p&gt;How does copyright work arrive in public domain and can be used freely?&lt;/p&gt;

&lt;p&gt;Most of works people create is protected with Copyrights. In most of the countries they last a lifetime of an author plus 25-100 years. Depending on the country you may find books of foreign authors sooner - verify &lt;a href="https://en.wikipedia.org/wiki/List_of_countries%27_copyright_lengths"&gt;detailed world map&lt;/a&gt; to see exact timings.&lt;/p&gt;

&lt;p&gt;You may wonder how to ask permission to translate a book, on public domain it is not required anymore (although if you are still wondering then just writing to Authors with a polite request will do). So can you translate public domain books? Yes, you can!&lt;/p&gt;

&lt;p&gt;Once the Copyrights expire, works are becoming publicly available, they become part of a &lt;a href="http://www.publicdomainsherpa.com/public-domain-books.html"&gt;public domain&lt;/a&gt;. This is where we are going to get the book to translate - &lt;a href="https://archive.org/details/bub_gb_x-7OAAAAMAAJ"&gt;Siddhartha by Herman Hesse&lt;/a&gt;. On Archive.org we can see &lt;em&gt;usage&lt;/em&gt; category which states: &lt;strong&gt;Usage Public Domain Mark 1.0&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In order to show the full process I printed a few pages:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RkR6DLrN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/f53f7adedc614092758217e09fc7e785/8bc0c/siddhartha-scanning-book.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RkR6DLrN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/f53f7adedc614092758217e09fc7e785/8bc0c/siddhartha-scanning-book.jpg" alt="siddhartha-scanning-book" title="siddhartha-scanning-book" width="650" height="650"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s start
&lt;/h2&gt;

&lt;p&gt;We need to first scan those pages. We will use mobile app called Microsoft Lens:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://play.google.com/store/apps/details?id=com.microsoft.office.officelens&amp;amp;hl=en_US&amp;amp;gl=US"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--utleSmRe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/174c547c5dde2f4304c3daf2b5610d74/941ef/microsoft-office-lens-app.png" alt="microsoft-office-lens-app" title="microsoft-office-lens-app" width="360" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you download it, try scanning the pages. It has nice option of making the scanned documents flat and readable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--igYW_xSA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/903f164df446214df0b5514327702417/dcf16/microsoft-office-lens-scanning-book-2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--igYW_xSA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/903f164df446214df0b5514327702417/dcf16/microsoft-office-lens-scanning-book-2.jpg" alt="microsoft-office-lens-scanning-book" title="microsoft-office-lens-scanning-book" width="606" height="1280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you finish scanning all the pages, select a black and white sharpening filter and sve those files.&lt;/p&gt;

&lt;p&gt;Example scanned document should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WzI4R-aw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/36aad37aaf375722ebb0df0aea3eacac/8bc0c/Herman-Hesse-Siddhartha.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WzI4R-aw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/36aad37aaf375722ebb0df0aea3eacac/8bc0c/Herman-Hesse-Siddhartha.jpg" alt="Herman-Hesse" title="Herman-Hesse" width="650" height="926"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now put all those scanned photos into one folder on your computer and let´s go to the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  The intro
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/hvitis/translate-anything-with-python"&gt;The script I wrote&lt;/a&gt; utilizes python packages for OCR scanning, translating and saving into docx file. It´s sort of a free document translation software and although it´s just a few python lines it can perform a full book translation and later you can generate pdf out of this docx.&lt;/p&gt;

&lt;p&gt;Even if you have just pdf it can be tweaked and used as ebook translator. You can just use free &lt;a href="https://pdf2png.com"&gt;pdf to png converter&lt;/a&gt; to obtain photos and run &lt;a href="https://github.com/hvitis/translate-anything-with-python"&gt;the script&lt;/a&gt;. This translation will only run if you´re online. The Python translate logic does not work offline because we are querying Google Translate API.&lt;/p&gt;

&lt;p&gt;Maybe you´ve heard about other services like reverso, bing translator or deepl translator. Using this script you can have unlimited, ad free experience that you can tweak to your needs and make your own book translation app.&lt;/p&gt;

&lt;p&gt;(If you do not want to use Google Services you may check &lt;a href="https://www.apertium.org/index.eng.html#?dir=eng-epo&amp;amp;q="&gt;apertium&lt;/a&gt; that also let´s you translate documents).&lt;/p&gt;

&lt;h1&gt;
  
  
  The code
&lt;/h1&gt;

&lt;p&gt;Code is available &lt;a href="https://github.com/hvitis/translate-anything-with-python/blob/main/main.py"&gt;here&lt;/a&gt; under GNU licence. You may want to check the &lt;a href="https://github.com/hvitis/translate-anything-with-python#instruction"&gt;usage and instalation steps&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The result is two files generated with original and translated text:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MWXam16P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/fca6fb8fa741788535e0d0549970dfd4/4d236/translation_result.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MWXam16P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/fca6fb8fa741788535e0d0549970dfd4/4d236/translation_result.png" alt="translation_result" title="translation\_result" width="650" height="289"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let me know what do you think and feel free to &lt;a href="https://hvitis.dev/contact"&gt;reach out&lt;/a&gt; if you need help.&lt;/p&gt;




&lt;p&gt;_Tell me about your insights and leave a comment - you are most welcome to see more posts of this type just go to &lt;a href="https://hvitis.dev"&gt;home page&lt;/a&gt;. Cover:_Photo by &lt;a href="https://unsplash.com/@beatriz_perez?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Beatriz Pérez Moya&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Software Development Engineer in Test || How Google tests software?</title>
      <dc:creator>george_pollock</dc:creator>
      <pubDate>Sun, 14 Mar 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/george_pollock/software-development-engineer-in-test-how-google-tests-software-1k64</link>
      <guid>https://dev.to/george_pollock/software-development-engineer-in-test-how-google-tests-software-1k64</guid>
      <description>&lt;p&gt;I wanted to know if at Google they do testing manually, if they have manual testers. If you want &lt;strong&gt;TLDR&lt;/strong&gt; answer, here is the answer ( 2 quotes taken from the books ):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In 2005 most of the testing was done manually if it was done at all.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Currently:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Attempting to assess product quality by asking humans to manually interact with every feature just doesn’t scale. When it comes to testing, there is one clean answer: automation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you want to read more on &lt;strong&gt;how they test their software&lt;/strong&gt; , keep reading!&lt;/p&gt;

&lt;p&gt;I will be quoting the books from the picture &lt;em&gt;a lot&lt;/em&gt; here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is Google’s software so good?
&lt;/h2&gt;

&lt;p&gt;Google engineers their products.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Software Engineering differs from programming in dimensionality programming is about producing code. Software engineering extends that to include the maintenance of that code for its useful life span.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In order to engineer software properly a pipeline of continuos delivery of new features, changes and improvements has to be set up. This pipeline has to stream tested and approved changes to a user in order to avoid expensive fixes ( &lt;strong&gt;shifting left concept&lt;/strong&gt; ) and lose of trust.&lt;/p&gt;

&lt;p&gt;In order to have well-working pipeline a few steps have to be taken.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clear documentation and specification that allows for .&lt;/li&gt;
&lt;li&gt;Process of testing that is mostly automated which allows scaling.&lt;/li&gt;
&lt;li&gt;Reusability of code: components, dependencies, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s break down those 2 points and analyse them&lt;/p&gt;

&lt;h2&gt;
  
  
  Documentation - Holy Grail that takes time to shine
&lt;/h2&gt;

&lt;p&gt;The development should be about development. Engineers should focus on investigating the code, implementing, developing features, testing. The &lt;em&gt;should not waste time on figuring out what they have to develop in the first place&lt;/em&gt;. They should have clean documentation both for new projects:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Project teams are more focused when their design goals and team objectives are clearly stated.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and for legacy code:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Quality documentation has tremendous benefits for an engineering organization. Code and APIs become more comprehensive and reduce mistakes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Writing documentation, maintaining it and spending time on it can have a very big feedback loop when it comes to profits.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Benefits aren’t immediate.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It may be difficult to see immediate gains but in a long term they will be visible. They are necessary. On the beginning Google had no troubles with documentation but as the codebase grows, the need for it becomes more and more visible. That is why, in case wqhen a company wants to grow and scale their products, it is necessary to have a good documentation from the beginning. Google’s history gives a little bit of insight:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;New users discovering bad documents either couldn’t confirm that the documents were wrong or didn’t have an easy way to report errors. […] The way to improve the situation was to move important documentation under same sort of source control that was being used to track code changes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even if scaling is not taken into consideration, normal development can also hugely benefit from writing documentation. Developers need to know that &lt;strong&gt;writing documentation is not much different than writing the code&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing - why should we do it?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Shifting left concept.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What is it?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you can catch it before the original developer commits the flaw to version control, it’s even cheaper.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If we have User Story development on the left side of the graph, then on the right side of it we have delivery to production. The X axis is time.&lt;/p&gt;

&lt;p&gt;The closer to the left side of the graph we catch bugs, the cheaper it will cost us.&lt;/p&gt;

&lt;p&gt;Catching bugs on production is &lt;strong&gt;very costly&lt;/strong&gt; : revising legacy code, changing integrations, losing customer’s confidence in our products. All that affects the turnover. That is also why documentation plays an important part. It helps to shift towards left side. Helps to &lt;strong&gt;avoid introducing bugs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;There will always be bugs. No matter how good the developers and documentation. The most important part of shifting left is implementing testing process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing - Google’s good standards for everyone
&lt;/h2&gt;

&lt;p&gt;There is a few places where we can automate testing. At Google there is a culture that says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Treat your tests like production code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This means that a lot of testing is being done by the developers. They are responsible for writing tests. They can’t test everything. That is why there is a separate job position that for some scopes of testing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The engineers who build systems today, play an active and integral role in writing and running automated tests for their own code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Test scopes that are at Google are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Narrow scope - unit tests (80% of tests)&lt;/li&gt;
&lt;li&gt;Mediums scope - integration tests (15% of tests)&lt;/li&gt;
&lt;li&gt;Large scope - end to end tests (5% of tests)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The 5% that is left - exploratory, beta, smoke testing.&lt;/p&gt;

&lt;p&gt;Test suite antipatterns are basically processes that have significantly different amounts of tests by percentage in a code base.&lt;/p&gt;

&lt;p&gt;e.g an &lt;strong&gt;ice cream antipattern&lt;/strong&gt; is the revers of the top example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unit tests (20% of tests)&lt;/li&gt;
&lt;li&gt;Integration tests (55% of tests)&lt;/li&gt;
&lt;li&gt;End to end tests (25% of tests)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Antipatterns should be avoided. Remember, this is the Google’s view of products so deviating from those rules could be possible. We need to remember that the goal of Google is to &lt;strong&gt;deliver quickly&lt;/strong&gt; , &lt;strong&gt;well tested product&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If your company’s structure or process is not similar to Google’s - there are chances that the goal is. Everybody should have structure that allows for quick deliveries and high quality.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Even in companies where QA is a prominent organization, developer-written tests are commonplace. At the speed and scale that today’s systems are being developed, the only way to keep up is by sharing the development of tests around the entire engineering staff.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Testing - Automate where possible
&lt;/h2&gt;

&lt;p&gt;You should be able to automate every test that you make. In case of failure or bug, a new test to cover the case should be created. This requires a very well structures architecture of the software product and according chose of tools.&lt;/p&gt;

&lt;p&gt;It is important to remember that testing should always be done in order to increase quality assurance. You have to be able to trust your tests. That means that &lt;strong&gt;tests have to be good&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A bad test suite can be worse than no test suite at all.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Treating tests in this way, &lt;em&gt;fixing and adjusting them immediately&lt;/em&gt; maintains (or increases) our level or certainty regarding test results.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Allowing failed tests to pile up quickly defeats any value they were providing, so it is imperative not to let that happen.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Google’s take on broken tests is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Teams that prioritize fixing a broken test within minutes of a failure are able to keep confidence high and failure isolation fast, and therefore derive more value out of their tests.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not adjusting and fixing test causes test flakiness. This can have negative impact on the team and quality.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If test flakiness continues to grow, you will experience something much worse than lost productivity; a loss of confidence in the tests. […] After that happens, engineers will stop reacting to test failures, eliminating any value tha test suite provided.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At Google % of failed tests is limited to 0.15%.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing - Bunch of advices for SDET
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;SDET&lt;/strong&gt; - Among of other responsibilities that they have, &lt;strong&gt;Software Developer Engineer in Tests&lt;/strong&gt; is a person that guards quality by automating testing procedures. They are usually responsible for implementing medium and larger tests where SDEs ( &lt;strong&gt;Software Developer Engineers&lt;/strong&gt; ) develop smaller tests.&lt;/p&gt;

&lt;p&gt;At Google they differentiate tests to 3 sets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Small - No sleeping, no awaits, no blocking calls, they run as fast as possible.&lt;/li&gt;
&lt;li&gt;Medium - localhost webdriver, slower, nondeterministic.&lt;/li&gt;
&lt;li&gt;Large tests - no localhost, remote cluster, integrate wide assets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The amount of small tests should be the highest due to it’s runtime and maintainability (that’s why SDEs are always responsible for covering their code with good unit tests).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Smaller and smaller tests tourned out to be faster, more stable and generally less painful.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;All tests should strive to be hermetic. The larger the tests the more difficult to stick to this advice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reusability
&lt;/h2&gt;

&lt;p&gt;Code is a liability. Using the Statical Code Analysis tools we could assess the amount of duplication that is in our codebase. Increasing duplication decreases the speed of delivery in a CI/CD pipe.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Duplicated code not only is a wasted effort, it can actually cost more in time than not having the code at all; changes that could be easily performed under one code pattern often require more effort when there is duplication in the codebase. Basically, “if you’re writing it from scratch you’re doing it wrong”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Sum up
&lt;/h2&gt;

&lt;p&gt;Google surprises me with the quality of their product. Their uptime, security measures, user interface and ease of access is amazing. If I love their products it means that they test it well. The quality that they maintain is a proof that their way works. If they say that it’s possible to scale testing by automating it or that developers should be testers, it’s difficult to disagree with this statement.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Tell me about your insights and leave a comment - you are most welcome to see more posts of this type just go to &lt;a href="https://hvitis.dev"&gt;home page&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&amp;lt;!-- DOCS --&amp;gt;&amp;lt;!-- [0]:&lt;/p&gt;

&lt;p&gt;How does Google test software?”&lt;br&gt;
fundamentals of testing 720 1.30    0.03&lt;br&gt;
qa at amazon    590 0.31    0.06&lt;br&gt;
google testing blog 320 1.41    0.02&lt;br&gt;
how google tests software pdf   210 0.00    0.04&lt;br&gt;
android automation testing tools    140 2.70    0.3&lt;br&gt;
software testing new technologies   110 1.00    0.1&lt;br&gt;
how we test software at microsoft   110 6.57    0.08&lt;br&gt;
google cloud functions testing  70  0.00    0&lt;br&gt;
how we test software at microsoft pdf   50  0.00    0.04&lt;br&gt;
google qa salary    30  0.00    0.04&lt;br&gt;
google cloud platform automation    20  7.69    0.22&lt;br&gt;
google software quality assurance   10  0.00    0.1&lt;br&gt;
how google tests software amazon    10  0.00    0.14&lt;br&gt;
how google tests software part one  0   0.00    0&lt;br&gt;
how google tests software blog  0   0.00    0&lt;br&gt;
cloud test automation using selenium    0   0.00    0&lt;br&gt;
devops test data management 0   0.00    0&lt;br&gt;
gcp devops architecture 0   0.00    0&lt;br&gt;
test data management java   0   0.00    0&lt;br&gt;
effective ways in the test management.  0   0.00    0&lt;br&gt;
crowdtesting platform   0   0.00    0&lt;br&gt;
testing new features    0   0.00    0&lt;br&gt;
learn android testing   0   0.00    0&lt;br&gt;
ui android test 0   0.00    0&lt;br&gt;
android studio unit test ui 0   0.00    0&lt;br&gt;
google phone testing    0   0.00    0&lt;br&gt;
how does facebook test new features 0   0.00    0&lt;br&gt;
sdet conferences    0   0.00    0&lt;br&gt;
google automation summit    0   0.00    0&lt;br&gt;
screenster login    0   0.00    0&lt;br&gt;
google's acc methodology    0   0.00    0&lt;br&gt;
how to test google book 0   0.00    0&lt;br&gt;
qa in google    0   0.00    0&lt;br&gt;
google testing blog 320 1.41    0.02&lt;br&gt;
how google tests software amazon    10  0.00    0.14&lt;br&gt;
how we test software at google  10  0.00    0&lt;br&gt;
how google test software free pdf   0   0.00    0&lt;br&gt;
how google tests software 2020  0   0.00    0&lt;br&gt;
how google tests software blog  0   0.00    0&lt;br&gt;
how google tests software summary   0   0.00    0&lt;br&gt;
how google tests software epub  0   0.00    0&lt;/p&gt;

&lt;p&gt;Static code analysis.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One of the most important technological improvements regarding automation over the past few years is automatic static analysis of a given code change.&lt;/p&gt;

&lt;p&gt;As a corollary to this, we also strongly discourage the use of control flow statements like conditionals and loops in tests.&lt;/p&gt;

&lt;p&gt;When conducting and exploratory test, the specific problems to be found are unknown at the start. As with the detection of security vulnerabilities, as soon as an exploratory test discovers an issue, an automated test should be added to prevent future regressions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;--&amp;gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Geolocation tutorial project with Geodjango and GIS data to build using REST api.</title>
      <dc:creator>george_pollock</dc:creator>
      <pubDate>Mon, 09 Nov 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/george_pollock/geolocation-tutorial-project-with-geodjango-and-gis-data-to-build-using-rest-api-k1j</link>
      <guid>https://dev.to/george_pollock/geolocation-tutorial-project-with-geodjango-and-gis-data-to-build-using-rest-api-k1j</guid>
      <description>&lt;h2&gt;
  
  
  Boilerplate with Geodjango and Leaflet - learn while using it and deploy to Heroku
&lt;/h2&gt;

&lt;p&gt;The topic we will cover here. Click to go to code examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Get geolocation from the IP&lt;/strong&gt; - we will get coordinates of the IP that we extract from the request itself. I mention loading IP data from other DB to not use external API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Searching via Address&lt;/strong&gt; - we will use &lt;a href="https://docs.djangoproject.com/en/3.1/topics/db/queries/#complex-lookups-with-q-objects"&gt;q django query&lt;/a&gt; to search location fields.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adding new objects on map&lt;/strong&gt; - we will add a few objects using demo VueJS component with api from django rest framework.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Closest object&lt;/strong&gt; - we will use geodjango point to find closest object&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Plus useful snippets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Drawing polygons on map&lt;/strong&gt; - we check here geodjango area.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;List of objects within radius&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calculate distance between two points&lt;/strong&gt; - backend and frontend solution.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deployable boilerplate with all above&lt;/strong&gt; - how to prepare PostgreSQL database for geodjango on Heroku.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Important:&lt;/em&gt; We will be using vuejs with geodjango (connecting django rest framework api with javascript) throughout this tutorial - &lt;a href="https://github.com/openwisp/django-rest-framework-gis"&gt;django-rest-framework-gis&lt;/a&gt;. This django package is compatible with both currently used django versions - Django 2 and Django 3. For more compatibility check &lt;a href="https://github.com/openwisp/django-rest-framework-gis#compatibility-with-drf-django-and-python"&gt;geodjango documentation&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Intercepting requests - using proxy and interceptor to hack your workflow ( no &lt;a href="https://github.com/openwisp/django-rest-framework-gis#compatibility-with-drf-django-and-python"&gt;swagger&lt;/a&gt;? no problem! )&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get geolocation from the IP
&lt;/h2&gt;

&lt;p&gt;There are 3 ways of obtaining geolocation based on IP address: (easy) ⚪ Call an external geocoding webservices API that returns location data (done from frontend or backend) (harder) 🟠 Use geo IP database with mapped IP.&lt;/p&gt;

&lt;p&gt;First let’s get IP address from the django request. Let’s install &lt;a href="https://github.com/un33k/django-ipware"&gt;&lt;strong&gt;django-ipware&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install django-ipware
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and use it in &lt;strong&gt;class views&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from rest_framework.generics import ListAPIView
from rest_framework.response import Response
from rest_framework import status
from ipware import get_client_ip

class ShowUsersIP(ListPIView):
    """
    Sample API endpoint that shows user's IP
    """
    queryset = Message.objects.all()
    serializer_class = UserSerializer

    def get(self, request):
        client_ip, is_routable = get_client_ip(request)
        print('IP_INFO: ',client_ip, is_routable)
        data = {
            'client_ip': client_ip,
            'is_routable': is_routable
        }
        return Response(data, status=status.HTTP_200_OK)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or &lt;strong&gt;function based views&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.http.response import JsonResponse
from ipware import get_client_ip

def show_users_ip(request):
    client_ip, is_routable = get_client_ip(request)
    data = {
        'client_ip': client_ip,
        'is_routable': is_routable
    }
    return JsonResponse(data)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  (The &lt;em&gt;easy&lt;/em&gt; one) ⚪
&lt;/h4&gt;

&lt;p&gt;Now that we know how to get the IP of the user we can track it’s location. With &lt;a href="https://github.com/un33k/django-ipware"&gt;ip.info&lt;/a&gt; we get 50k calls on freemium which is more than enough. In order to obtain the location you need to pass the IP to the request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import sys
import urllib.request
import json

ACCESS_TOKEN = 'YOUR_TOKEN'

def get_lat_lng_from_ip(ip_address):
    """Returns array that consists of latitude and longitude"""
    URL = 'https://ipinfo.io/{}?token={}'.format(ip_address, ACCESS_TOKEN)
    try:
        result = urllib.request.urlopen(URL).read()
        result = json.loads(result)
        result = result['loc']
        lat, lng = result.split(',')
        return [lat, lng]
    except:
        print("Could not load: ", URL)
        return None

location = get_lat_lng_from_ip('208.80.152.201')
print('Latitude: {0}, Longitude: {1}'.format(*location))
# Prints: Latitude: 32.7831, Longitude: -96.8067
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response we get and transform to get lat and lng is this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "ip": "208.80.152.201",
  "city": "Dallas",
  "region": "Texas",
  "country": "US",
  "loc": "32.7831,-96.8067",
  "org": "AS14907 Wikimedia Foundation Inc.",
  "postal": "75270",
  "timezone": "America/Chicago"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Responses vary between providers. Some of other service providers are: Google, &lt;a href="https://opencagedata.com/api"&gt;OpenCage&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now let’s save the latitude and longitude we got from user’s IP to his account ! All examples are shown in the &lt;a href="https://github.com/hvitis/geodjango-rest-vue-boilerplate"&gt;boilerplate code&lt;/a&gt;. The User model we have &lt;a href="https://github.com/hvitis/geodjango-rest-vue-boilerplate/blob/main/backend/accounts/models.py#L56"&gt;there extends Abstract user&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# User model
class User(AbstractUser):
    #...
    coordinates = models.PointField(blank=True, null=True, srid=4326)

# Update view
# ...
from rest_framework_gis.pagination import GeoJsonPagination
from backend.accounts.api.serializers import UpdateLocationSerializer
from backend.utils.coordinates import get_lat_lng_from_ip
from rest_framework.response import Response
from django.contrib.gis.geos import GEOSGeometry
from django.contrib.gis.geos import Point
from rest_framework import status
import json

class UpdateLocation(UpdateAPIView):
    """ Updates location of a user using it's IP taken from request"""
    model = User
    serializer_class = UpdateLocationSerializer
    pagination_class = GeoJsonPagination

    def update(self, request, *args, **kwargs):
        """Here we:
        - get location from the IP
        - change coordinates to a randomly
        close one in order to anonymize users location.
        """

        # Using ipware library
        client_ip, is_routable = get_client_ip(request)
        # Using our function created previously in utils
        latitude, longitude = get_lat_lng_from_ip(client_ip)
        if not latitude:
            return Response({'message': 'IP or location was not found.'}, status=status.HTTP_406_NOT_ACCEPTABLE)
        # Anonimizing users location before saving
        latitude, longitude = self.anonymize_location(latitude, longitude)
        print('Users latitude {} and longitude {}'.format(latitude, longitude))

        # For GeoDjango PointField we define y and x
        # more in docs: https://docs.djangoproject.com/en/3.1/ref/contrib/gis/geos/#point
        point = Point(float(longitude), float(latitude), srid=4326)

        # Requires at least 1 user in DB (e.g. admin)
        user_obj = User.objects.all().first()

        # Using partial update to not create a new user obj
        anonymize_profile = UpdateLocationSerializer(user_obj, data={'coordinates': point}, partial=True)
        if not anonymize_profile.is_valid():
            return Response(anonymize_profile.errors, status=status.HTTP_400_BAD_REQUEST)
        anonymize_profile.save()

        pnt = GEOSGeometry(point)
        geojson = json.loads(pnt.geojson)
        return Response({'coordinates': reversed(geojson['coordinates'])}, status=status.HTTP_201_CREATED)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For your purposes there is a high chance you should use the first solution. There is many providers with free tiers offering many calls with high degree of accuracy.&lt;/p&gt;

&lt;h4&gt;
  
  
  (The &lt;em&gt;hard&lt;/em&gt; one) 🟠
&lt;/h4&gt;

&lt;p&gt;This option is based on downloading databases of IP and locations and querying it with the obtained IP of the user. You can check &lt;a href="https://www.ip2location.com/development-libraries/ip2location/python"&gt;IP2location&lt;/a&gt; page to see how to do it. Install python package for querying the DB and download the BINs with data to query.&lt;/p&gt;

&lt;p&gt;(for more loading dbsync data check out &lt;a href="https://realpython.com/location-based-app-with-geodjango-tutorial/"&gt;this realpython django tutorial&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Searching via Address
&lt;/h2&gt;

&lt;p&gt;Here we talk about geocoding and reverse geocoding. You can imagine that although with IP we could have location data in our DB - here, with addresses it is not going to be possible because we need much higher accuracy and the amount of data that is needed to achieve it is a lot bigger. You will be forced to use external service’s API.&lt;/p&gt;

&lt;p&gt;What if you don’t want to use &lt;a href="https://developers.google.com/maps/documentation/geocoding/overview"&gt;Google Geocoding API&lt;/a&gt;? There is a &lt;a href="https://pypi.org/project/geopy/"&gt;geopy library&lt;/a&gt; that provides easy API access to &lt;a href="https://nominatim.openstreetmap.org/ui/search.html?q=malaga+refino"&gt;Nominatim geocoding information&lt;/a&gt; that is open source. You just need to specify &lt;strong&gt;the name&lt;/strong&gt; when using it. It can be name of your app.&lt;/p&gt;

&lt;p&gt;Let’s see how easy it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from geopy.geocoders import Nominatim
&amp;gt;&amp;gt;&amp;gt; geolocator = Nominatim(user_agent="mysuperapp")
&amp;gt;&amp;gt;&amp;gt; location = geolocator.geocode("Warsaw Culture Palace")
&amp;gt;&amp;gt;&amp;gt; print(location.address)
Pałac Kultury, 1, Plac Defilad, Śródmieście Północne, Warszawa, województwo mazowieckie, 00-110, Polska
&amp;gt;&amp;gt;&amp;gt; print((location.latitude, location.longitude))
(52.2317641, 21.005799675616117)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to implement it we need to follow good REST API practices! How to implement it into django search endpoint?&lt;/p&gt;

&lt;p&gt;First it’s important to follow a &lt;a href="https://hvitis.dev/rest-api-design-best-practices#querystring"&gt;good URL naming practices&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yourapp.io/coordinates?address=QUERY_ADDRESS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Django we can implement it like this starting from &lt;em&gt;urls.py&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# urls.py

from django.urls import path
from backend.accounts.api.views import GetCoordinatesFromAddress

app_name = 'accounts'

urlpatterns = [
    # ...
     path("coordinates", # the rest will be in views: ?address=QUERY_ADDRESS
          GetCoordinatesFromAddress.as_view(), name="get-coordinates"),
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and in &lt;em&gt;views.py&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from geopy.geocoders import Nominatim
# ...

class GetCoordinatesFromAddress(ListAPIView, GeoFilterSet):
    """ Shows nearby Users"""

    def get(self, *args, **kwargs):
        # We can check on the server side the location of the users, using request
        # point = self.request.user.coordinates
        # ?address=QUERY_ADDRESS
        # QUERY_ADDRESS is the information user passes to the query
        QUERY_ADDRESS = self.request.query_params.get('address', None)

        if QUERY_ADDRESS not in [None, '']:
            # here we can use the geopy library:
            geolocator = Nominatim(user_agent="mysuperapp")
            location = geolocator.geocode(QUERY_ADDRESS)
            return Response({'coordinates': [location.latitude ,location.longitude]}, status=status.HTTP_200_OK)
        else:
            return Response({'message': 'No address was passed in the query'}, status=status.HTTP_400_BAD_REQUEST)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if we call our app’s API with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://geodjango-rest-vue-boilerplate.herokuapp.com/api/accounts/nearbyusers?address=warsaw
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We get in response body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "coordinates": [52.2319581, 21.0067249]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a front end example if you want to [try it][] or [see the code][].&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding new objects on map
&lt;/h2&gt;

&lt;p&gt;🚧🏗️👷 It will be here soon!&lt;/p&gt;

&lt;h2&gt;
  
  
  Closest object
&lt;/h2&gt;

&lt;p&gt;🚧🏗️👷 It will be here soon!&lt;/p&gt;

&lt;h2&gt;
  
  
  Drawing polygons on map
&lt;/h2&gt;

&lt;p&gt;🚧🏗️👷 It will be here soon!&lt;/p&gt;

&lt;h2&gt;
  
  
  List of objects within radius
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from geopy.geocoders import Nominatim
from rest_framework_gis.filterset import GeoFilterSet
from rest_framework_gis import filters as geofilters
from django.db.models import Q
from django.contrib.gis.measure import Distance
# ...

class ListNearbyUsers(ListAPIView, GeoFilterSet):
    """ Shows nearby Users"""
    model = User
    serializer_class = NearbyUsersSerializer
    pagination_class = GeoJsonPagination
    contains_geom = geofilters.GeometryFilter(name='coordinates', lookup_expr='exists')

    def get_queryset(self, *args, **kwargs):
        QUERY_ADDRESS = self.request.query_params.get('address', None)
        queryset = []

        if QUERY_ADDRESS not in [None, '']:
            queryset = User.objects.all()
            # here we can use the geopy library:
            geolocator = Nominatim(user_agent="mysuperapp.com")
            location = geolocator.geocode(QUERY_ADDRESS)

            # Let's use the obtained information to create a geodjango Point
            point = Point(float(location.longitude), float(location.latitude), srid=4326)
            # and query for 10 Users objects to find active users within radius
            queryset = queryset.filter(Q(coordinates__distance_lt=(
                point, Distance(km=settings.RADIUS_SEARCH_IN_KM))) &amp;amp; Q(is_active=True)).order_by('coordinates')[0:10]
            return queryset
        else:
            return queryset
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Calculate distance between two points
&lt;/h2&gt;

&lt;p&gt;🚧🏗️👷 It will be here soon!&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployable boilerplate with all above
&lt;/h2&gt;

&lt;p&gt;🚧🏗️👷 It will be here soon!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Did you make any mistakes when using REPLACETHIS or you’ve seen one here? Tell me about your insights. Leave a comment with YOUR opinion.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>LEGO Art Creator - Mosaic and Portraits.</title>
      <dc:creator>george_pollock</dc:creator>
      <pubDate>Mon, 02 Nov 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/george_pollock/lego-art-creator-mosaic-and-portraits-1hfc</link>
      <guid>https://dev.to/george_pollock/lego-art-creator-mosaic-and-portraits-1hfc</guid>
      <description>&lt;h1&gt;
  
  
  LEGO Art creator
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Everything on how to make mosaic art
&lt;/h2&gt;

&lt;p&gt;I present to you LEGO custom art generator that you can use for making your artwork. This mosaic maker is pure online software (you can use it offline once the page is loaded). Use your photos in ratio 1x1 and generate pixel art. LEGO Art maker trusted by thousands of people.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hvitis.dev/mosaic-art-maker"&gt;Click Here&lt;/a&gt; to enter online&lt;a href="https://hvitis.dev/mosaic-art-maker"&gt;LEGO Mosaic Art maker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OTf4Z09q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/vs9a5vert8b1x9w0cq2o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OTf4Z09q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/vs9a5vert8b1x9w0cq2o.png" alt="Lego Art Mosaic Cat" width="800" height="1208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;read more below&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to make your own art
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Select an image from your device. (You can use your face picture to make art from photo - the tool is on your computer, I don't store any files you upload.)&lt;/li&gt;
&lt;li&gt;Select size of the board and color set (you can chose e.g. &lt;a href="https://brickset.com/article/59534/review-31203-world-map"&gt;LEGO World Map&lt;/a&gt; 2021 set colors and others)&lt;/li&gt;
&lt;li&gt;Select if you want to use rectangle tiles or circular.&lt;/li&gt;
&lt;li&gt;Click Generate and Convert the picture to LEGO board&lt;/li&gt;
&lt;li&gt;You can use the &lt;strong&gt;edit mode&lt;/strong&gt;. Click on the color name and then on a stud you want to change the color of.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;What's new?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.lego.com/en-us/product/world-map-31203"&gt;LEGO World Map&lt;/a&gt; color set. It is the biggest LEGO set so far. It means you have plenty LEGO pieces to reuse!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now you can upload for example a &lt;a href="https://mapswire.com/north-america/physical-maps/"&gt;geo map of north america&lt;/a&gt; and generate things like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9tw3fsCm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/f75d9f11e28bef4652b45c0a2e11765d/4c7bf/lego-art-world-map-maker-online-1.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9tw3fsCm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/f75d9f11e28bef4652b45c0a2e11765d/4c7bf/lego-art-world-map-maker-online-1.webp" alt="Custom LEGO World Art" title="Custom LEGO World Art" width="800" height="801"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you don´t quite like your generated art - you can always edit it!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CTgBDMEn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/9e692422ea8de7233ee0a638f040e3dd/4c7bf/lego-art-world-map-maker-online-2.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CTgBDMEn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/9e692422ea8de7233ee0a638f040e3dd/4c7bf/lego-art-world-map-maker-online-2.webp" alt="Custom LEGO World Art Edited" title="Custom LEGO World Art Edited" width="800" height="801"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.lego.com/en-us/product/mosaic-maker-40179"&gt;LEGO Portrait&lt;/a&gt; color set. It is the set you get in photo-booths. I got one from the very LEGO house but did not quite like the outcome. Here is the outcome from the generator I made:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--W-EQ3LBY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/7e48cb0b02a2b5c68ab01153b3ec300e/c5f2f/lego-portrait-mosaic-maker-generator.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--W-EQ3LBY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/7e48cb0b02a2b5c68ab01153b3ec300e/c5f2f/lego-portrait-mosaic-maker-generator.webp" alt="LEGO Portrait online maker" title="LEGO Portrait online maker" width="800" height="799"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember that you can generate those mosaics and retouch them later in edit mode to make it the way you like!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Options&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The color themes - you can use pieces from different LEGO sets to reuse them and have even more fun. The themes are: Andy Warhol, Star Wars Sith, Iron Man, Mickey Mouse, Harry Potter, World Map, Mickey Mouse and custom.&lt;/li&gt;
&lt;li&gt;Studs numbered with BrickLink IDs so you can convert image to LEGO art and download the instructions immediately.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Requests&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you need more options don't hesitate to contact me via &lt;a href="https://hvitis.dev/contact"&gt;contact form&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How did it all started?
&lt;/h2&gt;

&lt;p&gt;This LEGO mosaic software was made by me for a reason. I didn't really like the way that &lt;a href="https://www.bricklink.com/v3/studio/download.page"&gt;&lt;strong&gt;stud.io&lt;/strong&gt;&lt;/a&gt; was doing mosaics. For example for a &lt;a href="https://cdn.catawiki.net/assets/marketing/marketing/upload_images-files/25639-b4ab0d290ab1d4ab3c94abcb09545b1294e3f70f-original.jpg"&gt;Marlyn photo&lt;/a&gt; it generates this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SUTEAHYS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/e609867362eaba1923ad9beab4b81103/5f327/marlyn_mosaic_maker_studio.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SUTEAHYS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/e609867362eaba1923ad9beab4b81103/5f327/marlyn_mosaic_maker_studio.png" alt="MarlynStudio" title="Marlyn Monroe Warhol" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not quite for a portrait maker.&lt;/p&gt;

&lt;p&gt;It was rendering to this (in stud.io):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sUKhygvD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/99680f3492728d09d9174731b7d81fde/7c13d/marlyn_mosaic_maker_studio_render.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sUKhygvD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/99680f3492728d09d9174731b7d81fde/7c13d/marlyn_mosaic_maker_studio_render.png" alt="MarlynStudioRender" title="Marlyn Monroe Warhol LEGO Render" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I didn't really like the fact the lips are black and the hair is green. Besides there's a lot of black and dark pieces around. I know you can tweak the photo hue, saturation etc but what I want is a no hustle way of doing this. That is why I created my mosaic maker app.&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://hvitis.dev/mosaic-art-maker"&gt;my generator&lt;/a&gt; the result of the first photo is this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bp_rzVw1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/9a76800a2de985b95d084082bd549916/a73dd/marlyn_custom_mosaic_maker_studio.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bp_rzVw1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/9a76800a2de985b95d084082bd549916/a73dd/marlyn_custom_mosaic_maker_studio.png" alt="MarlynStudioRenderCustom" title="Marlyn Monroe Warhol LEGO Render Custom" width="800" height="795"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I invite you to &lt;a href="https://hvitis.dev/mosaic-art-maker"&gt;use it&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why was I doing mosaics?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Many creative people are finding that creativity doesn't grow in abundance, it grows from scarcity - the more Lego bricks you have doesn't mean you're going to be more creative; you can be very creative with very few Lego bricks. - &lt;strong&gt;Jorgen Vig Knudstorp&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This quote from &lt;a href="https://en.wikipedia.org/wiki/J%C3%B8rgen_Vig_Knudstorp"&gt;Jorgen Vig Knudstorp&lt;/a&gt; who was a LEGO Group president made me think about creativity. I am using just my laptop to create and make my ideas reality but when it comes to LEGO you can just use a single squares 1x1 and create an astonishing pieces of art.&lt;/p&gt;

&lt;p&gt;Making mosaic is very rewarding and you are becoming best LEGO artist when making your own canvas. Trust me - I was doing this as art therapy with LEGO. It's very calming and more creative than puzzles. It does not matter to me how much money artists make, I do that for pleasure. My friends always like the art. It looks a bit like ASCII but just like ASCII mosaic it can be a favorite one to toy with. You can make really anything, Beatels set, Star Wars Sith or Elon Musk. I made Freddie Mercury face by default to show you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uJysQolr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/59f1950f0222a4ad78aaebc0f2ffaab3/b11fe/freddie-mercury-mosaic.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uJysQolr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/59f1950f0222a4ad78aaebc0f2ffaab3/b11fe/freddie-mercury-mosaic.png" alt="Freddie" title="Freddie Mercury Mosaic Show must go on - cartoon" width="800" height="799"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you have an example with edit mode that I used to add the bottom left 'HVITIS' title .&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Lk1JFYXS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/289db7a5b4a8f4818f874f5a350ce063/56c00/freddie-mercury-mosaic-edited.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Lk1JFYXS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/289db7a5b4a8f4818f874f5a350ce063/56c00/freddie-mercury-mosaic-edited.png" alt="Freddie Mercury LEGO Art" title="Freddie Mercury LEGO Art" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Convert your picture with online mosaic maker art now &lt;a href="https://hvitis.dev/mosaic-art-maker"&gt;here&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;This is good LEGO art alternative because you can order your own pieces on Pick a Brick and be unique. The coolest thing is that this app is always here. Save this page to your favorite so you can use it anytime you want! In 2021 you can have a new art build.&lt;/p&gt;

&lt;p&gt;You know what is also super awesome? Once you export the generated file, you can render it in stud.io and make it 3D. The quality and level of details is amazing:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8s0Dj5S4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/2288619ecc97ec757870ceaef66cf303/5f327/rendering-mosaic-3d-generated-in-online-free-tool-maker.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8s0Dj5S4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/2288619ecc97ec757870ceaef66cf303/5f327/rendering-mosaic-3d-generated-in-online-free-tool-maker.png" alt="3DStud.ioRender" title="3D Render of mosaic generated here" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is Freddie in zoomed 3D without editing to show the beauty of silver, fluorescent, transparent and other colors:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1XJZebcS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/d09be2a508fb693fc0129ce44b0954a8/5f327/freddie-mercury-mosaic-3d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1XJZebcS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/d09be2a508fb693fc0129ce44b0954a8/5f327/freddie-mercury-mosaic-3d.png" alt="Freddie3D" title="Freddie Mercury Mosaic Show must go on - cartoon 3d" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you would like to see the whole process from a software perspective you can check &lt;a href="https://hvitis.dev/project-lego-art-creator-mosaic-and-portraits-free-tutorial-using-javascript-react-gatsbyjs"&gt;my other post&lt;/a&gt; about how I was building it.&lt;/p&gt;

&lt;p&gt;Otherwise - &lt;a href="https://hvitis.dev/contact"&gt;&lt;strong&gt;let me know if you like it&lt;/strong&gt;&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Thank you!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Enter here &lt;a href="https://hvitis.dev/mosaic-art-maker"&gt;Mosaic Art maker&lt;/a&gt; and convert picture to LEGO.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;or listen to me talking about the software:&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Do you need more functionality in the generator? Drop me a message &lt;a href="https://hvitis.dev/contact"&gt;here&lt;/a&gt;. Did you learn anything reading this post? Tell me about your insights. You are most welcome to see more posts of this type - just go to &lt;a href="https://hvitis.dev"&gt;home page&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to make your own lego art
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;You need a board&lt;/li&gt;
&lt;li&gt;You can use your face picture to make art from photo - the tool is on your computer, I don’t store any files you upload.&lt;/li&gt;
&lt;li&gt;Convert the picture to LEGO board&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I was doing this as art therapy with LEGO. Making mosaic is very rewarding and you are becoming best LEGO artist when making your canvas. It doesn’t matter how much artists make, I do that for pleasure. &lt;/p&gt;

&lt;p&gt;It looks a bit like ASCII but it’s my favourite toy. You can make really anything, Beatels set, Rolling Stones, Star Wars Sith or Elon Musk. I made Freddie Mercury face by default to show you. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Lk1JFYXS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/289db7a5b4a8f4818f874f5a350ce063/56c00/freddie-mercury-mosaic-edited.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Lk1JFYXS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/289db7a5b4a8f4818f874f5a350ce063/56c00/freddie-mercury-mosaic-edited.png" alt="Lego Art Freddie Mercury" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is good LEGO art alternative because you can order your own pieces on Pick a Brick and be unique. The mosaic maker has exporting buttons so that you can order your pieces.&lt;/p&gt;

&lt;p&gt;The coolest thing is that this app is always here. Online. I do not collect any images or results you get with the maker.&lt;/p&gt;

&lt;p&gt;Save this page to your favourite so you can use it anytime you want! &lt;/p&gt;

&lt;p&gt;In 2021 - the year of staying indoors - you can have a new art build. Convert picture to LEGO art and share your results!&lt;/p&gt;

&lt;p&gt;Click &lt;a href="https://hvitis.dev/mosaic-art-maker"&gt;Here&lt;/a&gt; to test out the maker.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Django Rest Framework &amp; Filepond ReactJS</title>
      <dc:creator>george_pollock</dc:creator>
      <pubDate>Tue, 20 Oct 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/george_pollock/django-rest-framework-filepond-reactjs-3776</link>
      <guid>https://dev.to/george_pollock/django-rest-framework-filepond-reactjs-3776</guid>
      <description>&lt;h2&gt;
  
  
  Integrating DRF with Filepond ReactJS
&lt;/h2&gt;

&lt;p&gt;Why? Because it is amazing out-of-the-box solution for Pythonists. Just have a quick look:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kis9i3oG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://raw.githubusercontent.com/pqina/filepond-github-assets/master/filepond-animation-01.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kis9i3oG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://raw.githubusercontent.com/pqina/filepond-github-assets/master/filepond-animation-01.gif" alt="FilepondDjango" title="How to upload pictures via front end app to django rest backend" width="370" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is a Django REST Framework plugin for uploading pictures via Filepond components. It works amazing! Filepond has everything you might need for uploading pictures. Everything neatly works together and I am really happy after using it. Works on different browsers, integrates with Amazin S3 and has powerful options.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://django-rest-filepond-react-js.herokuapp.com/"&gt;Here&lt;/a&gt; you can check it live in action. (&lt;em&gt;It’s on heroku so you need to wait a lot to boot it up (and refresh the page if you get timedout).&lt;/em&gt;)&lt;/p&gt;

&lt;p&gt;Django is known to be cumbersome when uploading pictures. Thank god we have a ready to use solution that neatly integrates with Filepond. There has been some issues when understanding the &lt;em&gt;docs&lt;/em&gt; in my case that is why I decided to make a tutorial.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Goal: Integrate django-drf-filepond with react-filepond&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;What we need to do:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the previous &lt;a href="https://hvitis.dev/how-to-upload-files-with-filepond-and-drf-extension"&gt;tutorial on Filepond VueJS&lt;/a&gt; I wrote more on how to use DRF extension. Here I want to show you a piece of front-end code and give you &lt;a href="https://github.com/hvitis/django-rest-filepond-react-js/tree/main"&gt;boilerplate on github&lt;/a&gt; that you can discover on your own.&lt;/p&gt;

&lt;p&gt;You can also deploy it directly to heroku by clicking on the button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://heroku.com/deploy?template=https://github.com/hvitis/django-rest-filepond-react-js"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QuyDiwwm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.herokucdn.com/deploy/button.png" alt="Deploy to Heroku" width="147" height="32"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;( for more useful repos ready to deploy check out &lt;a href="https://dev.tolet-anybody-deploy-your-code-deploy-to-heroku-button"&gt;post on heroku buttons&lt;/a&gt; )&lt;/p&gt;

&lt;h2&gt;
  
  
  React component settings
&lt;/h2&gt;

&lt;p&gt;Generally it is pretty straight-forward. You can follow the official &lt;strong&gt;docs&lt;/strong&gt; at &lt;a href="https://github.com/pqina/react-filepond"&gt;the official repo&lt;/a&gt;. The most important part that is omitted there is that when installing and placing the VueJS component on your front-end remember to change &lt;strong&gt;name&lt;/strong&gt; to &lt;strong&gt;filepond&lt;/strong&gt;. In ReactJS case it is important also to change &lt;strong&gt;server&lt;/strong&gt; to our DRF endpoints &lt;em&gt;fp/process/&lt;/em&gt; to POST an upload.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;FilePond
  ref={ref =&amp;gt; (this.pond = ref)}
  files={this.state.files}
  allowMultiple={true}
  allowReorder={true}
  maxFiles={3}
  server="http://127.0.0.1:8000/fp/process/"
  name="filepond"
  oninit={() =&amp;gt; this.handleInit()}
  onupdatefiles={fileItems =&amp;gt; {
    // Set currently active file objects to this.state
    this.setState({
      files: fileItems.map(fileItem =&amp;gt; fileItem.file),
    })
  }}
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Handling all the class, functions and setState you can check out &lt;a href="https://github.com/hvitis/django-rest-filepond-react-js/blob/main/src/containers/Uploader.js"&gt;in the repo’s file&lt;/a&gt; if you are having problems. 💁🏻&lt;/p&gt;

&lt;p&gt;This is how it looks like when using on deployed heroku version:&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/deeb4fbe1e6880096d90a616f80df5a5/71f70/filepond-reactjs-django-example.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UIk_pJP5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/deeb4fbe1e6880096d90a616f80df5a5/4d236/filepond-reactjs-django-example.png" alt="FilepondReactJSExample" title="Uploadinf pictures to front end spa app" width="650" height="631"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let me know if that was helpful or if you want me to explain it better / more.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Did you make any mistakes when using Filepond or you’ve seen one here? Tell me about your insights. Leave a comment with YOUR opinion.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&amp;lt;!-- DOCS --&amp;gt;&amp;lt;!-- EXAMPLES --&amp;gt;&amp;lt;!--&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YoxBDTLp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/v1/./ss-swagger-postman-docs.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YoxBDTLp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/v1/./ss-swagger-postman-docs.PNG" alt="photo_tag" title="Some TAG info that will be visible" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
--&amp;gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>TUTORIAL OAuth2 Django 2 and Djoser - part 1</title>
      <dc:creator>george_pollock</dc:creator>
      <pubDate>Sat, 25 Jul 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/george_pollock/tutorial-oauth2-django-2-and-djoser-part-1-4hhb</link>
      <guid>https://dev.to/george_pollock/tutorial-oauth2-django-2-and-djoser-part-1-4hhb</guid>
      <description>&lt;h2&gt;
  
  
  OAuth2 Django 2 and Djoser - Tutorial pt 1 - Introduction
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;There is &lt;a href="https://github.com/hvitis/social_djoser_template"&gt;repo on GitHub&lt;/a&gt; in case you want to clone the code.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;''The truth is rarely pure and never simple.''
    - Oscar Wilde
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is so much confusion when it comes to OAuth and Django! I wasted quite a lot of time on getting lost inbetween another forks of another package, app or a library. Sadly, maintanance issues or REST non-REST packages adds to the confusion.&lt;/p&gt;

&lt;p&gt;After making a research I decided to choose &lt;a href="https://github.com/sunscrapers/djoser"&gt;&lt;strong&gt;Djoser library&lt;/strong&gt;&lt;/a&gt; that works quite well. Is maintained, has nice docs and could be used for OAuth2 integrations. Many libraries use &lt;strong&gt;social_django&lt;/strong&gt; (&lt;em&gt;social-auth-app-django&lt;/em&gt;) under the hood. This tutorial was made due to BETA social implementation that &lt;a href="https://djoser.readthedocs.io/en/latest/social_endpoints.html"&gt;does not have extended documentation&lt;/a&gt; ( &lt;strong&gt;yet&lt;/strong&gt;!).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The goal :&lt;/strong&gt; Use 1 library to get REST extension for Django Authentication with extended User model that work with Google OAuth2.
&lt;/h3&gt;

&lt;p&gt;Basically to kill two birds with one stone ( this harsh translation of polish &lt;em&gt;‘cook two meals over one campfire’&lt;/em&gt; always strikes me )&lt;/p&gt;

&lt;p&gt;Let´s get to the chase! What we will do here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 1&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
Start the project, install libraries and apps.&lt;/li&gt;
&lt;li&gt;Explain all neccessary &lt;strong&gt;settings&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Explain &lt;strong&gt;urls&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
Create Google OAuth credentials ( &lt;a href="https://hvitis.dev/oauth-django-djoser-tutorial-vuejs-facebook-one-click-button"&gt;Facebook in Part 2&lt;/a&gt; ).&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;POSTMAN&lt;/strong&gt; to test the basic flow. ( by the way here are, &lt;a href="https://hvitis.dev/5-ways-you-could-improve-your-automated-postman-tests"&gt;POSTMAN tricks&lt;/a&gt; and &lt;a href="https://hvitis.dev/5-lessons-for-intermediate-jedi-how-to-learn-postman"&gt;POSTMAN for Jedi&lt;/a&gt; posts in case you’re interested )&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://hvitis.dev/oauth-django-djoser-tutorial-vuejs-facebook-one-click-button"&gt;&lt;strong&gt;Part 2&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In contruction… 🚧🏗️&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Explain the basic flow - architecture chart - how does it work?&lt;/li&gt;
&lt;li&gt;Implement the basic flow in VueJS&lt;/li&gt;
&lt;li&gt;Implement the Facebook OAuth2&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Start the project, install libraries and apps.
&lt;/h2&gt;

&lt;p&gt;Start your virtual environment using &lt;a href="https://virtualenv.pypa.io/en/latest/"&gt;virtualenv&lt;/a&gt;, activate it and install django:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;virtualenv venvSocialDjoserDRFJWT
cd venvSocialDjoserDRFJWT
source bin/activate (on Unix)
Scripts\activate.bat (on Windows)
pip install django==2.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create project and one app for extending User model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;django-admin startproject SocialDjoser
cd SocialDjoser
python3 manage.py startapp accounts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let’s install all python-backend libraries we will use throught this tutorial ( later we also use npm-vue-js libraries ):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install django-cors-headers
pip install djangorestframework
pip install djangorestframework_simplejwt
pip install djoser (version 2.0.3 as of writing this tutorial)
pip install social-auth-app-django
pip install Pillow (for adding user's thumbnail - not related to social oauth)
pip install psycopg2 (JWT time )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;¡Important!&lt;/strong&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Djoser version 2.0.3 uses &lt;a href="https://python-social-auth.readthedocs.io/en/latest/configuration/django.html"&gt;&lt;strong&gt;social_django&lt;/strong&gt; (social-auth-app-django)&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;social_django&lt;/strong&gt; uses &lt;a href="https://github.com/python-social-auth/social-core"&gt;&lt;strong&gt;social_core&lt;/strong&gt; (social-auth-core)&lt;/a&gt; under the hood.&lt;/li&gt;
&lt;li&gt;We use &lt;a href="https://github.com/SimpleJWT/django-rest-framework-simplejwt"&gt;rest_framework_simplejwt (djangorestframework_simplejwt)&lt;/a&gt; for customizing information that comes in the JSON Web Token.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Explain all neccessary &lt;strong&gt;settings&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let’s have a look at the placings is settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSTALLED_APPS = [
    'corsheaders', # I always put it first here and in Middleware!
    'django.contrib.sites', # We add this as extra
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Project apps:
    'accounts', # The app we have created for extending User model. Needs to go before the DRF since it has User model that DRF uses.

    'rest_framework',
    'djoser',
    'social_django', # Not needed to add but pip install required. Adding it here will create additional acces to social user via admin
    'rest_framework_simplejwt',
    'rest_framework_simplejwt.token_blacklist' # Add it to avoid problems with migrations

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

&lt;/div&gt;



&lt;p&gt;Now let’s add CORS middleware and exceptions for developing purposes. Remember you shouldn´t whitelist everything in production!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MIDDLEWARE = [
    # IMPORTANT: CORS policies has to go before other entries
    'corsheaders.middleware.CorsMiddleware',

    # IMPORTANT: Essential when using django_social
    'social_django.middleware.SocialAuthExceptionMiddleware',
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The extra corsheaders middleware is for &lt;a href="https://python-social-auth.readthedocs.io/en/latest/configuration/django.html"&gt;allowing in-browser requests&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ok!&lt;/p&gt;

&lt;p&gt;Now Django REST Framework, JSON Web Token and Djoser settings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework_simplejwt.authentication.JWTAuthentication', # OAuth2, JWT
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.AllowAny', # Up to you to decide, depends on your project
    )
}

import datetime
from datetime import timedelta
from core import settings

SIMPLE_JWT = {
    ...
    'AUTH_HEADER_TYPES': ('Bearer', 'JWT',), # Adding Bearer for POSTMAN testing
    'USER_ID_FIELD': 'id',
    'USER_ID_CLAIM': 'user_id',

    'AUTH_TOKEN_CLASSES': (
        'rest_framework_simplejwt.tokens.AccessToken',
        # 'location.to.custom.token.CustomJWTToken' # This is optional - custom class where token could be manipulated e.g. enriched with tenants, UUIDs etc.
        ),
    ...
}

TEMPLATES = [
    {
        ...
        'OPTIONS': {
            ...
            'context_processors': [
                ...

                # Essential !!
                'social_django.context_processors.backends',
                'social_django.context_processors.login_redirect',
                ...
            ]
        }
    }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now comes the best part: &lt;strong&gt;Djoser and OAuth2&lt;/strong&gt;!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AUTHENTICATION_BACKENDS = (
    # We are going to implement Google, choose the one you need from docs
    'social_core.backends.google.GoogleOAuth2',

    # Crucial when logging into admin with username &amp;amp; password
    'django.contrib.auth.backends.ModelBackend',
)

# Client ID and Client Secret obtained from console.developers.google.com
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = 'YOUR_CLIENT_ID_KEY'

SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = 'YOUR_SECRET_KEY'

SOCIAL_AUTH_RAISE_EXCEPTIONS = False
# SOCIAL_AUTH_POSTGRES_JSONFIELD = True # Optional, how token will be saved in DB

white_list = ['http://localhost:8000/accounts/profile'] # URL you add to google developers console as allowed to make redirection

DJOSER = {
    "LOGIN_FIELD": "email", # Field we use to login on extended User model
    'SERIALIZERS': {
        'user': 'location.to.custom.serializers.CustomUserSerializer', # Custom Serializer to show more user data
        'current_user': 'location.to.custom.serializers.CustomUserSerializer', # Custom Serializer to show more user data
    },
    'SOCIAL_AUTH_ALLOWED_REDIRECT_URIS': white_list # Redirected URL we listen on google console
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok! We are done with settings. These are bare minimum to make Google OAuth2 work with DRF and JWT.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Explain &lt;strong&gt;urls&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;urlpatterns = [
    # Original Admin panel
    path('admin/', admin.site.urls),

    # Custom JWT implementation. That's optional. It's possible to do this with Djoser settings or just use the default JWT URL
    path('api/auth/jwt/create', CustomJWTToken.as_view()),

    # REST Implementation of Django Authentication system
    path('api/auth/', include('djoser.urls')),

    # Djoser Beta extension for social_django
    path('api/auth/social/', include('djoser.social.urls')),

    # The URL that you could use for testing and that later on can be used for Front-End app Authentication.
    path('accounts/profile/', RedirectSocial.as_view()),

    # The default Djoser endpoints for JWT.
    path('api/auth/', include('djoser.urls.jwt')),
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Create Google OAuth credentials ( &lt;a href="https://hvitis.dev/oauth-django-djoser-tutorial-vuejs-facebook-one-click-button"&gt;Facebook in Part 2&lt;/a&gt; ).
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://console.developers.google.com"&gt;Enter your account&lt;/a&gt; and here is how your console should look like.&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/53819775671a24a02d3ee23552cb877e/12874/oauth2-google-django-tutorial.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kYjGTkBF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/53819775671a24a02d3ee23552cb877e/4d236/oauth2-google-django-tutorial.png" alt="OAuth2Djoser" title="Google OAuth2 Django Djoser" width="650" height="271"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you need to put the redirection allowed URL&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/4e7f40a4335571203416fb3a81626481/12874/oauth2-google-django-tutorial-credentials.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C1lsYUB6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/4e7f40a4335571203416fb3a81626481/4d236/oauth2-google-django-tutorial-credentials.png" alt="OAuth2Djoser" title="Google OAuth2 Django Djoser" width="650" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Use POSTMAN to test the basic flow.
&lt;/h2&gt;

&lt;p&gt;You can &lt;a href="https://raw.githubusercontent.com/hvitis/social_djoser_template/master/postman_tests/social_djoser.postman_collection.json"&gt;download POSTMAN tests&lt;/a&gt; to import them and have a better understanding on how those endpoints work.&lt;/p&gt;

&lt;p&gt;They come with descriptions and scripted flow so you could have more insights. I will show you a quick test run to obtain a token.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First run the first GET request in order to obtain URL that opens you Google Login page. Copy the link nr 2. It’s an output of script that replaces HTTPS to HTTP that this endpoint returns ( you can do it manually )&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="///static/d8d2efb239958b367b3cd9dab1dd3d3b/27570/oauth-google-postman-authorization-uri.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--u2oEqoSa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/d8d2efb239958b367b3cd9dab1dd3d3b/4d236/oauth-google-postman-authorization-uri.png" alt="OAuth2DjoserGoogleTokenRegisterDjango" title="Google OAuth2 Django Djoser" width="650" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;This step is just a helper, don´t login via postman preview view. Just verify in preview of the second request that you are indeed seeing the login page ( could be skipped and done directly in the browser )&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="///static/0edffbc64695a30c3193a7db08246b8b/27570/oauth-google-postman-authorization-account.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fgiqWDHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/0edffbc64695a30c3193a7db08246b8b/4d236/oauth-google-postman-authorization-account.png" alt="OAuth2DjoserGoogleTokenRegisterDjango" title="Google OAuth2 Django Djoser" width="650" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;With the URL copied in step 1 open your browser and navigate to it. You should see a google select profile page or if you are using incognito mode ( or you’re not logged yet to any of google accounts ) you just see this:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="///static/5d096fd76c3afa45e4ca582713fb8160/13ec9/oauth-google-login-screen.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oYCkVgvv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/5d096fd76c3afa45e4ca582713fb8160/4d236/oauth-google-login-screen.png" alt="OAuth2DjoserGoogleTokenRegisterDjango" title="Google OAuth2 Django Djoser" width="650" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Finally, once logged in or account selected, you will see the outcome of the endpoint:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    path('accounts/profile/', RedirectSocial.as_view()),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which just returns JSON view with the code for POSTMAN testing purposes since we are not implementing it with front-end yet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.views import View
from django.http import JsonResponse

class RedirectSocial(View):

    def get(self, request, *args, **kwargs):
        code, state = str(request.GET['code']), str(request.GET['state'])
        json_obj = {'code': code, 'state': state}
        print(json_obj)
        return JsonResponse(json_obj)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="///static/458f61192fe6433b66a69092225a094a/6889d/oauth-google-response-code-state.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mP996YnL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/458f61192fe6433b66a69092225a094a/4d236/oauth-google-response-code-state.png" alt="OAuth2DjoserGoogleTokenRegisterDjango" title="Google OAuth2 Django Djoser" width="650" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy the code to 3rd POSTMAN endpoint (POST) and obtain TOKEN! 🎉🎊&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/8e0182fdb6dce7f0b2934884696504ee/37c2f/oauth-google-response-code-state-postman-how-to-obtain-token.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ed6yPAWA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/8e0182fdb6dce7f0b2934884696504ee/4d236/oauth-google-response-code-state-postman-how-to-obtain-token.png" alt="OAuth2DjoserGoogleTokenRegisterDjango" title="Google OAuth2 Django Djoser" width="650" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this token you can authenticate within DRF!&lt;/p&gt;

&lt;p&gt;Now seriously, go and make yourself a drink. 🍹 You deserve it!&lt;/p&gt;

&lt;p&gt;⏭️ In &lt;a href="https://hvitis.dev/oauth-django-djoser-tutorial-vuejs-facebook-one-click-button"&gt;the second part&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we implement those endpoints into &lt;strong&gt;VueJS front-end app&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;we extend the template with &lt;strong&gt;Facebook Sign In Button&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;➡️➡️➡️&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Did you implement social login with Django? How did you do it? How could I make this tutorial better for you? Share your insights and leave a comment with YOUR opinion.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&amp;lt;!-- DOCS --&amp;gt;&amp;lt;!-- EXAMPLES --&amp;gt;&amp;lt;!--&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YoxBDTLp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/v1/./ss-swagger-postman-docs.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YoxBDTLp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/v1/./ss-swagger-postman-docs.PNG" alt="photo_tag" title="Some TAG info that will be visible" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
--&amp;gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>TUTORIAL Django OAuth2 1-click Facebook login with VueJS - part 2</title>
      <dc:creator>george_pollock</dc:creator>
      <pubDate>Thu, 23 Jul 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/george_pollock/tutorial-django-oauth2-1-click-facebook-login-with-vuejs-part-2-3pa0</link>
      <guid>https://dev.to/george_pollock/tutorial-django-oauth2-1-click-facebook-login-with-vuejs-part-2-3pa0</guid>
      <description>&lt;h2&gt;
  
  
  Django OAuth2 1-click - Tutorial pt 2 - Facebook login with Djoser
&lt;/h2&gt;

&lt;p&gt;In order to obtain token to access out Django backend using Facebook Social Login we need to do the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set up a new app in Developers Facebook (no need to change hosts etc. you can easily redirect to localhost for testing purposes)&lt;/li&gt;
&lt;li&gt;Define settings and secret information in &lt;em&gt;settings.py&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Extend the Djoser Facebook views class for customization (not necessary but might be useful for explainint purposes)&lt;/li&gt;
&lt;li&gt;Add customized view to &lt;strong&gt;AUTHENTICATION_BACKENDS&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Whitelist view that we will be redirected to (FrontEnd) in Djoser´s &lt;strong&gt;SOCIAL_AUTH_ALLOWED_REDIRECT_URIS&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Make sure that &lt;strong&gt;urls.py&lt;/strong&gt; are set up in a right way.&lt;/li&gt;
&lt;li&gt;Test!&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  0. Setting up the app
&lt;/h2&gt;

&lt;p&gt;In order to set up the app follow steps from &lt;a href="https://simpleisbetterthancomplex.com/tutorial/2016/10/24/how-to-add-social-login-to-django.html"&gt;this amazing tutorial on django_core&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Defining scopes (!)
&lt;/h2&gt;

&lt;p&gt;In order to make it work you need email address from Facebook, otherwise Django will throw an error due to registering issues (email required).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SOCIAL_AUTH_FACEBOOK_KEY = 'YOUR_FACEBOOK_APP_ID'
SOCIAL_AUTH_FACEBOOK_SECRET = 'YOUR_APPS_SECRET_KEY'

# IMPORTANT! :
SOCIAL_AUTH_FACEBOOK_SCOPE = ['email']
SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_PARAMS = {
    'fields': 'email'
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Extending views.py
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# djoser/facebook.py

from social_core.backends.facebook import FacebookOAuth2

class CustomFacebookOAuth2(FacebookOAuth2):
    REDIRECT_STATE = False
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Add view to AUTHENTICATION_BACKENDS
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AUTHENTICATION_BACKENDS = (
    # Important for accessing admin with django_social
    # 'social_core.backends.google.GoogleOAuth2',
    'core.restconf.djoser.facebook.CustomFacebookOAuth2',
    'django.contrib.auth.backends.ModelBackend',
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Whitelist your redirection URL
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# where your DJOSER settings are
DJOSER = {
    # "LOGIN_FIELD": "email",
    # 'SEND_ACTIVATION_EMAIL': False,
    'SOCIAL_AUTH_ALLOWED_REDIRECT_URIS': [
    'http://localhost:8000/temporary-redirect-for-testing/',
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Make sure about urls.py
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# main/settings.py

# I made my URLs custom:
urlpatterns = [
    # ...
    path('api/auth/social/', include('djoser.social.urls')),

    # This is URL we will use for future testing in pt. 5
    # path('temporary-redirect-for-testing/', RedirectSocial.as_view()),
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will give us 2 endpoints to test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET http://localhost:8000/api/auth/social/o/facebook/?redirect_uri=http://localhost:8000/temporary-redirect-for-testing/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;that returns us URL we have to enter in a browser: (note api version that you can customize via &lt;a href="https://python-social-auth.readthedocs.io/en/latest/backends/facebook.html"&gt;social_core settings&lt;/a&gt; &lt;strong&gt;SOCIALS_AUTH_FACEBOOK_API_VERSION&lt;/strong&gt; - that is optional)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "authorization_url": "https://www.facebook.com/v3.2/dialog/oauth?client_id=YOUR_FACEBOOK_APP_ID&amp;amp;redirect_uri=http://localhost:8000/temporary-redirect-for-testing/&amp;amp;state=THIS_IS_GENERATED_BY_DJANGOf&amp;amp;return_scopes=true&amp;amp;scope=email"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST http://localhost:8000/api/auth/social/o/facebook/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one requires 2 parameters:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;state&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;both we obtain after calling &lt;strong&gt;redirect_uri&lt;/strong&gt; from first call and giving Facebook credentials for any Facebook user.&lt;/p&gt;

&lt;p&gt;Important to remember that this call has to be of:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Content-Type: application/x-www-form-urlencoded&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Calling this endpoint with a code and state will work only for the first time. Every next time renders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "non_field_errors": ["Authentication process canceled"]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But successful call gives us:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "access": "eyJ0eXAiOiJK...",
  "refresh": "eyJ0eXAiOiJ...",
  "user": "FACEBOOK_USER_WE_LOGGED_WITH@gmail.com"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. How do we test it?
&lt;/h2&gt;

&lt;p&gt;This is where a Testing endpoint would come in handy. We need the redirect view that will be called by facebook after executing &lt;strong&gt;authorization_url&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let´s create the view that will show us the &lt;strong&gt;code&lt;/strong&gt; and &lt;strong&gt;state&lt;/strong&gt; returned by facebook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# core/restconf/djoser/views.py
from django.http import JsonResponse
from django.views import View

class RedirectSocial(View):

    def get(self, request, *args, **kwargs):
        code, state = str(request.GET['code']), str(request.GET['state'])
        json_obj = {'code': code, 'state': state}
        print(json_obj)
        return JsonResponse(json_obj)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        print(context)
        return context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s add it to &lt;strong&gt;urls.py&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# main/settings.py

# Import it from wherever you create the view.
from core.restconf.djoser.views import RedirectSocial

# I made my URLs custom:
urlpatterns = [
    # ...
    path('api/auth/social/', include('djoser.social.urls')),
    path('temporary-redirect-for-testing/', RedirectSocial.as_view()),
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the final test:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We execute the 1st GET url&lt;/li&gt;
&lt;li&gt;We copy &lt;strong&gt;authorization_url&lt;/strong&gt; from the response to the browser.&lt;/li&gt;
&lt;li&gt;We log in to the app&lt;/li&gt;
&lt;li&gt;We get redirected to our testing RedirectSocial url:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="///static/21e1977971e51d032ceb86732c40c75c/5f327/facebook-oauth2-django-redirect.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LbeIgEsj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/21e1977971e51d032ceb86732c40c75c/4d236/facebook-oauth2-django-redirect.png" alt="OAuth2Djoser" title="Facebook OAuth2 Django Djoser" width="650" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🎉🎉🥳🥳 &lt;strong&gt;You did it!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now you can use your &lt;strong&gt;code&lt;/strong&gt; and &lt;strong&gt;state&lt;/strong&gt; to call the POST url. It can be done from your Django app (if you are not using JS frameworks) or it can be called from your Front End ap using e.g. &lt;strong&gt;axios&lt;/strong&gt; or &lt;strong&gt;fetch&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var myHeaders = new Headers()
myHeaders.append('Content-Type', 'application/x-www-form-urlencoded')
myHeaders.append('Cookie', 'sessionid=m4c2oc0ahj7dibomn4a2d8uo8wmjrcy0')

var urlencoded = new URLSearchParams()
urlencoded.append('code', 'YOUR_CODE_OBTAINED_FROM_REDIRECT')
urlencoded.append('state', 'YOUR_STATE_OBTAINED_FROM_REDIRECT')

var requestOptions = {
  method: 'POST',
  headers: myHeaders,
  body: urlencoded,
  redirect: 'follow',
}

fetch('http://localhost:8000/api/auth/social/o/facebook/', requestOptions)
  .then(response =&amp;gt; response.text())
  .then(result =&amp;gt; console.log(result))
  .catch(error =&amp;gt; console.log('error', error))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Dont’t forget to change redirect urls for front-end app&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Did you make any mistakes when using this tutorial or you’ve seen one here? Tell me about your insights. Leave a comment with YOUR opinion or QUESTION.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&amp;lt;!-- DOCS --&amp;gt;&amp;lt;!-- EXAMPLES --&amp;gt;&amp;lt;!--&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YoxBDTLp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/v1/./ss-swagger-postman-docs.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YoxBDTLp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/v1/./ss-swagger-postman-docs.PNG" alt="photo_tag" title="Some TAG info that will be visible" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
--&amp;gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Easiest, Quickest and Most elegant way to set up Django 2 Gallery</title>
      <dc:creator>george_pollock</dc:creator>
      <pubDate>Mon, 20 Jul 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/george_pollock/the-easiest-quickest-and-most-elegant-way-to-set-up-django-2-gallery-1fi0</link>
      <guid>https://dev.to/george_pollock/the-easiest-quickest-and-most-elegant-way-to-set-up-django-2-gallery-1fi0</guid>
      <description>&lt;h2&gt;
  
  
  How to make beautiful, responsive, gallery in Django
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;There is &lt;a href="https://github.com/hvitis/django-lightbox-photologue"&gt;repo on GitHub&lt;/a&gt; in case you want to clone the code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I was struggling many times with making my own custom Gallery or with just adding different options for photos. What is the reason of reinventing the wheel? I did not know this solution and I was tired of reviewing apps and repos that are &lt;a href="https://djangopackages.org/grids/g/gallery/"&gt;not maintained anymore&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The lightbox itself is an old technology but &lt;a href="https://github.com/lokesh/lightbox2/releases"&gt;it’s maintained and alive&lt;/a&gt;. Works very well and out of the box. You can &lt;a href="https://lokeshdhakar.com/projects/lightbox2/"&gt;see some examples here&lt;/a&gt; on how smoot it works.&lt;/p&gt;

&lt;p&gt;The photologue is also maintained and it has amazing functionalities (see below). It also works with AWS Amazon S3 Bucket.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;This is how it looks like&lt;/strong&gt; in the Template. It’s possible navigate with keyboard between the images and the transition is great.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="///static/d7cd46ed50a89a61d291c0502f8065a6/5f327/django-photologue-lightbox.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1JGuMdnT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/d7cd46ed50a89a61d291c0502f8065a6/4d236/django-photologue-lightbox.png" alt="Photologue Admin" width="650" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;This is how it looks like&lt;/strong&gt; in the Admin:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="///static/614923c583b29acda904b7e3d8d9b801/66d4a/django-photologue-admin.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rHdgH130--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/614923c583b29acda904b7e3d8d9b801/4d236/django-photologue-admin.png" alt="Photologue Admin" width="650" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s code it
&lt;/h2&gt;

&lt;p&gt;To implement it in your app you need to do a few things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/lokesh/lightbox2/releases"&gt;Download lightbox&lt;/a&gt; and unzip it. I would not recommend adding CDN since there are different versions and some of them require initializing the galleries separately.&lt;/li&gt;
&lt;li&gt;Load JS and CSS as static files. You can load a lightbox+jquery file from zipped package or you can load just lightbox JS in case you are already using JQuery.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;!--Lightbox CSS --&amp;gt;
    &amp;lt;link href="{% static 'lightbox.css' %}" rel="stylesheet"&amp;gt;
&amp;lt;/head&amp;gt;

...
    &amp;lt;!--Lightbox and JQuery--&amp;gt;
    &amp;lt;script src="{% static 'lightbox-plus-jquery.js' %}"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don’t forget about&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 manage.py collectstatic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://django-photologue.readthedocs.io/en/stable/pages/installation.html"&gt;Install photologue&lt;/a&gt; and extend your model that has photos/gallery. In my case it´s a blog post and FOreignKey. Your case might be different. Everything depends on &lt;a href="https://www.geeksforgeeks.org/python-relational-fields-in-django-models/"&gt;DB relations&lt;/a&gt; you need to apply.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.db import models
from photologue.models import Gallery
# Create your models here.
class Post(models.Model):
    gallery = models.ForeignKey(Gallery, on_delete=models.SET_NULL, null=True)

    title = models.CharField(max_length=199)
    content = models.TextField()

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Pass your models to views.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.shortcuts import render
from .models import Post

def homepage(request):
    post_list = Post.objects.all()
    context = {}
    context['post_list'] = post_list
    return render(request, 'base.html', context)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the view to URL&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;urlpatterns = [
    path('', homepage, name='homepage'),
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Iterate through gallery loaded into Template context.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="container"&amp;gt;
  {% for post in post_list %}
  &amp;lt;h1&amp;gt;{{post.title}}&amp;lt;/h1&amp;gt;
  &amp;lt;p&amp;gt;{{post.content}}&amp;lt;/p&amp;gt;

  &amp;lt;!--Gallery--&amp;gt;
  &amp;lt;div class="row"&amp;gt;
    {% for photo in post.gallery.sample %}
    &amp;lt;a
      class="align-self-center"
      title="{{ photo.title }}"
      href="{{ photo.get_display_url }}"
      data-lightbox="gallery-example"
      max-height="150px"
    &amp;gt;
      &amp;lt;img src="{{ photo.get_thumbnail_url }}" /&amp;gt;
    &amp;lt;/a&amp;gt;
    {% endfor %}
  &amp;lt;/div&amp;gt;
  {% endfor %}
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Photologue has &lt;em&gt;get_display_url&lt;/em&gt; for big photos and &lt;em&gt;get_thumbnail_url&lt;/em&gt; for thumbnails. You can &lt;strong&gt;customize their sizes&lt;/strong&gt; , effects and more in your Django admin!&lt;/p&gt;

&lt;p&gt;The only thing to make lightbox 2 work is part of HTML tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data-lightbox="NAME_OF_YOUR_GALLERY"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;so don´t miss it! Also in case you want to have more than one galleries remember to change those tags e.g. :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!--first galery with 3 photos:--&amp;gt;

&amp;lt;a href="{{ photo.get_display_url }}" data-lightbox="FIRST_GALLERY" max-height="150px"&amp;gt;&amp;lt;img src="{{ photo.get_thumbnail_url }}" &amp;gt;&amp;lt;/a&amp;gt;
&amp;lt;a href="{{ photo.get_display_url }}" data-lightbox="FIRST_GALLERY" max-height="150px"&amp;gt;&amp;lt;img src="{{ photo.get_thumbnail_url }}" &amp;gt;&amp;lt;/a&amp;gt;
&amp;lt;a href="{{ photo.get_display_url }}" data-lightbox="FIRST_GALLERY" max-height="150px"&amp;gt;&amp;lt;img src="{{ photo.get_thumbnail_url }}" &amp;gt;&amp;lt;/a&amp;gt;

&amp;lt;!--second galery with 2 photos:--&amp;gt;

&amp;lt;a href="{{ photo.get_display_url }}" data-lightbox="SECOND_GALLERY" max-height="150px"&amp;gt;&amp;lt;img src="{{ photo.get_thumbnail_url }}" &amp;gt;&amp;lt;/a&amp;gt;
&amp;lt;a href="{{ photo.get_display_url }}" data-lightbox="SECOND_GALLERY" max-height="150px"&amp;gt;&amp;lt;img src="{{ photo.get_thumbnail_url }}" &amp;gt;&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope this 🖼️ Gallery solution came in handy!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Did you make progress when using this post? Tell me about your insights. Leave a comment with YOUR opinion.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&amp;lt;!-- DOCS --&amp;gt;&amp;lt;!-- EXAMPLES --&amp;gt;&amp;lt;!--&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YoxBDTLp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/v1/./ss-swagger-postman-docs.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YoxBDTLp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/v1/./ss-swagger-postman-docs.PNG" alt="photo_tag" title="Some TAG info that will be visible" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
--&amp;gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>REST API Best practices - Why's and How's</title>
      <dc:creator>george_pollock</dc:creator>
      <pubDate>Wed, 24 Jun 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/george_pollock/rest-api-best-practices-why-s-and-how-s-304n</link>
      <guid>https://dev.to/george_pollock/rest-api-best-practices-why-s-and-how-s-304n</guid>
      <description>&lt;h2&gt;
  
  
  Why your API should be REST ?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Representational_state_transfer"&gt;REST&lt;/a&gt; helps. A lot. Let’s focus on what REST gives your team. The picture I’ve chosen respresents the idea very well. In a crowd of backenders, front-enders, clients, users and testers - well design API increases productivity and efficiency, decreases frustration, let’s people cooperate better. In case you’re a bit confused on what’s REST try &lt;a href="https://www.codecademy.com/articles/what-is-rest"&gt;improving your knowledge&lt;/a&gt; before continuing.&lt;/p&gt;

&lt;p&gt;If you are a &lt;strong&gt;front end&lt;/strong&gt; developer you may want to save yourself writing custom messages for bad error requests. You may want to have a reusable functions for services and getting data, this shines when things are consistent. When requests you make are predictible, when their codes represent the actual state.&lt;/p&gt;

&lt;p&gt;If you are a &lt;strong&gt;back end&lt;/strong&gt; developer you may want to check your services by calling them while developing. It’s easier to debug if you can actually read in a message what did just happen instead of seeing empty body. Coding is not guessing, requests responses should be self explanatory.&lt;/p&gt;

&lt;p&gt;If you are a &lt;strong&gt;tester&lt;/strong&gt; then you should make everybody follow the REST practices, otherwise you will go nuts. Backend API testing tools like &lt;a href="https://learning.postman.com/getting-started/"&gt;POSTMAN&lt;/a&gt; could ease your work, especially if you know &lt;a href="https://hvitis.dev/5-lessons-for-intermediate-jedi-how-to-learn-postman"&gt;some tricks&lt;/a&gt;. If you want to perform server side automation testing and write set of tests for the API - it will be hard if all you get is unconsistency in HTTP responses. Even if your API testing resume says: &lt;em&gt;automation tester&lt;/em&gt; - it only makes sense if the API is well designed.&lt;/p&gt;

&lt;p&gt;If you are a &lt;strong&gt;user&lt;/strong&gt; - you have a limited contact with developers, maybe the only thing that could help you is documentation. Well designed API could benefit from rest api documentation tools like &lt;a href="https://swagger.io/"&gt;SWAGGER&lt;/a&gt;, &lt;a href="https://www.sphinx-doc.org/en/master/"&gt;Sphinx&lt;/a&gt; or &lt;a href="https://learning.postman.com/docs/postman/api-documentation/documenting-your-api/"&gt;POSTMAN&lt;/a&gt; but the best documentation won’t have all the possible error you may encounter when using API. That is why for the sake of the future and potential integrations or exposing your API to customers, please, design well!&lt;/p&gt;

&lt;h2&gt;
  
  
  How to design well ?
&lt;/h2&gt;

&lt;p&gt;Here is the list of must haves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Error handling&lt;/li&gt;
&lt;li&gt;Methods&lt;/li&gt;
&lt;li&gt;Naming consistency&lt;/li&gt;
&lt;li&gt;Resources&lt;/li&gt;
&lt;li&gt;Returning objects&lt;/li&gt;
&lt;li&gt;Slash redirect&lt;/li&gt;
&lt;li&gt;Status codes&lt;/li&gt;
&lt;li&gt;Query parameters&lt;/li&gt;
&lt;li&gt;Versioning&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Error handling
&lt;/h3&gt;

&lt;p&gt;In order to provide more specific machine-readable messages with an error response, the API clients can react to errors more effectively and eventually it makes the API services much more reliable from the REST API testing perspective. Clients could benefit a lot from a good error handling since they can use the message strings comming directly from backend ( that eases translation issues ).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For non-success conditions, developers SHOULD be able to write one piece of code that handles errors consistently across different Microsoft REST API Guidelines services.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This quote comes from &lt;a href="https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md"&gt;Microsoft’s REST API design best practices&lt;/a&gt; (it’s a great place to learn although it often shows design examples of api architecture for a huge project).&lt;br&gt;&lt;br&gt;
The quote says you need a wrapper. Some class or function that will be responsibe for showing a consistant error message for non-success requests. One important reminder: &lt;em&gt;Error responses MUST use standard HTTP status codes in the 400 or 500 range to detail the general category of error&lt;/em&gt;.&lt;br&gt;&lt;br&gt;
In case you are developing a huge system then go back and take a look at &lt;a href="https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md#examples"&gt;Microsoft’s example&lt;/a&gt;. My take on this for smaller projects would be as follows:&lt;/p&gt;
&lt;h5&gt;
  
  
  Error : Object
&lt;/h5&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Required&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;code&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;✔&lt;/td&gt;
&lt;td&gt;One of a server-defined set of error codes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;target&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;The target of the error.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;message&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;✔&lt;/td&gt;
&lt;td&gt;A human-readable representation of the error.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;details&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;details[]&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;An array of details about specific errors that led to this reported error.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h5&gt;
  
  
  Details : Object
&lt;/h5&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Required&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;code&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;✔&lt;/td&gt;
&lt;td&gt;A more specific error code than was provided by the containing error.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;target&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;The target of the error.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;message&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;✔&lt;/td&gt;
&lt;td&gt;A human-readable representation of the error details.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The simple design example example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "error": {
    "code": "WrongMediaType",
    "message": "Data types accepted: csv, json."
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(this message should be returned along with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/415"&gt;status code 413&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Other extended example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "error": {
    "code": "BadArgument",
    "target": "GetAllCatsService",
    "message": "Data introduced has 1 error.",
    "details": [
      {
        "code": "NullValue",
        "target": "CatWeigth",
        "message": "Cat's weight must not be null"
      }
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The way you name your key&amp;amp;value pairs in returned object is totally up to you. The way you construct your wrapper is also your choice although you may want to &lt;a href="https://github.com/topics/error-handling"&gt;use one of existing libraries&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SUM_UP:&lt;/strong&gt; Error handling is extremely important for backend automation testing and usability, it also could bring more profits for clients. It is possible to start small with a simple error / message object that could be extended with time and complexity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Methods
&lt;/h3&gt;

&lt;p&gt;There is &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods"&gt;many HTTP methods&lt;/a&gt; but you should use at least those:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GET&lt;/li&gt;
&lt;li&gt;POST&lt;/li&gt;
&lt;li&gt;PUT&lt;/li&gt;
&lt;li&gt;DELETE&lt;/li&gt;
&lt;li&gt;PATCH
(You should know what is the difference between POST/PUT/PATCH)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using methods is strictly connected with naming consistency because the method themselves are verbs which is a direct reason why you should avoid using verbs in your URLs. Instead of duplicating code and making it unmaintainable and unintuitive - use methods well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET: https://yourdomain.com/getCats ⬅️🛑Wrong
GET: https://yourdomain.com/cats ⬅️✅ Good

POST: https://yourdomain.com/getCats ⬅️🛑Wrong
GET: https://yourdomain.com/cats ⬅️✅ Good

GET: https://yourdomain.com/getCats ⬅️🛑Wrong
GET: https://yourdomain.com/getCat/{id} ⬅️🛑Wrong
POST: https://yourdomain.com/postCats ⬅️🛑Wrong
DELETE: https://yourdomain.com/deleteCats ⬅️🛑Wrong

GET: https://yourdomain.com/cats ⬅️✅ Good
GET: https://yourdomain.com/cats/{id} ⬅️✅ Good
POST: https://yourdomain.com/cats ⬅️✅ Good
DELETE: https://yourdomain.com/cats ⬅️✅ Good
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods"&gt;more methods&lt;/a&gt; and more &lt;a href="https://tools.ietf.org/rfc/rfc7231.txt"&gt;ON methods&lt;/a&gt;. Read-up before continuing!&lt;/p&gt;

&lt;h4&gt;
  
  
  Difference between POST/PUT/PATCH
&lt;/h4&gt;

&lt;p&gt;It’s pretty simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;POST&lt;/strong&gt; creates a new resource that did not exist before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST:
URL: https://yourdomain.com/cats/
REQUEST:

{
  "name": "George",
  "color": "black",
  "is_adopted": true
}

RESPONSE CODE: 201
RESPONSE:

{
  "id": 1,
  "name": "George",
  "color": "black",
  "is_adopted": true
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;PUT&lt;/strong&gt; updates resource previously created with a new object information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PUT:
URL: https://yourdomain.com/cats/{catId}
REQUEST:

{
  "name": "Bob",
  "color": "white",
  "is_adopted": false
}

RESPONSE CODE: 200
RESPONSE:

{
  "id": 1,
  "name": "Bob",
  "color": "white",
  "is_adopted": false
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;PATCH&lt;/strong&gt; updates resource previously created with partial information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PUT:
URL: https://yourdomain.com/cats/{catId}
REQUEST:

{
  "name": "Zoey"
}

RESPONSE CODE: 200
RESPONSE:

{
  "id": 1,
  "name": "Zoey",
  "color": "white",
  "is_adopted": false
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Naming consistency
&lt;/h3&gt;

&lt;p&gt;It’s simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;URIs resources as nouns - &lt;em&gt;do not&lt;/em&gt; use verbs in your URI
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET: domain.com/getCats ⬅️🛑Wrong
GET: domain.com/getCat/{id} ⬅️🛑Wrong
POST: domain.com/postCats ⬅️🛑Wrong
DELETE: domain.com/deleteCats ⬅️🛑Wrong

GET: domain.com/cats ⬅️✅ Good
GET: domain.com/cats/{id} ⬅️✅ Good
POST: domain.com/cats ⬅️✅ Good
DELETE: domain.com/cats ⬅️✅ Good
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Pluralized resources
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET: domain.com/cat ⬅️🛑Wrong
GET: domain.com/cat/{id} ⬅️🛑Wrong

GET: domain.com/cats ⬅️✅ Good
GET: domain.com/cats/{id} ⬅️✅ Good
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Lowercase letters and dashes
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET: domain.com/Cats ⬅️🛑Wrong

GET: domain.com/cats ⬅️✅ Good

---

GET: domain.com/cat_races ⬅️🛑Wrong

GET: domain.com/cat-races ⬅️✅ Good
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;(American) &lt;strong&gt;English&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET: domain.com/gatos ⬅️🛑Wrong

GET: domain.com/cats ⬅️✅ Good
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;No file extensions
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET: domain.com/cats.pdf ⬅️🛑Wrong

GET: domain.com/cats ⬅️✅ Good
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Do not use trailing slashes
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET: domain.com/cats/ ⬅️🛑Wrong

GET: domain.com/cats ⬅️✅ Good
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Snake_casing for query parameters
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET: domain.com/cats?skinColor=black ⬅️🛑Wrong

GET: domain.com/cats?skin_color=black ⬅️✅ Good
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;They should be flat, no nesting.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET: domain.com/animals/{id}/family/{id}/colors/{id}/cats ⬅️🛑Wrong

GET: domain.com/cats ⬅️✅ Good
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;If nested is required it should be shallow.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET: domain.com/animals/{id}/family/{id}/colors/{id}/cats ⬅️🛑Wrong

GET: domain.com/animals/{id}/cats ⬅️✅ Good
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Returning objects
&lt;/h3&gt;

&lt;p&gt;It depends on your client and architecture but in most cases it’s good to return a body on creating resources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "result": {
    "cat": {
      "id": 1,
      "name": "Georgina"
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You could think about wrapping the responses with additional info but you need to remember that certain requests &lt;strong&gt;should return empty body&lt;/strong&gt; e.g. DELETE requests. Once the resource has been deleted and status code 204 returned then body should be empty. In most cases the decision on body of successful requests is up to you or your front-end collegue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Slash redirect
&lt;/h3&gt;

&lt;p&gt;As part of naming consistency: &lt;strong&gt;do not use trailing forward slashes&lt;/strong&gt;. In case of using slashes e.g. by your users (mistakes / no docs etc) you should try to redirect to original resource. It’s an interesting topic, try &lt;a href="https://www.danielmorell.com/guides/htaccess-seo/redirects/https-www-and-trailing-slash"&gt;reading more about it&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“The trailing slash must not have specific semantics. Resource paths must deliver the same results whether they have the trailing slash or not.” - &lt;a href="https://opensource.zalando.com/restful-api-guidelines/index.html#api-naming"&gt;Zalando’s RESTful API guidelines&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Status codes
&lt;/h3&gt;

&lt;p&gt;Like with HTTP methods &lt;a href="https://www.restapitutorial.com/httpstatuscodes.html"&gt;there is many of them&lt;/a&gt;. Try starting from the basics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;200s
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP_200_OK
HTTP_201_CREATED
HTTP_204_NO_CONTENT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;300s
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;400s
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP_400_BAD_REQUEST
HTTP_401_UNAUTHORIZED
HTTP_403_FORBIDDEN
HTTP_404_NOT_FOUND
HTTP_405_METHOD_NOT_ALLOWED
HTTP_408_REQUEST_TIMEOUT
HTTP_415_UNSUPPORTED_MEDIA_TYPE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Important to know the &lt;strong&gt;difference&lt;/strong&gt; between &lt;strong&gt;401&lt;/strong&gt; and &lt;strong&gt;403&lt;/strong&gt; :&lt;br&gt;&lt;br&gt;
&lt;strong&gt;401&lt;/strong&gt; - No credentials, no token, unauthenticated&lt;br&gt;&lt;br&gt;
&lt;strong&gt;402&lt;/strong&gt; - No authorization for the resource, role not correct, not enough eprmissions. Basically e.g. you may want to access admin resources as a simple user.&lt;/p&gt;
&lt;h3&gt;
  
  
  Query parameters
&lt;/h3&gt;

&lt;p&gt;Query resources via url parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;domain.com/cats?name=georgina&amp;amp;color=black
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stick with &lt;a href="https://opensource.zalando.com/restful-api-guidelines/#137"&gt;conventional query parameters&lt;/a&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Versioning
&lt;/h3&gt;

&lt;p&gt;If you are not working on a &lt;strong&gt;mobile app&lt;/strong&gt; or in a &lt;strong&gt;bigger team&lt;/strong&gt; you can skip it for now. This is very important if you are planning an API for a mobile app because app updates take long time to develop or deliver and it’s difficult to synchronise the changes with the backend. In case you are starting a project in a bigger team or a company, versioning is also extremly important since it allows more agile development - backenders don´t have to wait for front-enders. You can deploy your new API without worrying that you’ll break the client’s app. There is many REST API verioning strategies, at the end the goal is to maintain backward compatibility and avoid code duplication.&lt;br&gt;&lt;br&gt;
There is multiple possibilities of versioning schemes for your API:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Versioning via URL
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;urlpatterns = [
    url(
        include('v1/registration',
        register_via_email
    ),
    url(
        include('v2/registration',
        register_via_oauth
    )
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Versioning via hostname:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://v1.yourdomain.com/registration/
https://v2.yourdomain.com/registration/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Versioning via parameter:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://yourdomain.com/registration/?version=1
https://yourdomain.com/registration/?version=2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Restful API best practices when it comes to way of versioning API - doesn’t exist. Remember that your case might be different and your needs differ too - choose what is the best solution for you depending on the circumstances. Google has a &lt;a href="https://cloud.google.com/blog/products/gcp/api-design-which-version-of-versioning-is-right-for-you"&gt;great source&lt;/a&gt; on versioning API, you should check it out before laying first lines of code.&lt;/p&gt;

&lt;p&gt;Once you use versioning you can benefit from it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def registration_type(self):
    if self.request.version == 'v1':
        return register_via_email(self.body.email, self.body.password)
    return register_via_oauth(self.body.token)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;SUM_UP:&lt;/strong&gt; API Versioning is a great way to implement changes to code but it should be used if other methods are unavailable, use it conciously to not introduce unnecessary complexity.&lt;/p&gt;







&lt;p&gt;&lt;em&gt;Did you make any mistakes when using REST API or you’ve seen one here? Tell me about your insights. Leave a comment with YOUR opinion.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&amp;lt;!-- DOCS --&amp;gt;&amp;lt;!-- EXAMPLES --&amp;gt;&amp;lt;!--&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YoxBDTLp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/v1/./ss-swagger-postman-docs.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YoxBDTLp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/v1/./ss-swagger-postman-docs.PNG" alt="photo_tag" title="Some TAG info that will be visible" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
--&amp;gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to implement reCAPTCHA v3</title>
      <dc:creator>george_pollock</dc:creator>
      <pubDate>Fri, 12 Jun 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/george_pollock/how-to-implement-recaptcha-v3-14pl</link>
      <guid>https://dev.to/george_pollock/how-to-implement-recaptcha-v3-14pl</guid>
      <description>&lt;h2&gt;
  
  
  reCAPTCHA v3 - prepare yourself for bots!
&lt;/h2&gt;

&lt;p&gt;I will just quickly explain you what is reCAPTCHA, give you some explanation on how it works and we will go to examples and usage.&lt;/p&gt;

&lt;h3&gt;
  
  
  What and how ? 👨‍🎓
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;reCAPTCHA&lt;/strong&gt; is a technology that assesses probability that the entity that uses your web-code (page, app, portal etc) is a human and not a bot ( or the other way around ). Grabbing information of behaviour (of a user or a bot) it encapsulates it in the token that gets send to your server. On your server, the token is being send again to Google for returning the assessment on how probable is that the token was generated by a human. Part of response returned from Google to your server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "score": number // the score for request (0.0 likely bot - 1.0 likely human)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Having this information you could use it to later in your logic e.g. to return 404 for suspicious requests.&lt;/p&gt;

&lt;p&gt;It uses AI and information gathering under the hood which may be disliked by certain people. You can &lt;a href="https://webmasters.googleblog.com/2018/10/introducing-recaptcha-v3-new-way-to.html"&gt;learn more&lt;/a&gt; on that matter and check the &lt;a href="https://www.fastcompany.com/90369697/googles-new-recaptcha-has-a-dark-side"&gt;history &amp;amp; usage&lt;/a&gt; of reCAPTCHA to get better knowledge on how to use it and have your own opinion. Maybe you don´t really want to use it?&lt;/p&gt;

&lt;p&gt;Last but not least, quote from &lt;em&gt;docs&lt;/em&gt; on where to use it and where it can get usage data from:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For this reason, we recommend including reCAPTCHA verification on forms or actions as well as in the background of pages for analytics.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Let´s implement it - example and usage 🛠️
&lt;/h2&gt;

&lt;p&gt;Have a quick look at the flow we will go through:&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/13c1c7c46a9b270edbe741109a17c381/d2448/reCAPTCHA-flow-explanation-tutorial.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lP1H-zGE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/13c1c7c46a9b270edbe741109a17c381/4d236/reCAPTCHA-flow-explanation-tutorial.png" alt="reCAPTCHA-flow-explanation-tutorial" title="reCAPTCHA-flow-explanation-tutorial" width="650" height="230"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will be following the programmatic steps from the &lt;a href="https://developers.google.com/recaptcha/docs/v3#placement_on_your_website"&gt;official guide&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  GENERATE
&lt;/h3&gt;

&lt;p&gt;To generate the token first you need to generate the &lt;a href="https://www.google.com/recaptcha/admin/create"&gt;&lt;strong&gt;SECRET_SITE_KEY&lt;/strong&gt; and &lt;strong&gt;SECRET_KEY&lt;/strong&gt;&lt;/a&gt;. Then the steps are straightforward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add the JS script to the page (index.html). Front end frameworks have a folder called &lt;strong&gt;public&lt;/strong&gt; that has &lt;strong&gt;index.html&lt;/strong&gt; file inside. Open it and put the script on the bottom of the body, just like you would be adding bootstrap.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;body class="h-100"&amp;gt;
  ...
  &amp;lt;script src="https://www.google.com/recaptcha/api.js?render=YOUR_SIT_KEY"&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;div id="app"&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add the function to methods available in the component.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; methods: {
    verifyCaptcha() {
      e.preventDefault();
      grecaptcha.ready(() =&amp;gt; {
        grecaptcha
        // Don't forget about putting your unique SECRET_SITE_KEY.
          .execute("SECRET_SITE_KEY", {
            action: "submit"
          })
          .then(token =&amp;gt; {
            // Try loggin the token first time to see if it got generated.
            console.log(token);
            // Add your logic to submit to your backend server here.
            // Here we will send the token to our backend using axios (install and import it to the component).
            // You could also use a Vue built in $http
            const body = { token: token };
            axios
            // We are POSTing to a dedicated URL we have on backend (it can be any URL that will need the reCAPTCHA token)
              .post("http://localhost:8000/api/verify-captcha/", body)
              .then(response =&amp;gt; {
                // THe is_human part is our custom parameter comming from our backend. You can call it other name or just return something completly different. This is 100% to developer how will the reCAPTCHA returned probability be used.
                if (response.data.is_human) {
                 // Your front-end logic fired-up on success.
                } else {
                 // Your front-end logic fired-up on error.
                }
              })
              .catch(error =&amp;gt; {
                console.log("Error : ", error);
              })
              // Boolean that could e.g. stop page loader.
              .finally(() =&amp;gt; (this.loading = false));
          });
      });
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add the method to an element on your page (the method where you execute reCAPTCHA token generation - verifyCaptcha - in our case)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;b-button @click="verifyCaptcha"&amp;gt;Submit&amp;lt;/b-button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;( Here I use &lt;a href="https://buefy.org/documentation/start/"&gt;Buefy library&lt;/a&gt; for VueJS but your button tag may be called different way or just  )&lt;/p&gt;

&lt;h3&gt;
  
  
  VERIFY
&lt;/h3&gt;

&lt;p&gt;Verification is happening on backend, since we want to use the assessment to decide what to do on that particular request. Should we let the request add e-mail address to DB or not etc., any kind of server-logic.&lt;/p&gt;

&lt;p&gt;Let’s have a look at the quote from &lt;a href="https://developers.google.com/recaptcha/docs/v3#placement_on_your_website"&gt;&lt;strong&gt;docs&lt;/strong&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;reCAPTCHA tokens expire after two minutes. If you’re protecting an action with reCAPTCHA, make sure to call execute when the user takes the action rather than on page load.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What does it mean? It means that we can generate token on Front End &amp;gt; console.log it in developer tools &amp;gt; copy it and use in &lt;strong&gt;POSTMAN&lt;/strong&gt; using Google’s endpoint ( or our backend but this makes sense only if axios or communication front-end==back-end doesn´t work for some reason ).&lt;/p&gt;

&lt;p&gt;Let’s start to test the token generated on front-end. The URL for checking it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;METHOD: POST
https://www.google.com/recaptcha/api/siteverify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and we need to provide a following body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "response": "TOKEN_GENERATED_ON_FRONT_END_ACTION",
  "secret": "YOUR_SECRET_KEY"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or we could put those values as encoded form:&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/333829db4d3bcb1f5f40474cacda3e99/5f327/postman-recaptcha-token-verify.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--om-RvhZl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/333829db4d3bcb1f5f40474cacda3e99/4d236/postman-recaptcha-token-verify.png" alt="postman-recaptcha-token-verify" title="postman-recaptcha-token-verify" width="650" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This very request is the request you have to send &lt;strong&gt;from your backend&lt;/strong&gt; to later use the &lt;strong&gt;score&lt;/strong&gt; value in your logic.&lt;/p&gt;

&lt;p&gt;I wanted to start with POSTMAN because it has very useful feature that let’s you &lt;a href="https://learning.postman.com/docs/postman/sending-api-requests/generate-code-snippets/"&gt;&lt;strong&gt;export request in any language you want&lt;/strong&gt;&lt;/a&gt;. I will export it in python´s requests:&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/e14dde0e595781b500d07594b0c119c6/9a489/postman-export-request.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m8GxppiC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/e14dde0e595781b500d07594b0c119c6/4d236/postman-export-request.png" alt="postman-export-request" title="postman-export-request" width="650" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you execute this script in Python e.g. in CMD / Bash you will get this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "success": true,
  "challenge_ts": "2020-06-13T22:58:18Z",
  "hostname": "localhost",
  "score": 0.9,
  "action": "submit"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let´s jump into Django now.&lt;/p&gt;

&lt;h3&gt;
  
  
  PROCESS &amp;amp; RETURN
&lt;/h3&gt;

&lt;p&gt;I will show you that in one code snippet. For learning purposes everything shown here is as simple as possible. In real life you would have a process function somewhere in a separate file and custom return afterwards.&lt;/p&gt;

&lt;p&gt;As I mentioned, verifying will be done in a custom, dedicated endpoint but you can do it in any of your endpoints (as long as you pass the token there)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# urls.py

urlpatterns = [
    # ...
    path('api/verify-captcha/', VerifyCaptcha.as_view(), name='verify-captcha'),
]

# api.py

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

import json
import requests

YOUR_SECRET_KEY = "YOUR_SECRET_KEY"
GOOGLE_URL = 'https://www.google.com/recaptcha/api/siteverify'

class VerifyCaptcha(APIView):
    """Calls Google endpoint to verify front-end TOKEN and returns information whether user is a human.
    """
    # ...

        # This is POST endpoint that we were calling with axios in the first front-end example.
    def post(self, request, *args, **kwargs):
        # Decoding the payload
        request = json.loads(request.body.decode('utf-8'))
        # Taking out the token from the payload
        TOKEN_GENERATED_ON_FRONT_END_ACTION = request['token']
        # Creating body to send to Google for verification. You could also pass user's IP as an optional parameter but I never do that.
        body = {
            "secret": YOUR_SECRET_KEY,
            "response": TOKEN_GENERATED_ON_FRONT_END_ACTION
        }
        # Sending the request
        r = requests.post(GOOGLE_URL, data=body, json=body,)
        # Receiving the response
        google_response = r.json()

        # Analyzing the response
        if google_response['success'] == True:
            # Preparing our response that will be send to our front-end
            response = {"is_human": True}

            # This is our custom logic in case the request was initiated by a bot.
            if google_response['score'] &amp;lt; 0.5:
                response['is_human'] = False
            return Response(
                data=response, status=status.HTTP_200_OK, content_type="application/json")
        else:
            return Response(
                data={"is_human": None, "message": "Validation of FE token went wront."}, status=status.HTTP_404_NOT_FOUND, content_type="application/json")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case &lt;a href="https://developers.google.com/recaptcha/docs/verify"&gt;official docs&lt;/a&gt; give you all the info on possible responses from Google&lt;/p&gt;

&lt;p&gt;You did it! 👏&lt;/p&gt;

&lt;p&gt;Now you can avoid bots 🤖&lt;/p&gt;







&lt;p&gt;&lt;em&gt;Did you make any mistakes when using reCAPTCHA or you’ve seen one here? Tell me about your insights. Leave a comment with YOUR opinion.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>5 ways to improve your automated POSTMAN tests.</title>
      <dc:creator>george_pollock</dc:creator>
      <pubDate>Sat, 23 May 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/george_pollock/5-ways-to-improve-your-automated-postman-tests-49pc</link>
      <guid>https://dev.to/george_pollock/5-ways-to-improve-your-automated-postman-tests-49pc</guid>
      <description>&lt;h2&gt;
  
  
  Improve your POSTMAN tests.
&lt;/h2&gt;

&lt;p&gt;The methods I am sharing in this article allow me to prepare more robust tests. Some example use cases would be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wondering how to create random number or random name for a variable? Need to use some jQuery for parsing HTML? Try using 3rd party libraries in POSTMAN sandbox.&lt;/li&gt;
&lt;li&gt;Executing POST with body that needs to be changed? No problem! Try to make some changable body conent by preparing it in pre-requests.&lt;/li&gt;
&lt;li&gt;Your requests just return a rendered page HTML? Try parsing it and scrapping for the data you need ( &lt;strong&gt;tokens&lt;/strong&gt; for example ).&lt;/li&gt;
&lt;li&gt;Your request response makes the next request redundant? You want to execute previous request? Queue execution of specific request.&lt;/li&gt;
&lt;li&gt;You are recieving big objects of important data? Verify just its format by validating with schema.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Using 3rd party libraries in pre scripts
&lt;/h2&gt;

&lt;p&gt;You want to create random numbers? use lodash library? jQuery? Chai assertions?Maybe you need some high level time operations for your scripts? MomentJS? No problem.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Passing, parsing URLs&lt;/li&gt;
&lt;li&gt;Validating Schemas&lt;/li&gt;
&lt;li&gt;Decoding, encoding keys, tokens with SHA256 (atob, btoa)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No problem. POSTMAN allows you to use &lt;a href="https://learning.postman.com/docs/postman/scripts/postman-sandbox-api-reference/"&gt;3rd party libraries&lt;/a&gt; in its sandbox. Next tips will be tightly connected with this information, so have as look before proceeding!&lt;/p&gt;

&lt;h2&gt;
  
  
  Passing prerequest to body
&lt;/h2&gt;

&lt;p&gt;Let’s say SWAGGER tells you that in body you need to pass string as title:&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/10da27252b913a8ec3d2e522b0f52526/741eb/ss-swagger-postman-docs.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x8ElyiPV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/10da27252b913a8ec3d2e522b0f52526/4d236/ss-swagger-postman-docs.png" alt="swagger_postman" title="Swagger Endpoint Mapping" width="650" height="271"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can programaticaly change your body content in pre-request scripts so that e.g. each time you make a request you have different Job title.&lt;/p&gt;

&lt;p&gt;First open your pre-request scripts tab, prepare your body and &lt;strong&gt;stringify it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/676db402caea38d6ca8c9afff76e8957/fe3aa/ss-postman-prerequest-trick-script-add-on-extension.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LAI0MsUq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/676db402caea38d6ca8c9afff76e8957/4d236/ss-postman-prerequest-trick-script-add-on-extension.png" alt="postman-pre-script" title="Sending request with prerequest scripts" width="650" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(code version in case you need to copy)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const title = "Boss' Assistant nr " + _.random(0, 10)

const preparedBody = {
    "title" : title
}

pm.environment.set("job_object", JSON.stringify(preparedBody))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have to set this body object as an environment, global or collection variable. Once you do it, before executing the script you just need to use it in body like that:&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/4edc23247710f1795fd3b2aaf55cf8ea/9f555/ss-postman-body-request.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mFNVDIC2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/4edc23247710f1795fd3b2aaf55cf8ea/4d236/ss-postman-body-request.png" alt="postman-pre-script-use" title="Sending request with prerequest scripts" width="650" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now each time you execute this request you will get new Job title:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"title": "Boss' Assistant nr 5"
...
"title": "Boss' Assistant nr 2"
...
"title": "Boss' Assistant nr 6"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Parsing data from HTMLs forms
&lt;/h2&gt;

&lt;p&gt;General use case: There is some visible or hidden data within the HTML tags on the rendered page that you need to pass / verify / check.&lt;/p&gt;

&lt;p&gt;Specific use cases: You have a page that has a login fields with generated token that you need for next request.&lt;/p&gt;

&lt;p&gt;Let’s say that you make a request to some API and it redirects you to a page with input fields that have tokens assigned. That’s a common use case with SAML and SSO. You can practice &lt;a href="https://app.onelogin.com/login"&gt;here&lt;/a&gt; on a real use case. This login field has a token.&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/534b6424a166b90727b77bb9e06a4e15/fdd36/ss-input-field-token.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6kLJQgNc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/534b6424a166b90727b77bb9e06a4e15/fdd36/ss-input-field-token.png" alt="input-token" title="Sending request with prerequest scripts" width="471" height="743"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On requesting the URL of this page we will get just normal HTML:&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/9f11cc271cc9eaaf05b1b08d3bf11fd6/f7a66/ss-make-html-request-postman.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H4H9n_6---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/9f11cc271cc9eaaf05b1b08d3bf11fd6/4d236/ss-make-html-request-postman.png" alt="postman-html-request" title="HTML body in POSTMAN request" width="650" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you’ve read in a previous tip, we can use libraries provided in POSTMAN SandBox. jQuery is &lt;a href="https://blog.postman.com/jquery-replaced-by-cheeriojs-in-postman-sandbox/"&gt;replaced by CheerioJS&lt;/a&gt; which emulates jQuery core API.&lt;/p&gt;

&lt;p&gt;Let’s load the library and see if it’s working:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const $ = cheerio.load(pm.response.text())
console.log('Title of the page: ', $('title').text())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you just need to use your selectors magic knowledge. Let’s query for the TOKEN we need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log($('input[name=authenticity_token]').attr('value'))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;( &lt;strong&gt;TIP 1:&lt;/strong&gt; If you are not good with selectors, click right mouse button on element you are looking for and then &lt;strong&gt;copy selector&lt;/strong&gt; )&lt;/p&gt;

&lt;p&gt;( &lt;strong&gt;TIP 2:&lt;/strong&gt; If you need other information from HTML elements, check the &lt;a href="https://github.com/cheeriojs/cheerio"&gt;Cheerio documentation&lt;/a&gt; for more. )&lt;/p&gt;

&lt;p&gt;And finally let’s write the test and export the TOKEN:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pm.test('input field it should have a token', () =&amp;gt; {
  let TOKEN = $('input[name=authenticity_token]').attr('value')
  pm.expect(TOKEN).to.not.be.empty
  pm.environment.set('TOKEN', TOKEN)
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can use the TOKEN in other requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  SetNextRequest
&lt;/h2&gt;

&lt;p&gt;I’m assuming you know what is a postman collection. It’s a set of requests or folders with requests, depending how you order your work. The basic workflow that POSTMAN uses is checking request one after the other. It goes from the top to bottom basically. Most of this is well &lt;a href="https://learning.postman.com/docs/postman/collection-runs/building-workflows/#getting-started"&gt;described already&lt;/a&gt; but I will just mention that with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;postman.setNextRequest('REQUEST_NAME_HERE')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can go back to &lt;strong&gt;previous requests&lt;/strong&gt; or &lt;strong&gt;skip some requests&lt;/strong&gt; or &lt;strong&gt;loop through requests&lt;/strong&gt; &lt;a href="https://learning.postman.com/docs/postman/scripts/branching-and-looping/"&gt;7&lt;/a&gt;. It’s IMPORTANT to remember that naming convention in your requests that follows e.g. CamelCase and has consistent information &lt;strong&gt;helps tremendously&lt;/strong&gt; because it makes your code cleaner.&lt;/p&gt;

&lt;p&gt;Instead of using default naming:&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/0f0d231f46ec04eb0377b19e172df287/efa85/ss-naming-postman-requests.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zEW_iFQv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/0f0d231f46ec04eb0377b19e172df287/efa85/ss-naming-postman-requests.png" alt="postman-request-naming" title="Naming POSTMAN request" width="579" height="206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Try naming your request in a way that will be easier to write them in the scripts when passing their names into your &lt;strong&gt;setNextRequest()&lt;/strong&gt; e.g. using request method and no spaces:&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/62b6cf9eb54336bacf5d4331e39ea4eb/41bf6/ss-naming-postman-requests-good.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kC69QvmP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hvitis.dev/static/62b6cf9eb54336bacf5d4331e39ea4eb/41bf6/ss-naming-postman-requests-good.png" alt="good-postman-request-namingt" title="Naming POSTMAN request good" width="576" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Validating schema
&lt;/h2&gt;

&lt;p&gt;Imagine you make a test for checking if your API returns a Bank Account number.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const jsonData = pm.response.json()
pm.test('returns IBAN as a number', () =&amp;gt; {
  const IBAN = jsonData.IBAN
  pm.expect(IBAN)
    .to.be.an('number')
    .that.does.not.include('ES')
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You &lt;a href="https://www.chaijs.com/api/bdd/"&gt;assert&lt;/a&gt; that it should be a number and it works fine but what if you would need to be sure as per data types of an entire response of object with 50 keys? &lt;a href="https://postman-quick-reference-guide.readthedocs.io/en/latest/assertions.html"&gt;Using assertions&lt;/a&gt; would be cumbersome.&lt;/p&gt;

&lt;p&gt;That’s a use case for &lt;a href="https://json-schema.org/understanding-json-schema/about.html"&gt;schema validation&lt;/a&gt;. POSTMAN allows us to use&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tv4 - Tiny Validator (for v4 JSON Schema)
and / or&lt;/li&gt;
&lt;li&gt;Ajv - Another JSON Schema Validator&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="https://geraintluff.github.io/tv4/"&gt;documentation&lt;/a&gt; for both libraries shows all the API you could use. I will just show you the basic idea behind it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// We create a schema for our response
var schema = {
  IBAN: {
    type: 'number',
  },
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and write a test for it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const jsonData = pm.response.json()
pm.test('Schema is valid', () =&amp;gt; {
  pm.expect(tv4.validate(jsonData, schema)).to.be.true
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could verify properties, whether field is required, nested objects, referencing and many more. Always remember to &lt;a href="https://www.npmjs.com/package/ajv"&gt;&lt;strong&gt;read documentation&lt;/strong&gt;&lt;/a&gt; before starting to know the full potential of your tools!&lt;/p&gt;







&lt;p&gt;&lt;em&gt;Did you make any mistakes when using POSTMAN or you’ve seen one here? Tell me about your insights. Leave a comment with YOUR opinion.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Your Web presence with Django.</title>
      <dc:creator>george_pollock</dc:creator>
      <pubDate>Sat, 11 Apr 2020 17:26:32 +0000</pubDate>
      <link>https://dev.to/george_pollock/your-web-presence-with-django-2ci8</link>
      <guid>https://dev.to/george_pollock/your-web-presence-with-django-2ci8</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzqhr7jrsmgp4ts6la26b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzqhr7jrsmgp4ts6la26b.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have you ever made a curriculum vitae? If you did then probably you’ve started with a template. In most of the templates there is always a ‘web’ place for your website. Setting up may be cumbersome for many but there is many services that solve that. Here you can use ( and work on! ) a template to set up with literally 2 clicks.&lt;/p&gt;

&lt;p&gt;We are focusing here mostly on people who either want to start a podcast/blog or want to start programming in Python. In case you just want to start a podcast and are looking for a website then we are &lt;a href="https://github.com/hvitis/Podcaster" rel="noopener noreferrer"&gt;here&lt;/a&gt; for you.&lt;/p&gt;

&lt;p&gt;In case you code — stay and read along!&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Junior CV references can be better
&lt;/h2&gt;

&lt;p&gt;Great way to boost your curriculum is to start working on a project. To go out from &lt;strong&gt;“while True: do online courses”&lt;/strong&gt; loop. I’m not saying another to-do list. I’m saying something that can be useful, used and visible.&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;What experience do you have, Sir?&lt;/li&gt;
&lt;li&gt;Well, […] and I was contributing to an open-source project that you can see  on my website.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Contributing to open-source is a great way to learn, leave your knowledge out there and let people use it.&lt;br&gt;
You can search for &lt;strong&gt;good first issues&lt;/strong&gt; &lt;a href="https://github.com/search?q=good+first+issue&amp;amp;type=Issues" rel="noopener noreferrer"&gt;directly on GitHub&lt;/a&gt; or you can use apps like &lt;a href="https://github.com/cutenode/good-first-issue" rel="noopener noreferrer"&gt;this CLI&lt;/a&gt; one or &lt;a href="https://goofi.now.sh/" rel="noopener noreferrer"&gt;this one&lt;/a&gt; — that aim to help you find those. Both solutions have their advantages but in case you didn’t find anything or your level is not that high yet (or you simply like my idea) then you can find &lt;a href="https://github.com/hvitis/Podcaster/issues" rel="noopener noreferrer"&gt;some open issues&lt;/a&gt; for &lt;strong&gt;Django beginners&lt;/strong&gt; and start using your knowledge!&lt;/p&gt;

&lt;h2&gt;
  
  
  Your online presence counts
&lt;/h2&gt;

&lt;p&gt;Recruiters are very well aware of the fact that &lt;a href="https://www.inc.com/jt-odonnell/staggering-85-of-job-applicants-lying-on-resumes-.html" rel="noopener noreferrer"&gt;people lie on their resume&lt;/a&gt;. Fortunately in IT the easiest way to verify actual knowledge is to click on a link in your resume and see with their own eyes. Amount of contributions, users or just the look of your page. Nowadays personal website is essential in your &lt;a href="https://www.forbes.com/sites/danschawbel/2011/02/21/5-reasons-why-your-online-presence-will-replace-your-resume-in-10-years/" rel="noopener noreferrer"&gt;online presence&lt;/a&gt;.&lt;br&gt;
Even if you don’t like Podcaster idea and you’re not intending to contribute, there are many other platforms where you can start your page or &lt;a href="https://ghost.org/" rel="noopener noreferrer"&gt;blog&lt;/a&gt; in seconds. Try them out or build your website from scratch. You won’t regret it!&lt;/p&gt;

&lt;h2&gt;
  
  
  What you lose by not trying
&lt;/h2&gt;

&lt;p&gt;Coding together ( pair programming ) as well as &lt;a href="https://hvitis.com/peer-testing-and-everything-you-should-know-about-it" rel="noopener noreferrer"&gt;testing together&lt;/a&gt; ( peer testing ) can be &lt;a href="https://medium.com/better-programming/when-pair-programming-works-it-works-really-well-heres-why-c51857bbcf0f" rel="noopener noreferrer"&gt;profitable&lt;/a&gt;. Peer activities are profitable not only according to our experience but to &lt;a href="https://www.researchgate.net/publication/220832212_Peer_Testing_in_Software_Engineering_Projects" rel="noopener noreferrer"&gt;studies&lt;/a&gt;. As long as you don’t have other important side project or you’re not exchanging your time for money, reading other people’s code can bring you value.&lt;br&gt;
Give it a shot and search for some Good First Issue today. In the worst case scenario you can find an interesting, free software that can ease your life.&lt;/p&gt;

</description>
      <category>django</category>
      <category>opensource</category>
      <category>python</category>
      <category>podcast</category>
    </item>
  </channel>
</rss>
