<?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: Felipe Henrique Gross Windmoller</title>
    <description>The latest articles on DEV Community by Felipe Henrique Gross Windmoller (@felipewind).</description>
    <link>https://dev.to/felipewind</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%2F633772%2Ff6feb3dd-194c-4308-9ee1-a9d680c50a8d.jpg</url>
      <title>DEV Community: Felipe Henrique Gross Windmoller</title>
      <link>https://dev.to/felipewind</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/felipewind"/>
    <language>en</language>
    <item>
      <title>Python FastAPI: Tutorial to Test HTTP Client Requests</title>
      <dc:creator>Felipe Henrique Gross Windmoller</dc:creator>
      <pubDate>Mon, 13 May 2024 12:05:48 +0000</pubDate>
      <link>https://dev.to/felipewind/python-fastapi-tutorial-to-test-http-client-requests-2ah9</link>
      <guid>https://dev.to/felipewind/python-fastapi-tutorial-to-test-http-client-requests-2ah9</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyjynwmplm1x1w64w7yt0.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyjynwmplm1x1w64w7yt0.jpeg" alt="Testing HTTP Client Requests"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: I’m learning Python, so please correct me if I’ve written something wrong!&lt;/p&gt;

&lt;p&gt;In this tutorial, we’ll explore how to test HTTP client calls in a FastAPI Python application using two different methods: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;unittest.mock&lt;/code&gt;: This is a built-in Python library used for mocking objects in tests. It allows you to replace parts of your system under test and make assertions about how they have been used.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;httpretty&lt;/code&gt;: This is a third-party library that allows you to mock HTTP requests at a low level by creating a fake HTTP server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To run the tests, just execute this on the root of the project directory:&lt;/p&gt;

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

pytest


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

&lt;/div&gt;

&lt;p&gt;You should see output similar to this:&lt;/p&gt;

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

$ pytest
============================================================================================== test session starts ==============================================================================================
platform linux -- Python 3.11.6, pytest-8.2.0, pluggy-1.5.0
rootdir: /home/wsl/github/python-study/api-client
plugins: anyio-4.2.0
collected 3 items

tests/test_main.py .                                                                                                                                                                                      [ 33%]
tests/test_main_httppretty_mock.py .                                                                                                                                                                      [ 66%]
tests/test_main_magic_mock.py .                                                                                                                                                                           [100%]

=============================================================================================== 3 passed in 0.39s ===============================================================================================


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

&lt;/div&gt;

&lt;p&gt;This output indicates that all three tests passed successfully. The percentage in brackets shows the progress of the test run.&lt;/p&gt;

&lt;h3&gt;
  
  
  Versions of my modules
&lt;/h3&gt;

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

$ pip list
Package                            Version
---------------------------------- -----------
fastapi                            0.111.0
httpretty                          1.1.4
pydantic                           2.5.3
pytest                             8.2.0
requests                           2.31.0


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Project structure
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

.
├── app
│   ├── __init__.py
│   └── main.py
└── tests
    ├── __init__.py
    ├── test_main_httppretty_mock.py
    └── test_main_magic_mock.py


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

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;__init__.py&lt;/code&gt; are just empty files&lt;/p&gt;

&lt;h3&gt;
  
  
  main.py
&lt;/h3&gt;

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

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HTTPException&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Union&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;

&lt;span class="n"&gt;API_SERVER_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;API_SERVER_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:8010&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;API_LOG_LEVEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;API_LOG_LEVEL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;INFO&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Configure basic logging
&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;API_LOG_LEVEL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
    &lt;span class="n"&gt;is_offer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Union&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;


&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_root&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;World&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/items/{item_id}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Union&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;API_SERVER_URL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/items/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;q&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="c1"&gt;# Raises HTTPError for bad responses (4XX or 5XX)
&lt;/span&gt;        &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;item_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;item_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Deserialize the JSON into an Item object
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestException&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Request failed: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Log the error
&lt;/span&gt;        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;



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

&lt;/div&gt;
&lt;h3&gt;
  
  
  test_main_magic_mock.py
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi.testclient&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TestClient&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;unittest.mock&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MagicMock&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;app.main&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TestClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@pytest.fixture&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;mock_requests_get&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Create a MagicMock object to mock requests.get
&lt;/span&gt;    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;requests.get&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;mock_get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Prepare a mock response object with necessary methods
&lt;/span&gt;        &lt;span class="n"&gt;mock_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MagicMock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;mock_response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sample Item&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_offer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;mock_response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raise_for_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MagicMock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;mock_get&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mock_response&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;mock_get&lt;/span&gt;


&lt;span class="c1"&gt;# The mock_requests_get fixture is automatically used here.
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_read_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mock_requests_get&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/items/1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sample Item&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_offer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;# Assert if requests.get was called correctly
&lt;/span&gt;    &lt;span class="n"&gt;mock_requests_get&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assert_called_once_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:8010/items/1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;q&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  test_main_httppretty_mock.py
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;httpretty&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi.testclient&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TestClient&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;app.main&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TestClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@httpretty.activate&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_read_item&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Mocking the external API call
&lt;/span&gt;    &lt;span class="n"&gt;httpretty&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register_uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;httpretty&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:8010/items/1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sample Item&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: 100.0, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_offer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: null}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;content_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;  &lt;span class="c1"&gt;# Define the expected status code
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Call the endpoint
&lt;/span&gt;    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/items/1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Assertions
&lt;/span&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sample Item&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_offer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

</description>
      <category>python</category>
      <category>fastapi</category>
      <category>testing</category>
    </item>
    <item>
      <title>Strategic Moves: Exploring the Chessboard of Domain-Driven Design</title>
      <dc:creator>Felipe Henrique Gross Windmoller</dc:creator>
      <pubDate>Wed, 06 Sep 2023 14:25:26 +0000</pubDate>
      <link>https://dev.to/felipewind/strategic-moves-exploring-the-chessboard-of-domain-driven-design-2dl5</link>
      <guid>https://dev.to/felipewind/strategic-moves-exploring-the-chessboard-of-domain-driven-design-2dl5</guid>
      <description>&lt;p&gt;Software development and a game of chess. At first, it might not be obvious to compare these two subjects and they might seem fundamentally different for you; however, these two topics are based on navigating an abundance of possibilities and choices and have more similarities than you could anticipate. In this article, I will take you through the strategic and tactical principles of Domain-Driven Design (DDD) comparing it to strategies and tactics of a chess match.&lt;/p&gt;




&lt;h2&gt;
  
  
  Chess Strategy
&lt;/h2&gt;

&lt;p&gt;The objective of chess is very clear: we want to win the game! However, this is challenging. Let’s imagine the beginning of a game: each Pawn can move one or two squares and each Knight can also make two different moves. So, there are twenty different options to make the first chess move. To make things more complicated, after our first move it’s our opponent’s turn and then we must come up with a new decision. The number of possibilities increases exponentially as we try to calculate the movements that can be done depending on our opponent’s decision. Some great masters are reputed to predict 15 to 20 moves ahead.&lt;/p&gt;

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

&lt;p&gt;So, how do we know what is a good opening movement? Chess strategy can guide us. In the chess strategy the game is divided into three phases: opening, middle and end game. In the opening, we must follow these principles: control the center of the board, develop our minor pieces — the Knights and Bishops — castling to protect our King and move our Queen to connect our Rooks. After accomplishing these principles, we finish the opening phase and enter the middle game. Studies have proved that following these principles improve our chances of winning the game.&lt;/p&gt;

