<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Лайвкодинг FastAPI on IT Ментор | Python методичка</title><link>https://zhukovsd.github.io/python-backend-interview-prep/livecoding/tasks/fastapi/</link><description>Recent content in Лайвкодинг FastAPI on IT Ментор | Python методичка</description><generator>Hugo</generator><language>ru</language><atom:link href="https://zhukovsd.github.io/python-backend-interview-prep/livecoding/tasks/fastapi/index.xml" rel="self" type="application/rss+xml"/><item><title>Загрузка платежей с проверкой блокировки записи в БД</title><link>https://zhukovsd.github.io/python-backend-interview-prep/livecoding/tasks/fastapi/payment-upload-lock-check/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://zhukovsd.github.io/python-backend-interview-prep/livecoding/tasks/fastapi/payment-upload-lock-check/</guid><description>&lt;h4&gt;2. Загрузка платежей с проверкой блокировки записи в БД&lt;/h4&gt;
 &lt;p&gt;&lt;strong&gt;Условие задачи:&lt;/strong&gt;&lt;br&gt;
Дан API-эндпоинт на FastAPI для загрузки файла со списком платежей. Файл содержит до 1000 записей, каждая из которых включает ИНН получателя, номер счета, сумму и назначение платежа.&lt;br&gt;
Нужно доработать обработку загрузки так, чтобы при сохранении платежей дополнительно выполнялась проверка: не заблокирована ли соответствующая запись в базе данных.&lt;br&gt;
Если запись заблокирована, такая операция должна корректно обрабатываться и учитываться при формировании результата обработки файла.&lt;br&gt;
Предложи дополнительные способы оптимизации&lt;/p&gt;</description></item><item><title>Критика кода перевода средств в FastAPI</title><link>https://zhukovsd.github.io/python-backend-interview-prep/livecoding/tasks/fastapi/fastapi-transfer-review/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://zhukovsd.github.io/python-backend-interview-prep/livecoding/tasks/fastapi/fastapi-transfer-review/</guid><description>&lt;h4&gt;1. Критика кода перевода средств в FastAPI&lt;/h4&gt;
 &lt;p&gt;&lt;strong&gt;Условие задачи:&lt;/strong&gt;&lt;br&gt;
Дан фрагмент кода на FastAPI и asyncpg, реализующий создание таблицы пользователей и эндпоинт для перевода денег между пользователями.&lt;/p&gt;
&lt;p&gt;Нужно провести критический разбор этого кода: найти архитектурные, логические, SQL-, безопасностные и синтаксические проблемы, а также указать, почему такая реализация может приводить к ошибкам, уязвимостям или некорректной работе сервиса.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;import asyncpg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fastapi &lt;span style="color:#f92672"&gt;import&lt;/span&gt; FastAPI, Body, HTTPException
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app FastAPI()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DB_DSN &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;postgresql:&lt;span style="color:#f92672"&gt;//&lt;/span&gt;test:test&lt;span style="color:#a6e22e"&gt;@localhost&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;testdb&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_connection&lt;/span&gt;()&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; asyncpg&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Connection: 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; asyncpg&lt;span style="color:#f92672"&gt;.&lt;/span&gt;connect(DB_DSN)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@app.on_event&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;startup&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;on_startup&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;conn &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; get_connection()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; conn&lt;span style="color:#f92672"&gt;.&lt;/span&gt;execute(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;‘’’&lt;/span&gt;CREATE TABLE IF NOT EXISTS &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;user&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id TEXT NOT NULL, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;name TEXT NOT NULL, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;balance DOUBLE PRECISION )&lt;span style="color:#960050;background-color:#1e0010"&gt;’’’&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@app.post&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;transfer&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;transfer&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; user: str &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Body(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;to_user: str &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Body(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;amount: float &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Body(),):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;conn &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; get_connection()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;row &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; conn&lt;span style="color:#f92672"&gt;.&lt;/span&gt;fetchrow(&lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;select id, balance from &amp;#34;&amp;#34;user&amp;#34;&amp;#34; where id = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;from_user&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; row[&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;balance&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; amount:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;raise&lt;/span&gt; HTTPException(status_code&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;400&lt;/span&gt;, detail&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;Insufficient funds&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; conn&lt;span style="color:#f92672"&gt;.&lt;/span&gt;execute(&lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;UPDATE &amp;#34;&amp;#34;user&amp;#34;&amp;#34; SET balance = balance -&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;amount&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; WHERE id = (from_user&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;conn&lt;span style="color:#f92672"&gt;.&lt;/span&gt;execute(&lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;UPDATE &amp;#34;&amp;#34;user&amp;#34;&amp;#34; SET balance balance + &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;amount&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; WHERE id = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;to_user&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; {&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;success&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;}&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote class="book-hint warning"&gt;
 &lt;strong&gt;Спойлеры к решению&lt;/strong&gt;
&lt;/blockquote&gt;

&lt;details &gt;&lt;summary&gt;Подсказки&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 &lt;ul&gt;
&lt;li&gt;В коде есть синтаксические ошибки: &lt;code&gt;app FastAPI()&lt;/code&gt;, &lt;code&gt;conn await get_connection()&lt;/code&gt;, &lt;code&gt;await.conn.execute(...)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Таблица названа &lt;code&gt;&amp;quot;user&amp;quot;&lt;/code&gt; — это неудобное имя, лучше использовать &lt;code&gt;users&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Подключение к БД создаётся на каждый запрос и не закрывается.&lt;/li&gt;
&lt;li&gt;Для FastAPI-сервиса лучше использовать пул соединений.&lt;/li&gt;
&lt;li&gt;SQL собирается через f-string, что создаёт SQL-инъекцию.&lt;/li&gt;
&lt;li&gt;Денежные суммы нельзя хранить в &lt;code&gt;DOUBLE PRECISION&lt;/code&gt; и принимать как &lt;code&gt;float&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Перевод денег должен выполняться внутри транзакции.&lt;/li&gt;
&lt;li&gt;При конкурентных запросах нужно блокировать строки пользователей.&lt;/li&gt;
&lt;li&gt;Нужно проверять существование обоих пользователей.&lt;/li&gt;
&lt;li&gt;Нужно проверять, что сумма положительная.&lt;/li&gt;
&lt;/ul&gt;

 &lt;/div&gt;
&lt;/details&gt;

&lt;details &gt;&lt;summary&gt;Решение&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 &lt;p&gt;В коде смешаны сразу несколько типов проблем: синтаксис, SQL-инъекции, некорректная работа с соединениями, отсутствие транзакции, race condition при переводе денег и неправильный тип для баланса.&lt;/p&gt;</description></item></channel></rss>