Найти в Дзене
Записки сисадмина

Python. CGI. Пишем простейшее API.

Звенит январская вьюга, как жаль, что в Москве и в начале мая. Раз уж планы с шашлыком отменились, греемся не возле мангала, а под одеялом и котейкой. И, конечно же, продолжаем изучать что-то новое. Бывает иногда такая ситуация, что тебе нужно как-то отправить данные из одного приложения в другое. Конечно, есть огромный спектр способов и вариаций это сделать, но, когда у тебя в команде одни веб разработчики, тебе придется немного отступить и согласиться на запросы по http и поднимать свое api. Итак, вводные: Приступим: apt install nginx systemctl start nginx systemctl enable nginx В любых дистрибутивах это будет указано первой строчкой в файле /etc/nginx/nginx.conf Нам же это нужно будет для того, чтобы выдать правильные права на папку и скрипт, иначе nginx не сможет его запустить. mkdir /var/www/python_api chown -R www-data:www-data /var/www/python_api/ touch /etc/nginx/sites-enabled/api.conf server { listen 80; location / { gzip off; root /var/www/python_api; fastcgi_pass unix:/v
Оглавление

Звенит январская вьюга, как жаль, что в Москве и в начале мая. Раз уж планы с шашлыком отменились, греемся не возле мангала, а под одеялом и котейкой. И, конечно же, продолжаем изучать что-то новое.

Бывает иногда такая ситуация, что тебе нужно как-то отправить данные из одного приложения в другое.

Конечно, есть огромный спектр способов и вариаций это сделать, но, когда у тебя в команде одни веб разработчики, тебе придется немного отступить и согласиться на запросы по http и поднимать свое api.

Итак, вводные:

  1. К нашей виртуалке будут обращаться по http (значит, нам нужен веб сервер)
  2. Нам будут передавать данные (которые мы должны будем обработать)
  3. В ответ от нас ожидают json объект с результатом (понадобится библиотека json)

Приступим:

Настраиваем веб сервер

  • Устанавливаем nginx на наш сервер:
apt install nginx

  • Запускам его и добавляем в автозагрузку:
systemctl start nginx
systemctl enable nginx

  • Проверяем, что он запустился и работает:
  • Перейдя по IP нашего сервера увидим приветственную надпись веб сервера:
-2
  • Заранее проверяем, какая версия python у нас установлена (позже объясню, для чего):
-3
  • Проверяем, под каким пользователем у нас работает nginx:
-4

В любых дистрибутивах это будет указано первой строчкой в файле /etc/nginx/nginx.conf

Нам же это нужно будет для того, чтобы выдать правильные права на папку и скрипт, иначе nginx не сможет его запустить.

  • Создадим папку, где будет находиться скрипт и дадим nginx права на нее:
mkdir /var/www/python_api
chown -R www-data:www-data /var/www/python_api/
-5
  • Создадим конфигурационный файл для nginx в папке /etc/nginx/sites-enabled
touch /etc/nginx/sites-enabled/api.conf

  • Запишем туда такой location:
server {
listen 80;
location / {
gzip off;
root /var/www/python_api;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME /var/www/python_api$fastcgi_script_name;
}
}
-6
  • Проверяем правильность нашего конфиг файла:
-7
  • Не забываем установить fcgiwrap, иначе увидим следующую ошибку:
2025/05/02 15:37:58 [crit] 5281#5281: *4 connect() to unix:/var/run/fcgiwrap.socket failed (2: No such file or directory) while connecting to upstream, client: 192.168.122.1, server: , request: "GET / HTTP/1.1", upstream: "fastcgi://unix:/var/run/fcgiwrap.socket:", host: "192.168.122.152"

apt install fcgiwrap
sudo systemctl enable fcgiwrap
sudo systemctl start fcgiwrap

  • Создаем скрипт, к которому будем обращаться:
-8
touch /var/www/python_api/api.py
chown www-data:www-data /var/www/python_api/api.py

  • Также делаем наш файл исполняемым:
chmod +x /var/www/python_api/api.py

  • Добавляем в наш файл строки:
-9
  • Сохраняем и перезапускаем наш веб сервер:
systemctl restart nginx

Знакомимся с CGI

В прошлой статье мы разбирались с тем, как отправлять http запросы. Настало время использовать эти знания.

  • Проверяем то, что нам отдает наш веб сервер:
-10
-11
  • Однако, если мы передадим что-то в параметрах, наш сервер это не поймет.
-12
-13

Как мы видим, наш скрипт пока что не умеет принимать никаких параметров в запросе. Так мы сталкиваемся с тем, что нам нужен cgi.

Маленькое лирическое отступление.

Если мы загуглим "python3 cgi", по первой же ссылке увидим:

-14

Библиотека cgi была удалена из python версии 3.13. Именно для этого мы и проверяли версию python на нашем веб сервере. Если же вы используете версию python 3.13 и выше, вам на помощь придет эта библиотека. Это форк стандартной cgi библиотеки, который поддерживается в python 3.13. При этом, синтаксис самих скриптов никак не меняется.

Если же у вас версия python 3.12 и ниже, у вас будет уже установлена классическая версия cgi.

Конец лирического отступления.

  • Давайте научим наш скрипт принимать параметры. За это у нас отвечает модуль cgi.FieldStorage().
-15
  • При отправке того же запроса, что и ранее, мы получим следующий результат:
-16
  • Однако, у нашей формы есть метод getvalue(), который может по ключу найти значение в запросе:
-17
-18
  • Осталось только добавить логики.

В ответ на наш запрос мы хотим отдавать не текст, а json объект, а полученное имя в параметре 'user' мы будем обрабатывать в отдельной функции.

Также мы должны отдавать статус True/False, чтобы при обращении к нашему скрипту было понятно, отработал он правильно, или нет. А в случае какого-либо Exception, он отдавал весь Traceback.

-19
-20
#!/usr/bin/python3
import cgi
import json
form = cgi.FieldStorage()
user = form.getvalue('user')
def some_func(param):
return f'{param} is our new user'
try:
new_string = some_func(param=user)
status_code = True
error = None
except Exception as e:
new_string = ''
status_code = False
error = e
print("Content-type: application/json\n")
response = {'status': status_code, 'error': error, 'content': new_string}
print(json.dumps(response))

В заключение хочется напомнить: любой ответ нашего веб сервера формируется с помощью нескольких вызовов print(), где в первом вы должны указать, какой тип данных передаете, а в следующем - уже сами данные.