&lt;p&gt;Having the opening strategy clarified it looks easier to choose our first move. For example, we can move our Queen Pawn to d4, and it seems perfect according to strategy principles and it meets two strategy objectives. First, the Pawn now is in position to control c5 and e5 squares and so we are in the center of the board and one step closer to get control of it. Second, it gives space for our Bishop and Queen to move.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  Strategy and Heuristics
&lt;/h2&gt;

&lt;p&gt;As stated before, the number of possible moves in a chess game can be overwhelming and strategy helps us find faster and better ones. The mental technique of taking shortcuts to solve complex problems fast is called heuristic. It provides us with results that are good enough for our immediate goals. This is useful when we need to make a decision, but we would take too much time analyzing all the information and possibilities. Bringing this to our discussion here imagine it is your turn to make a move in the game and there are around 20 different possibilities, however now you know there are strategies you can follow and reduce this number to 5. The idea is that heuristic would help you choose within these 5 possibilities, making it possible for you to make a good move, not necessarily the best, but fast since you had less options.&lt;/p&gt;




&lt;h2&gt;
  
  
  Domain-Driven Design Strategy
&lt;/h2&gt;

&lt;p&gt;It has been said that the objective of a chess game is to win. In comparison, what is our goal in an IT project? The simplest answer is that we must resolve a business problem with a software solution. Therefore, the most important element in a software project is to understand the problem, because no matter how good our implementation is, if we don’t understand the business requirements it will be impossible to achieve our purpose.&lt;/p&gt;

&lt;p&gt;Furthermore, as in chess, in the IT world we are also overwhelmed with information and different possibilities. For example: how do we evaluate our options and choose the best one to build a software that can suit the business problem? Depending on the domain complexity the number of options is huge and it’s difficult to make a decision.&lt;/p&gt;

&lt;p&gt;Domain-driven design (DDD) is a technique which was created by Eric Evans in 2003 to help us improve the communication between businesspeople and IT and give us heuristics to decide the best software implementation. In the same way which chess strategy helps us choose what piece we should move to start the game, DDD strategies also help us make choices to build a software that serves the business needs.&lt;/p&gt;

&lt;p&gt;The strategies, simplifying, are to identify the business domain and its subdomains, build the ubiquitous language and design the bounded contexts. We should first understand these concepts and then see how they can help us build software projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Business Domain and Subdomains
&lt;/h2&gt;

&lt;p&gt;The business domain is the market in which a company is inserted such as investments, credit card, marketing. It is divided into subdomains which are the business building blocks working together and allowing the company to exist. Let’s take a retail company for example, some subdomains could be customers, accounting, and stocking.&lt;/p&gt;

&lt;p&gt;There are three types of subdomains: core, generic and supporting. Core subdomains are the important ones because they differentiate a company from others and it’s what makes the company special and successful. They are complex and are always changing to generate improvements.&lt;/p&gt;

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

&lt;p&gt;Supporting subdomains are the simple ones, they don’t change too much and don’t make the company unique. However, we must build them ourselves because there are no pre-made solutions available, or it’s just an easier solution rather than developing the integration with a ready-made one.&lt;/p&gt;

&lt;p&gt;Generic subdomains are complex but not unique and so they don’t make the company special. They are problems that have been solved before, even by other industries, and there are solutions out there that we can use, as software you can buy or use for free. For instance, think about encryption, unless this is the core business of the company it is smarter to use something that is already made instead of developing it from scratch.&lt;/p&gt;

&lt;p&gt;In chess we wonder which piece we should move first. In a software project we ask what type of architecture we should use. Perhaps, layered architecture? Hexagonal architecture? Command and query responsibility segregation (CQRS)? Strategic DDD gives us some heuristics to decide. Depending on the subdomain type we can pick the best architecture. For a simple supporting subdomain, we can go with layered architecture but for a core subdomain, which is complex and changes often, hexagonal architecture could be a better option.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ubiquitous Language and Bounded Contexts
&lt;/h2&gt;

&lt;p&gt;As mentioned earlier, communication between businesspeople and IT is challenging. Often, there are two separate languages: one understood by domain experts, and another used by software programmers. This issue increases the cognitive load on teams and makes misunderstandings more likely. It’s a bit like the telephone game kids play. The requirements from businesspeople need to go from the language domain experts use to the one programmers understand, and, frequently, this translation is far from perfect.&lt;/p&gt;

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

&lt;p&gt;The strategy proposed by domain-driven design to tackle this problem of communication is to adopt the same terminology used by the business specialists in everywhere in a software project. This means that the same terms used in the meetings between the domain experts and IT people will show up in domain models, tables, and programs. That’s why the name of this pattern is ubiquitous language, which is a single language used everywhere to keep things clear and consistent.&lt;/p&gt;

&lt;p&gt;However, when people talk, some words can have different meanings depending on the situation. For instance, in a sales context, “customer” might refer to someone who purchases goods, while in a support context, it could refer to someone seeking assistance. This dubiousness isn’t a problem for human conversations, but software programs don’t admit ambiguities, everything must have one clear definition.&lt;/p&gt;

&lt;p&gt;To overcome this problem, strategic DDD has the bounded context pattern. The idea is just like the name suggest, we delimit a context to the meaning of our terms. In our previous example of the term “customer”, we would have a bounded context named “sales” and another one called “support”. Therefore, inside de “sales” bounded context, the word “customer” is going to have exactly one meaning.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Microservices and Domain-Driven Design
&lt;/h2&gt;

&lt;p&gt;In a microservices architecture, getting the size of our services right is very important. If they are too big, they become individually very complex and difficult to maintain. On the other hand, if they are too small, the global complexity of lots of tiny microservices communicating between them is going to be high. DDD helps us with some heuristics: a service shouldn’t be bigger than the bounded context, or else our language won’t be clear, and the software could get really complicated. Usually, the size of a microservice fits well with a subdomain. The application boundaries will follow how the business works, and new features from businesspeople typically get added to a single microservice, without causing a ripple effect where multiple microservices will need to be changed and deployed together.&lt;/p&gt;




&lt;h2&gt;
  
  
  Strategies and Tactics
&lt;/h2&gt;

&lt;p&gt;Strategies serve as guiding principles that steer us towards optimal choices, offering a roadmap to attain overarching objectives. Whether aiming to triumph in a chess match or excel in a software project, strategies outline the trajectory for long-term success. In contrast, tactics are more about quick results. They focus on getting things done in a short amount of time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Chess Tactics
&lt;/h2&gt;

&lt;p&gt;Chess tactics are clever tricks that players use to catch their opponents off guard or win quickly. One famous tactic is the double attack. This happens when a single move creates two problems for the opponent, and they can’t solve both. Look at the picture below: the Knight is attacking both the King and the Rook at the same time. The opponent must move the King, and in the next turn, he will lose the Rook.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  Domain-Driven Design Tactics
&lt;/h2&gt;

&lt;p&gt;While strategic DDD provides us with guidance for comprehending business requirements and crafting software solutions aligned with company objectives, tactical domain-driven design operates within the practical realm of coding programs. The three most recognized tactical patterns of DDD are value objects, entities, and aggregates.&lt;/p&gt;

&lt;p&gt;Value objects are important components in programming that help us represent specific pieces of information, like dates or money amounts, in a clear and consistent way. They’re like little containers for data and rules that make our code easier to understand and maintain. Value objects are special because once we create them, we can’t change them, which keeps our data reliable. They’re like building blocks that help us create strong and reliable software. Value objects can be identified by the composition of their values.&lt;/p&gt;

&lt;p&gt;Entities are essential in programming as they represent the core elements in a system that have unique identities and behaviors. Just like characters in a story, entities hold important information and can interact with each other. These objects help us model real-world concepts, like customers or orders, making our software more reflective of the actual situation. Because entities have individual identities, they’re crucial for tracking and managing data accurately. In programming, entities act as the main characters that drive our applications.&lt;/p&gt;

&lt;p&gt;Aggregates are vital in programming because they group together related entities and value objects, creating a more organized structure for our code. Think of them as containers that hold everything needed to handle a specific part of our system. Aggregates help us manage complex data and interactions by providing a clear boundary for operations. This makes our code more understandable and reduces the chances of errors. In programming, aggregates act as the guardians of consistency and integrity, ensuring that our data stays accurate and dependable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Words
&lt;/h2&gt;

&lt;p&gt;To wrap things up, both DDD strategy and chess strategy guide our choices. Imagine strategy as a big plan for the long run, and tactics as practical steps for right now. It’s like having a map for the journey and tools for the adventure. Despite the differences between chess and IT, they both share a common goal: a desire for success. In chess, we aim to win the match, and in IT, we strive to succeed in our projects.&lt;/p&gt;

</description>
      <category>ddd</category>
      <category>chess</category>
      <category>designpatterns</category>
      <category>designsystem</category>
    </item>
    <item>
      <title>Quarkus Mutual TLS demo</title>
      <dc:creator>Felipe Henrique Gross Windmoller</dc:creator>
      <pubDate>Mon, 01 May 2023 15:52:02 +0000</pubDate>
      <link>https://dev.to/felipewind/quarkus-mutual-tls-demo-4jnn</link>
      <guid>https://dev.to/felipewind/quarkus-mutual-tls-demo-4jnn</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu7u643sud32u4mq97o1s.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu7u643sud32u4mq97o1s.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/felipewind/quarkus-mutual-tls-demo" rel="noopener noreferrer"&gt;Project quarkus-mutual-tls-demo available on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Demonstration project that shows how to configure Transport Layer Security (TLS) on Quarkus server and Quarkus client applications.&lt;/p&gt;

&lt;p&gt;There are two applications to this demo: server and client.&lt;/p&gt;

&lt;p&gt;First, I explain the concepts of &lt;code&gt;https&lt;/code&gt;, &lt;code&gt;tls&lt;/code&gt; and &lt;code&gt;mutual tls&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Then, I execute a few tests showing step by step how we configure and what are the problems that occur when we don't configure the applications properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Concepts&lt;/li&gt;
&lt;li&gt;Certificate Generation&lt;/li&gt;
&lt;li&gt;Tests:

&lt;ul&gt;
&lt;li&gt;Server with certificate and client without truststore configured&lt;/li&gt;
&lt;li&gt;Server with certificate and client with truststore configured&lt;/li&gt;
&lt;li&gt;Server with mutual TLS and client don't inform identity&lt;/li&gt;
&lt;li&gt;Server with mutual TLS and client inform its certificate&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Credits&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Concepts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  HTTPS
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;HTTPS stands for Hypertext Transfer Protocol Secure, which is a protocol used to establish a secure and encrypted connection between a web browser (or other client) and a web server.&lt;br&gt;
When you connect to a website using HTTPS, your browser and the server exchange cryptographic keys to establish a secure connection. This ensures that any data transmitted between the client and server is encrypted and protected from interception or tampering.&lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To estabilish a https connection, the server must have a server certificate. When the client access the server, it receives the server certificate and check if this certificate is valid and issued by a trusted Certificate Authority (CA).&lt;/p&gt;

&lt;h3&gt;
  
  
  TLS
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Transport Layer Security (TLS) is a cryptographic protocol designed to provide communications security over a computer network. The protocol is widely used in applications such as email, instant messaging, and voice over IP, but its use in &lt;strong&gt;securing HTTPS&lt;/strong&gt; remains the most publicly visible.&lt;sup id="fnref2"&gt;2&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Transport Layer Security (TLS) certificates—most commonly known as SSL, or digital certificates—are the foundation of a safe and secure internet. TLS/SSL certificates secure internet connections by encrypting data sent between your browser, the website you’re visiting, and the website server. They ensure that data is transmitted privately and without modifications, loss or theft.&lt;sup id="fnref3"&gt;3&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Mutual TLS&lt;/strong&gt; occurs when the client requires identification from the server and the server requires identification from the client as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Certificate generation
&lt;/h2&gt;

&lt;p&gt;Let's generate the server and clients certificates.&lt;/p&gt;

&lt;p&gt;Then we will create a single keystore containing all client certificates.&lt;/p&gt;

&lt;p&gt;The files are already on the project, if you wan't to execute the &lt;code&gt;keytool&lt;/code&gt; commands, first delete the files.&lt;/p&gt;

&lt;p&gt;Execute the following commands on the root folder of the project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Server Certificate
&lt;/h3&gt;

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

&lt;span class="nv"&gt;$ &lt;/span&gt;keytool &lt;span class="nt"&gt;-genkeypair&lt;/span&gt; &lt;span class="nt"&gt;-storepass&lt;/span&gt; server-password &lt;span class="nt"&gt;-keyalg&lt;/span&gt; RSA &lt;span class="nt"&gt;-keysize&lt;/span&gt; 2048 &lt;span class="nt"&gt;-dname&lt;/span&gt; &lt;span class="s2"&gt;"CN=server"&lt;/span&gt; &lt;span class="nt"&gt;-alias&lt;/span&gt; server &lt;span class="nt"&gt;-ext&lt;/span&gt; &lt;span class="s2"&gt;"SAN:c=DNS:localhost,IP:127.0.0.1"&lt;/span&gt; &lt;span class="nt"&gt;-validity&lt;/span&gt; 365000 &lt;span class="nt"&gt;-keystore&lt;/span&gt; server/server-keystore.jks


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Client "A" Certificate
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;keytool &lt;span class="nt"&gt;-genkeypair&lt;/span&gt; &lt;span class="nt"&gt;-storepass&lt;/span&gt; client-a-password &lt;span class="nt"&gt;-keyalg&lt;/span&gt; RSA &lt;span class="nt"&gt;-keysize&lt;/span&gt; 2048 &lt;span class="nt"&gt;-dname&lt;/span&gt; &lt;span class="s2"&gt;"CN=client"&lt;/span&gt; &lt;span class="nt"&gt;-alias&lt;/span&gt; client &lt;span class="nt"&gt;-ext&lt;/span&gt; &lt;span class="s2"&gt;"SAN:c=DNS:localhost,IP:127.0.0.1"&lt;/span&gt; &lt;span class="nt"&gt;-validity&lt;/span&gt; 365000 &lt;span class="nt"&gt;-keystore&lt;/span&gt; client/client-a-keystore.jks


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Client "B" Certificate
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;keytool &lt;span class="nt"&gt;-genkeypair&lt;/span&gt; &lt;span class="nt"&gt;-storepass&lt;/span&gt; client-b-password &lt;span class="nt"&gt;-keyalg&lt;/span&gt; RSA &lt;span class="nt"&gt;-keysize&lt;/span&gt; 2048 &lt;span class="nt"&gt;-dname&lt;/span&gt; &lt;span class="s2"&gt;"CN=client"&lt;/span&gt; &lt;span class="nt"&gt;-alias&lt;/span&gt; client-b &lt;span class="nt"&gt;-ext&lt;/span&gt; &lt;span class="s2"&gt;"SAN:c=DNS:localhost,IP:127.0.0.1"&lt;/span&gt; &lt;span class="nt"&gt;-validity&lt;/span&gt; 365000 &lt;span class="nt"&gt;-keystore&lt;/span&gt; client/client-b-keystore.jks


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Create the server truststore
&lt;/h3&gt;

&lt;p&gt;Create the server truststore file containing all the client keystores.&lt;/p&gt;

&lt;p&gt;Generating a server truststore file:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;keytool &lt;span class="nt"&gt;-genkeypair&lt;/span&gt; &lt;span class="nt"&gt;-storepass&lt;/span&gt; authorized-clients-password &lt;span class="nt"&gt;-keyalg&lt;/span&gt; RSA &lt;span class="nt"&gt;-keysize&lt;/span&gt; 2048 &lt;span class="nt"&gt;-dname&lt;/span&gt; &lt;span class="s2"&gt;"CN=client"&lt;/span&gt; &lt;span class="nt"&gt;-alias&lt;/span&gt; authorized-clients &lt;span class="nt"&gt;-ext&lt;/span&gt; &lt;span class="s2"&gt;"SAN:c=DNS:localhost,IP:127.0.0.1"&lt;/span&gt; &lt;span class="nt"&gt;-validity&lt;/span&gt; 365000 &lt;span class="nt"&gt;-keystore&lt;/span&gt; server/server-truststore-clients.jks


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

&lt;/div&gt;

&lt;p&gt;Adding keystore from client "A" to server truststore:&lt;/p&gt;

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

&lt;span class="nv"&gt;$ &lt;/span&gt;keytool &lt;span class="nt"&gt;-importkeystore&lt;/span&gt; &lt;span class="nt"&gt;-srckeystore&lt;/span&gt; client/client-a-keystore.jks &lt;span class="nt"&gt;-srcstorepass&lt;/span&gt; client-a-password &lt;span class="nt"&gt;-destkeystore&lt;/span&gt; server/server-truststore-clients.jks &lt;span class="nt"&gt;-deststorepass&lt;/span&gt; authorized-clients-password


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

&lt;/div&gt;

&lt;p&gt;Adding keystore from client "B" to server truststore:&lt;/p&gt;

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

&lt;span class="nv"&gt;$ &lt;/span&gt;keytool &lt;span class="nt"&gt;-importkeystore&lt;/span&gt; &lt;span class="nt"&gt;-srckeystore&lt;/span&gt; client/client-b-keystore.jks &lt;span class="nt"&gt;-srcstorepass&lt;/span&gt; client-b-password &lt;span class="nt"&gt;-destkeystore&lt;/span&gt; server/server-truststore-clients.jks &lt;span class="nt"&gt;-deststorepass&lt;/span&gt; authorized-clients-password


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Create the client truststore
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ cp server/server-keystore.jks client/client-truststore.jks


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Test - Server with certificate and client without truststore configured
&lt;/h2&gt;

&lt;p&gt;In this cenario, the server only accepts https connections, but the server certificate isn't present in the client trustore Certificate Authorite control.&lt;/p&gt;

&lt;p&gt;Enabling TLS on the server side:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Disallowing http access
&lt;/span&gt;&lt;span class="py"&gt;quarkus.http.insecure-requests&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;disabled&lt;/span&gt;

&lt;span class="c"&gt;# Configure https port
&lt;/span&gt;&lt;span class="py"&gt;quarkus.http.ssl-port&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;8445&lt;/span&gt;

&lt;span class="c"&gt;# Server Certificate
&lt;/span&gt;&lt;span class="py"&gt;quarkus.http.ssl.certificate.key-store-file&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;./server-keystore.jks&lt;/span&gt;
&lt;span class="py"&gt;quarkus.http.ssl.certificate.key-store-password&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;server-password&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Start server:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter the &lt;a href="//./server/"&gt;server folder&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Execute &lt;code&gt;$ ./mvnw quarkus:dev&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Test from Quarkus Client
&lt;/h3&gt;

&lt;p&gt;Start client:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter the &lt;a href="//./client/"&gt;client folder&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Execute &lt;code&gt;$ ./mvnw quarkus:dev&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Execute client endpoint that consumes server endpoint:&lt;/p&gt;

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

&lt;span class="nv"&gt;$ &lt;/span&gt;curl localhost:8080/hello


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

&lt;/div&gt;

&lt;p&gt;Try to access this endpoint from the client without the Trust Store configuration, we receive this error:&lt;/p&gt;

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

jakarta.ws.rs.ProcessingException: javax.net.ssl.SSLHandshakeException: Failed to create SSL connection
...
Caused by: javax.net.ssl.SSLHandshakeException: Failed to create SSL connection
        at io.vertx.core.net.impl.ChannelProvider$1.userEventTriggered(ChannelProvider.java:127)
        ... 25 more
Caused by: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
...
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
...
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Test from curl
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;curl https://localhost:8445
curl: &lt;span class="o"&gt;(&lt;/span&gt;60&lt;span class="o"&gt;)&lt;/span&gt; SSL certificate problem: self-signed certificate
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Test from curl allowing insecure server connections
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-k&lt;/span&gt; https://localhost:8445/hello

Hello from server


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Test - Server with certificate and client with truststore configured
&lt;/h2&gt;

&lt;p&gt;Configure client truststore:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Rest client specific Trust Store
&lt;/span&gt;&lt;span class="py"&gt;quarkus.rest-client.server-api.trust-store&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;./client-truststore.jks&lt;/span&gt;
&lt;span class="py"&gt;quarkus.rest-client.server-api.trust-store-password&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;server-password&lt;/span&gt;


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Test from Quarkus Client
&lt;/h3&gt;

&lt;p&gt;Start client:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter the &lt;a href="//./client/"&gt;client folder&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Execute &lt;code&gt;$ ./mvnw quarkus:dev&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Execute client endpoint that consumes server endpoint:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;curl localhost:8080/hello

Hello from server


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Test - Server with mutual TLS and client don't inform identity
&lt;/h2&gt;

&lt;p&gt;Include requiring of client identification (&lt;code&gt;quarkus.http.ssl.client-auth&lt;/code&gt;) and the truststore of the server, that are the identities that the server will trust:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Disallowing http access
&lt;/span&gt;&lt;span class="py"&gt;quarkus.http.insecure-requests&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;disabled&lt;/span&gt;

&lt;span class="c"&gt;# Configure https port
&lt;/span&gt;&lt;span class="py"&gt;quarkus.http.ssl-port&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;8445&lt;/span&gt;

&lt;span class="c"&gt;# Server Certificate
&lt;/span&gt;&lt;span class="py"&gt;quarkus.http.ssl.certificate.key-store-file&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;./server-keystore.jks&lt;/span&gt;
&lt;span class="py"&gt;quarkus.http.ssl.certificate.key-store-password&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;server-password&lt;/span&gt;

&lt;span class="c"&gt;# Require client identification
&lt;/span&gt;&lt;span class="py"&gt;quarkus.http.ssl.client-auth&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;required&lt;/span&gt;
&lt;span class="py"&gt;quarkus.http.ssl.certificate.trust-store-file&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;./server-truststore-clients.jks&lt;/span&gt;
&lt;span class="py"&gt;quarkus.http.ssl.certificate.trust-store-password&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;authorized-clients-password&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Start server:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter the &lt;a href="//./server/"&gt;server folder&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Execute &lt;code&gt;$ ./mvnw quarkus:dev&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Test from Quarkus Client
&lt;/h3&gt;

&lt;p&gt;Start client:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter the &lt;a href="//./client/"&gt;client folder&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Execute &lt;code&gt;$ ./mvnw quarkus:dev&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Execute client endpoint that consumes server endpoint:&lt;/p&gt;

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

&lt;span class="nv"&gt;$ &lt;/span&gt;curl localhost:8080/hello

io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
...
Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Test from curl
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-k&lt;/span&gt; https://localhost:8445

curl: &lt;span class="o"&gt;(&lt;/span&gt;56&lt;span class="o"&gt;)&lt;/span&gt; OpenSSL SSL_read: error:0A000412:SSL routines::sslv3 alert bad certificate, errno 0


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Test - Server with mutual TLS and client inform its certificate
&lt;/h2&gt;

&lt;p&gt;Add the client certificate:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Rest client specific Trust Store
&lt;/span&gt;&lt;span class="py"&gt;quarkus.rest-client.server-api.trust-store&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;./client-truststore.jks&lt;/span&gt;
&lt;span class="py"&gt;quarkus.rest-client.server-api.trust-store-password&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;server-password&lt;/span&gt;

&lt;span class="c"&gt;# Rest Client specific Key Store
&lt;/span&gt;&lt;span class="py"&gt;quarkus.rest-client.server-api.key-store&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;./client-a-keystore.jks&lt;/span&gt;
&lt;span class="py"&gt;quarkus.rest-client.server-api.key-store-password&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;client-a-password&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Start client:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter the &lt;a href="//./client/"&gt;client folder&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Execute &lt;code&gt;$ ./mvnw quarkus:dev&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Execute client endpoint that consumes server endpoint:&lt;/p&gt;

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

&lt;span class="nv"&gt;$ &lt;/span&gt;curl localhost:8080/hello

Hello from server


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

&lt;/div&gt;

&lt;p&gt;You can add any of the client keystores that are on the truststore of the server, that are &lt;code&gt;client-a-keystore.jks (client-a-password)&lt;/code&gt; or &lt;code&gt;client-b-keystore.jks (client-b-password)&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://quarkus.io/guides/security-authentication-mechanisms-concept#mutual-tls" rel="noopener noreferrer"&gt;https://quarkus.io/guides/security-authentication-mechanisms-concept#mutual-tls&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://quarkus.io/blog/quarkus-mutual-tls/" rel="noopener noreferrer"&gt;https://quarkus.io/blog/quarkus-mutual-tls/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://quarkus.io/guides/http-reference" rel="noopener noreferrer"&gt;https://quarkus.io/guides/http-reference&lt;/a&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://chat.openai.com/" rel="noopener noreferrer"&gt;https://chat.openai.com/&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Transport_Layer_Security" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Transport_Layer_Security&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;&lt;a href="https://www.digicert.com/tls-ssl/tls-ssl-certificates#:%7E:text=Transport%20Layer%20Security%20(TLS)%20certificates,visiting%2C%20and%20the%20website%20server" rel="noopener noreferrer"&gt;https://www.digicert.com/tls-ssl/tls-ssl-certificates#:~:text=Transport%20Layer%20Security%20(TLS)%20certificates,visiting%2C%20and%20the%20website%20server&lt;/a&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>quarkus</category>
      <category>java</category>
      <category>tutorial</category>
      <category>tls</category>
    </item>
    <item>
      <title>Uploading a file through Swagger in Quarkus</title>
      <dc:creator>Felipe Henrique Gross Windmoller</dc:creator>
      <pubDate>Sat, 11 Jun 2022 01:56:28 +0000</pubDate>
      <link>https://dev.to/felipewind/uploading-a-file-through-swagger-in-quarkus-3l8l</link>
      <guid>https://dev.to/felipewind/uploading-a-file-through-swagger-in-quarkus-3l8l</guid>
      <description>&lt;p&gt;In &lt;a href="https://github.com/felipewind/quarkus-swagger-upload-file" rel="noopener noreferrer"&gt;this project&lt;/a&gt; I show a way where you can upload a file through the SWagger-UI in Quarkus.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/dearrudam" rel="noopener noreferrer"&gt;Maximillian Arruda&lt;/a&gt; showed me how to to this and I decided to create this project to help other people who might also want to use this feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;Start the application with:&lt;/p&gt;

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

./mvnw compile quarkus:dev


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

&lt;/div&gt;

&lt;p&gt;Access the swagger-ui at &lt;a href="http://localhost:8080/q/swagger-ui" rel="noopener noreferrer"&gt;http://localhost:8080/q/swagger-ui&lt;/a&gt; and add the files you want to upload (the assets folder has two files for test):&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj375ae8kid93e0s47rtb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj375ae8kid93e0s47rtb.png" alt="Swagger-ui uploading files"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click execute.&lt;/p&gt;

&lt;p&gt;You'll receive one &lt;code&gt;202 Accepted&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The application sends the Buffer from the files to a Vert.X Bus Event, where they are processed and the information is displayed.&lt;/p&gt;

&lt;p&gt;In the developer are of the browser (usually when you press F12), you can see the HTTP POST request with all data being sent to the server:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fosjfb1euy0zuhn7oh0yz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fosjfb1euy0zuhn7oh0yz.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the logs of the application, you'll see that the HTTP endpoint is provided by by one executor thread and the processing of the file is done by one &lt;code&gt;worker thread&lt;/code&gt;: &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flzl1c1x5ey877pcp8u37.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flzl1c1x5ey877pcp8u37.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Under the hood
&lt;/h2&gt;

&lt;p&gt;This Java class does all the magic of the swagger-ui and send the events to the Vert.X event bus:&lt;/p&gt;

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

&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;org.acme&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.BufferedReader&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.IOException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.nio.file.Files&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.enterprise.context.RequestScoped&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.inject.Inject&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.ws.rs.Consumes&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.ws.rs.POST&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.ws.rs.Path&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.ws.rs.core.MediaType&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.ws.rs.core.Response&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.eclipse.microprofile.openapi.annotations.enums.SchemaType&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.eclipse.microprofile.openapi.annotations.media.Schema&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.eclipse.microprofile.openapi.annotations.responses.APIResponse&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.jboss.logging.Logger&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.jboss.resteasy.reactive.MultipartForm&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.jboss.resteasy.reactive.RestForm&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.jboss.resteasy.reactive.multipart.FileUpload&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.vertx.core.eventbus.EventBus&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@RequestScoped&lt;/span&gt;
&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"upload"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UploadResource&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt; &lt;span class="no"&gt;LOG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLogger&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UploadResource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="nc"&gt;EventBus&lt;/span&gt; &lt;span class="n"&gt;bus&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@POST&lt;/span&gt;
    &lt;span class="nd"&gt;@Consumes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MULTIPART_FORM_DATA&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@APIResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;responseCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"202"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt; &lt;span class="nf"&gt;upload&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="nd"&gt;@MultipartForm&lt;/span&gt; &lt;span class="nc"&gt;MultipartBody&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="no"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"upload() quantity of files + "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FileUpload&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

            &lt;span class="no"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"filePath "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filePath&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

            &lt;span class="nc"&gt;BufferedReader&lt;/span&gt; &lt;span class="n"&gt;br&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Files&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBufferedReader&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filePath&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

            &lt;span class="n"&gt;bus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"file-service"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;br&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="no"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"upload() before response Accepted"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accepted&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Class that will define the OpenAPI schema for the binary type input (upload)&lt;/span&gt;
    &lt;span class="nd"&gt;@Schema&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SchemaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;STRING&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"binary"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UploadItemSchema&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Class that will be used to define the request body, and with that&lt;/span&gt;
    &lt;span class="c1"&gt;// it will allow uploading of "N" files&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UploadFormSchema&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UploadItemSchema&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// We instruct OpenAPI to use the schema provided by the 'UploadFormSchema'&lt;/span&gt;
    &lt;span class="c1"&gt;// class implementation and thus define a valid OpenAPI schema for the Swagger&lt;/span&gt;
    &lt;span class="c1"&gt;// UI&lt;/span&gt;
    &lt;span class="nd"&gt;@Schema&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;UploadFormSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MultipartBody&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@RestForm&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"files"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FileUpload&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;This class consumes the events from the event bus and displays the data:&lt;/p&gt;

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

&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;org.acme&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.BufferedReader&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.IOException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.enterprise.context.ApplicationScoped&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.jboss.logging.Logger&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.quarkus.vertx.ConsumeEvent&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@ApplicationScoped&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FileService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt; &lt;span class="no"&gt;LOG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLogger&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FileService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

    &lt;span class="nd"&gt;@ConsumeEvent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blocking&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"file-service"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;processFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BufferedReader&lt;/span&gt; &lt;span class="n"&gt;br&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="no"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"processFile() begin"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;br&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;currentLine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;currentLine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;br&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readLine&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="no"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"currentLine "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;currentLine&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="no"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="no"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"processFile() end"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>quarkus</category>
      <category>java</category>
      <category>openapi</category>
      <category>github</category>
    </item>
    <item>
      <title>Controlling Hibernate Commit programmatically for batch execution on Quarkus</title>
      <dc:creator>Felipe Henrique Gross Windmoller</dc:creator>
      <pubDate>Thu, 31 Mar 2022 17:59:58 +0000</pubDate>
      <link>https://dev.to/felipewind/controlling-hibernate-commit-programmatically-for-batch-execution-on-quarkus-3fhk</link>
      <guid>https://dev.to/felipewind/controlling-hibernate-commit-programmatically-for-batch-execution-on-quarkus-3fhk</guid>
      <description>&lt;h2&gt;
  
  
  Problem with many commits during batch execution
&lt;/h2&gt;

&lt;p&gt;If you need to process a huge amount of data on a batch execution, it's important to control the number of commits that are done by Hibernate.&lt;/p&gt;

&lt;p&gt;Commit is one of the most expensive database operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the @Transactional annotation
&lt;/h2&gt;

&lt;p&gt;With Quarkus, you can control the execution of the commit using the &lt;code&gt;@Transactional&lt;/code&gt; annotation. When the method annotated with &lt;code&gt;@Transactional&lt;/code&gt; finishes successfully, Hibernate sends one commit to the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.transaction.Transactional&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="nd"&gt;@Transactional&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rollbackOn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;processClientOrders&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
     &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updateOrders&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
     &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insertHistory&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
     &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updateClient&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, when the processClientOrders() finishes, Hibernate sends one commit to the database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Difficulty in using @Transactional annotation to control batch execution
&lt;/h2&gt;

&lt;p&gt;On a batch execution, it's a good idea to control the numbers of commits using the quantity of processed items or time between commits.&lt;/p&gt;

&lt;p&gt;On my point of view, is a bit difficult to control this using the @Transactional annotation, specially to control the quantity of time between commits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Executing commit programmatically
&lt;/h2&gt;

&lt;p&gt;The contribution I try to give here is one idea to control the commits using the programmatic way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Define the commit parameters on you application
&lt;/h3&gt;

&lt;p&gt;This item is not obligatory, but I think is a good idea. Using this approach you can tune your values at deploy time.&lt;/p&gt;

&lt;p&gt;Define two parameters on your &lt;code&gt;application.properties&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="c"&gt;# Minimum quantity of items processed to execute commit
&lt;/span&gt;&lt;span class="py"&gt;app.quantity.of.items.to.commit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;1000&lt;/span&gt;

&lt;span class="c"&gt;# Minimum quantity of time (milliseconds) to execute commit
&lt;/span&gt;&lt;span class="py"&gt;app.quantity.of.time.ms.to.commit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;1000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Control the Transaction programmatically
&lt;/h3&gt;

&lt;p&gt;To control the Transaction programmatically you need to inject the &lt;code&gt;UserTransaction&lt;/code&gt; and then begin and commit the transaction manually.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Inject&lt;/span&gt;
&lt;span class="nc"&gt;UserTransaction&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@ConfigProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"app.quantity.of.items.to.commit"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;quantityItemsCommit&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@ConfigProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"app.quantity.of.time.ms.to.commit"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;quantityTimeCommit&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;batchProcess&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;listOfClients&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                 &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;SystemException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nc"&gt;NotSupportedException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                 &lt;span class="nc"&gt;SecurityException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;IllegalStateException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                 &lt;span class="nc"&gt;RollbackException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;HeuristicMixedException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;  
                 &lt;span class="nc"&gt;HeuristicRollbackException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;beforeCommit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Instant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;quantityOfClientsPendingCommit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;begin&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;listOfClients&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;processClientOrders&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Instant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;between&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;beforeCommit&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;toMillis&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(++&lt;/span&gt;&lt;span class="n"&gt;quantityOfClientsPendingCommit&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;quantityItemsCommit&lt;/span&gt;  
        &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;quantityTimeCommit&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
      &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;commit&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
      &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;begin&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
      &lt;span class="n"&gt;beforeCommit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Instant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
      &lt;span class="n"&gt;quantityOfClientsPendingCommit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;commit&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;processClientOrders&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
     &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updateOrders&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
     &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insertHistory&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
     &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updateClient&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code executes commit when the quantity of clients processed is greater or equal the limit or the time after the last commit is greater or equal the limit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;I hope that this article can add something and if you find some mistake that I did or have one idea to improve this concept, please comment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/9707938/calculating-time-difference-in-milliseconds"&gt;Stack Overflow post about calculating time in milliseconds&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://access.redhat.com/documentation/en-us/red_hat_build_of_quarkus/1.11/html-single/managing_jta_transactions_with_the_quarkus_transaction_manager/index#assembly_managing-jta-transactions-programmatically-using-the-api-approach_quarkus-transaction-manager"&gt;Red Hat documentation about Managing JTA transactions programmatically&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>hibernate</category>
      <category>quarkus</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>POC to parallelize long time processes using Kafka and Quarkus</title>
      <dc:creator>Felipe Henrique Gross Windmoller</dc:creator>
      <pubDate>Mon, 13 Dec 2021 21:26:48 +0000</pubDate>
      <link>https://dev.to/felipewind/poc-to-parallelize-long-time-processes-using-kafka-and-quarkus-3607</link>
      <guid>https://dev.to/felipewind/poc-to-parallelize-long-time-processes-using-kafka-and-quarkus-3607</guid>
      <description>&lt;h2&gt;
  
  
  poc-kafka-quarkus
&lt;/h2&gt;

&lt;p&gt;This project is available on &lt;a href="https://github.com/felipewind/poc-kafka-quarkus" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;POC to parallelize long time processes using Kafka and Quarkus.&lt;/p&gt;

&lt;p&gt;Imagine you have a big amount of items to process and each one takes a long time to finish.&lt;/p&gt;

&lt;p&gt;This POC proposes one solution to diminish the overall process time.&lt;/p&gt;

&lt;p&gt;The idea is simple, one application, the &lt;code&gt;producer&lt;/code&gt;, publishes messages on a Kafka topic and another application, the &lt;code&gt;processor&lt;/code&gt;, reads these messages and process them.&lt;/p&gt;

&lt;p&gt;If the messages don't need to be processed in an ordered way, we can configure the application, using SmallRye Reactive Message, to create a pool of threads and process multiple messages simultaneously. &lt;/p&gt;

&lt;p&gt;Kafka also allows that we consume messages from its topic from multiple instances of our application. To achieve this, we must configure the partition number of the topic. For instance, if our topic has a partition number of three and we run four instances of our application, three instances will be able to process one specific partition and the fourth will remain idle.&lt;/p&gt;

&lt;p&gt;In this POC I use both ideas, that is I run the processing application in multiple instances and each instance has its own thread pool that processes multiple messages simultaneously.&lt;/p&gt;

&lt;h2&gt;
  
  
  POC in action
&lt;/h2&gt;

&lt;p&gt;Just run the application, access the Swagger-UI to inform the quantity of items to process, execute it and check the results on the console log of the &lt;code&gt;producer&lt;/code&gt; and the &lt;code&gt;processor&lt;/code&gt; instances.&lt;/p&gt;

&lt;h3&gt;
  
  
  Swagger
&lt;/h3&gt;

&lt;p&gt;The Swagger-UI is on &lt;a href="http://localhost:8080/q/swagger-ui" rel="noopener noreferrer"&gt;http://localhost:8080/q/swagger-ui&lt;/a&gt;&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Producer sending messages
&lt;/h3&gt;

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

&lt;h3&gt;
  
  
  Processor instances receiving and processing messages
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1st instance with partition "2"&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;2nd instance with partitions "0" and "1"&lt;/strong&gt;&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Instructions to run
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Running everything with Docker Compose
&lt;/h3&gt;

&lt;p&gt;Compile the two projects&lt;/p&gt;

&lt;p&gt;Enter the processor folder and run:&lt;/p&gt;

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

$ ./mvnw package


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

&lt;/div&gt;

&lt;p&gt;Enter the producer folder and run:&lt;/p&gt;

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

$ ./mvnw package


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

&lt;/div&gt;

&lt;p&gt;Run the Docker Compose&lt;/p&gt;

&lt;p&gt;On the root folder, run:&lt;/p&gt;

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

$ docker-compose up


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

&lt;/div&gt;

&lt;p&gt;If you want to run multiple instances of the &lt;code&gt;processor&lt;/code&gt;, just pass the &lt;code&gt;scale&lt;/code&gt; argument:&lt;/p&gt;

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

$ docker-compose up --scale processor=2


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;NUM_PARTITIONS&lt;/code&gt; parameter of Kafka in the docker-compose file says how many partitions the topics will have.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running in development mode
&lt;/h3&gt;

&lt;p&gt;Start producer and processor&lt;/p&gt;

&lt;p&gt;Enter the processor folder and run:&lt;/p&gt;

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

$ mvn quarkus:dev


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

&lt;/div&gt;

&lt;p&gt;Enter the producer folder and run:&lt;/p&gt;

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

$ mvn quarkus:dev -Ddebug=5006


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

&lt;/div&gt;

&lt;p&gt;In this mode, Quarkus will automatically download one Kafka image and run it for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kafka concepts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Partitions
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;num.partitions&lt;/code&gt; parameter defines how many partitions the topic will have.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consumer groups
&lt;/h3&gt;

&lt;p&gt;The consumer group is defined by one id.&lt;/p&gt;

&lt;p&gt;One consumer group will receive all messages sent to a topic.&lt;/p&gt;

&lt;p&gt;One consumer group can have 'n' instances of applications running.&lt;/p&gt;

&lt;p&gt;Each instance of the consumer group will process messages from some partitons of the topic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consumer groups and partitions
&lt;/h3&gt;

&lt;p&gt;Each instance of the consumer group will be able to read one or more partitions of the topic.&lt;/p&gt;

&lt;p&gt;If you have more consumers than partitions, some consumers will remain idle. &lt;/p&gt;

&lt;h2&gt;
  
  
  Quarkus and SmallRye Reactive Message tips
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Processing messages in multiple worker threads
&lt;/h3&gt;

&lt;p&gt;If the messages don't need to be processed in order, you can use the following annotation:&lt;/p&gt;

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

&lt;span class="nd"&gt;@Incoming&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"extraction-requests"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Blocking&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ordered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"my-custom-pool"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Inform the number of threads of your &lt;code&gt;my-custom-pool&lt;/code&gt; in your application.properties:&lt;/p&gt;


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

&lt;p&gt;&lt;span class="py"&gt;smallrye.messaging.worker.my-custom-pool.max-concurrency&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;3&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Quarkus dev mode&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;You can inform the number of partitions the topic will have in your Kafka test container with this parameter, informing your topic name (in this case, extraction-requests) :&lt;/p&gt;


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

&lt;p&gt;quarkus.kafka.devservices.topic-partitions.extraction-requests=3&lt;/p&gt;

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

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Credits&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://quarkus.io/guides/kafka" rel="noopener noreferrer"&gt;https://quarkus.io/guides/kafka&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://strimzi.io/docs/operators/latest/using.html" rel="noopener noreferrer"&gt;https://strimzi.io/docs/operators/latest/using.html&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  smallrye
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://smallrye.io/smallrye-reactive-messaging/smallrye-reactive-messaging/3.13/index.html" rel="noopener noreferrer"&gt;https://smallrye.io/smallrye-reactive-messaging/smallrye-reactive-messaging/3.13/index.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://smallrye.io/smallrye-reactive-messaging/smallrye-reactive-messaging/3.1/advanced/blocking.html" rel="noopener noreferrer"&gt;https://smallrye.io/smallrye-reactive-messaging/smallrye-reactive-messaging/3.1/advanced/blocking.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://smallrye.io/smallrye-reactive-messaging/smallrye-reactive-messaging/3.1/emitter/emitter.html#_emitter_and_channel" rel="noopener noreferrer"&gt;https://smallrye.io/smallrye-reactive-messaging/smallrye-reactive-messaging/3.1/emitter/emitter.html#_emitter_and_channel&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>kafka</category>
      <category>quarkus</category>
      <category>github</category>
    </item>
    <item>
      <title>Shopping List</title>
      <dc:creator>Felipe Henrique Gross Windmoller</dc:creator>
      <pubDate>Tue, 12 Oct 2021 22:22:57 +0000</pubDate>
      <link>https://dev.to/felipewind/shopping-list-15ao</link>
      <guid>https://dev.to/felipewind/shopping-list-15ao</guid>
      <description>&lt;p&gt;The Shopping List project is open source and you can find it on &lt;a href="https://github.com/felipewind/shopping-list"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There, you are going to find instructions on how to build it and how to run it locally.&lt;/p&gt;

&lt;p&gt;The frontend is written in Angular and the backend in Quarkus. The database is PostgreSQL. They are deployed as containers on Heroku and the HTTP communication is protected by JWT tokens.&lt;/p&gt;

&lt;p&gt;I describe the technique used to deploy them as containers on Heroku in &lt;a href="https://medium.com/@felipewind/deploying-quarkus-postgresql-and-angular-nginx-on-heroku-as-containers-7244507e548f"&gt;this article on medium&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can access &lt;a href="https://best-shopping-list.herokuapp.com/#/"&gt;this demo version running on Heroku&lt;/a&gt; and try it right now. But as this is only a demo, please don't use a real password there!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The application get dormant after some time without use, so the first access can take some extra time.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  Business description
&lt;/h2&gt;

&lt;p&gt;Shopping List is a web application that was created especially for mobile devices.&lt;/p&gt;

&lt;p&gt;You'll be able to organize the products you want to buy and do your shopping more quickly.&lt;/p&gt;

&lt;p&gt;Once you create one account, you can create shopping lists and add products to them.&lt;/p&gt;

&lt;p&gt;When you're buying products at the market, you can check the products updating your list and switch from one shopping list to other very easily.&lt;/p&gt;

&lt;p&gt;You can, for instance, create one shopping list for fruits, other for cleaning products and another for grocery. So, in the top menu, you will be able to switch between these shopping lists while you're checking the products you already bought.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

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

&lt;h2&gt;
  
  
  Demo version running on Heroku
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://best-shopping-list.herokuapp.com/#/"&gt;Application&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://shopping-list-back-end.herokuapp.com/q/swagger-ui/"&gt;API swagger&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Angular
&lt;/h2&gt;

&lt;p&gt;I used Angular Material and &lt;a href="https://github.com/angular/flex-layout"&gt;Angular Flex-Layout&lt;/a&gt; in this project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quarkus
&lt;/h2&gt;

&lt;p&gt;On the Quarkus project I used Hibernate Panache to control the database and SmallRye JWT to protect the endpoints.&lt;/p&gt;

&lt;p&gt;Perhaps you can find it interesting the Swagger-UI, created automatically by the SmallRye OpenAPI, that has the possibility of doing one &lt;a href="https://github.com/felipewind/shopping-list#authentication-on-swagger"&gt;Authentication&lt;/a&gt; to test the endpoints protected by JWT.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;Thanks for reading this article and feel free to talk with me in case you got interested in this project!&lt;/p&gt;

</description>
      <category>angular</category>
      <category>quarkus</category>
      <category>docker</category>
      <category>github</category>
    </item>
    <item>
      <title>Create one Docker image of Angular + Nginx with dynamic API url</title>
      <dc:creator>Felipe Henrique Gross Windmoller</dc:creator>
      <pubDate>Fri, 09 Jul 2021 19:37:52 +0000</pubDate>
      <link>https://dev.to/felipewind/create-one-docker-image-of-angular-nginx-with-dynamic-api-url-57mi</link>
      <guid>https://dev.to/felipewind/create-one-docker-image-of-angular-nginx-with-dynamic-api-url-57mi</guid>
      <description>&lt;p&gt;In this tutorial, I explain one workaround that I did to create one Docker image of one Angular application which has one dynamic API URL.&lt;/p&gt;

&lt;p&gt;The article &lt;a href="https://www.mokkapps.de/blog/how-to-build-an-angular-app-once-and-deploy-it-to-multiple-environments#solution-4-override-environment-file-values"&gt;How To Build An Angular App Once And Deploy It To Multiple Environments - Solution 4: Override environment file values&lt;/a&gt; explains how you can do this.&lt;/p&gt;

&lt;p&gt;But, as I'm far from a Docker expert, I spent some time to create the Dockerfile to do this :)&lt;/p&gt;

&lt;p&gt;Just quoting the &lt;a href="https://www.mokkapps.de/blog/how-to-build-an-angular-app-once-and-deploy-it-to-multiple-environments#solution-4-override-environment-file-values"&gt;article&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The idea is to use Angular’s environment.ts (for local development) and environment.prod.ts (for all other stages) with placeholder values which are overwritten per deployment:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;apiUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MY_APP_API_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MY_APP_STAGE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;If our pod is started we can then run the following script, for example in a Dockerfile, that overrides these placeholder values:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="c"&gt;# replace placeholder value in JS bundle with environment specific values&lt;/span&gt;
&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"s#MY_APP_API_URL#&lt;/span&gt;&lt;span class="nv"&gt;$API_URL&lt;/span&gt;&lt;span class="s2"&gt;#g"&lt;/span&gt; /usr/share/nginx/html/main.&lt;span class="k"&gt;*&lt;/span&gt;.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  My contribution
&lt;/h2&gt;

&lt;p&gt;Here is the Dockerfile I created to run this workaround:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; nginx:latest&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; dist/your-app-name /usr/share/nginx/html&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["/bin/bash", "-c", \&lt;/span&gt;
"echo API_URL=[$API_URL], &amp;amp;&amp;amp; \
sed -i s&lt;span class="c"&gt;#MY_APP_API_URL#$API_URL#g /usr/share/nginx/html/main.*.js &amp;amp;&amp;amp; \&lt;/span&gt;
nginx -g 'daemon off;'"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ng build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Place this Dockerfile into your Angular root folder and run this to build your image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker build -t angular/your-app-name .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this, just run your container passing the &lt;code&gt;API_URL&lt;/code&gt; variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker run -p 80:80 --name your-app-name -e API_URL=http://localhost:8080 angular/your-app-name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>angular</category>
      <category>docker</category>
      <category>nginx</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>POC where Angular requests URL of image and Quarkus provides it through a raw copy and base64</title>
      <dc:creator>Felipe Henrique Gross Windmoller</dc:creator>
      <pubDate>Sun, 27 Jun 2021 19:19:06 +0000</pubDate>
      <link>https://dev.to/felipewind/poc-where-angular-requests-url-of-image-and-quarkus-provides-it-through-a-raw-copy-and-base64-4ia9</link>
      <guid>https://dev.to/felipewind/poc-where-angular-requests-url-of-image-and-quarkus-provides-it-through-a-raw-copy-and-base64-4ia9</guid>
      <description>&lt;p&gt;A simple POC where Angular requests the URL of an image to the Quarkus back end and then renders the image in the screen. Quarkus returns the image in two ways: (1) a simple copy from the URL of the image; (2) the image encoded in Base64 with the Media Type.&lt;/p&gt;

&lt;p&gt;The project is available on GitHub &lt;a href="https://github.com/felipewind/poc-http-copy-images" rel="noopener noreferrer"&gt;poc-http-copy-images&lt;/a&gt;.&lt;/p&gt;

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

&lt;h1&gt;
  
  
  Hypothetical problem to solve
&lt;/h1&gt;

&lt;p&gt;Let's imagine a hypothetical situation where only the backend have access to the URL of some images and you want to render these images on the frontend.&lt;/p&gt;

&lt;p&gt;In this POC, I propose two ways of solving this problem:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The backend access the URL of the image and expose the same Response object;&lt;/li&gt;
&lt;li&gt;The backend access the URL of the image, encode it into Base64 and expose it into a JSON object with the Media Type.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Running the POC
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Mock Server
&lt;/h2&gt;

&lt;p&gt;Optionally, you can run a Quarkus mock server which will provide three endpoints with the below images:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://localhost:8090/image/earth.png" rel="noopener noreferrer"&gt;http://localhost:8090/image/earth.png&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://localhost:8090/image/moon.jpg" rel="noopener noreferrer"&gt;http://localhost:8090/image/moon.jpg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://localhost:8090/image/solarsystem.svg" rel="noopener noreferrer"&gt;http://localhost:8090/image/solarsystem.svg&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;*** Optionally, because you can choose any image from the internet to run the test.&lt;/p&gt;

&lt;p&gt;Enter inside the mock-server folder and type:&lt;/p&gt;

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

$ mvn quarkus:dev -Ddebug=5006


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

&lt;/div&gt;

&lt;p&gt;The swagger will be available at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://localhost:8090/q/swagger-ui" rel="noopener noreferrer"&gt;http://localhost:8090/q/swagger-ui&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  Quarkus backend
&lt;/h2&gt;

&lt;p&gt;Enter inside the quarkus folder and type:&lt;/p&gt;

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

$ mvn quarkus:dev -Ddebug=5006


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

&lt;/div&gt;

&lt;p&gt;The swagger will be available at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://localhost:8080/q/swagger-ui" rel="noopener noreferrer"&gt;http://localhost:8080/q/swagger-ui&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  Angular frontend
&lt;/h2&gt;

&lt;p&gt;Enter inside the angular folder and type:&lt;/p&gt;

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

$ npm install
$ ng serve


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

&lt;/div&gt;

&lt;p&gt;The front end will be available at:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://localhost:4200/" rel="noopener noreferrer"&gt;http://localhost:4200/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok, in this screen, just put the URL of any image you desire (of the mock or the internet) and click on &lt;code&gt;Load Image&lt;/code&gt;:&lt;/p&gt;

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

&lt;p&gt;After clicking in the button, the image will be displayed in two columns, the left one is the raw copy from the URL and the right one is the Base64 version:&lt;/p&gt;

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

&lt;p&gt;Any new image searched will be shown and the previous ones will slide down:&lt;/p&gt;

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

</description>
      <category>angular</category>
      <category>java</category>
      <category>github</category>
      <category>quarkus</category>
    </item>
  </channel>
</rss>
