Tic Tac Toe, часть 0: Сравнение Svelte и React
Tic Tac Toe, часть 1: Svelte и Canvas 2D
Tic Tac Toe, часть 2: Undo/Redo с хранением состояний
Tic Tac Toe, часть 3: Undo/Redo с хранением команд
Tic Tac Toe, часть 4: Взаимодействие с бэкендом на Flask с помощью HTTP
В этой статье рассмотрим взаимодействие веб-приложения на Svelte из предыдущей статьи с бэкендом на Flask при помощи HTTP запросов. Оказалось, что поднять контейнер с бэкенд приложением на Flask быстрее чем на Boost.Beast, поэтому сделал пример с Flask. Не огорчайтесь, пример с Boost.Beast будет немного позже.
Установка проекта
Предполагается, что docker и docker-compose установлены на компьютере.
Клонируем проект на свой компьютер:
git clone https://github.com/nomhoi/tic-tac-toe-part4.git
Запускаем контейнеры:
cd tic-tac-toe-part4
docker-compose up -d
Выполняем сборку веб-приложения:
cd front
npm install
npm run-script build
Открываем броузер по адресу http://localhost. На Windows машине узнаем IP docker машины, обычно это http://192.168.99.100.
Мы видим, что справа появилась кнопка Get random number. По нажатии на эту кнопку веб-приложение обращается к бэкенду — выполняет запрос http://localhost/number и получает от него случайное число от 0 до 8 включительно. Это число используется для выполнения программного клика мышкой по игровому полю, вызывается метод history.push, на игровом поле появляется крестик или нолик. Если клетка уже занята, то появляется сообщение busy.
Docker контейнеры
Недавно на хабре появилась замечательная статья по docker и docker-compose для начинающих, можно ознакомиться. Здесь укажу только на моменты имеющие отношение к нашему проекту. Рассмотрим docker-compose.yml файл. Имеем два сервиса: nginx и flask.
docker-compose.yml:
version: "3.5"
services:
nginx:
image: nginx:alpine
container_name: nginx
volumes:
- ./front/public:/usr/share/nginx/html
- ./default.conf:/etc/nginx/conf.d/default.conf:ro
ports:
- "80:80"
depends_on:
- flask
networks:
- backend
flask:
build:
context: flask/
dockerfile: Dockerfile
ports:
- "5000:5000"
volumes:
- ./flask:/code
environment:
FLASK_ENV: development
networks:
- backend
networks:
backend:
name: backend
Сервис nginx запускает веб-сервер nginx, под которым выполняется наше веб-приложение. Сервис flask запускает Flask сервер с нашим небольшим бэкенд приложением.
Фронтенд
Веб-приложение взяли из предыдущей статьи и поместили в папку front. В проект добавили еще один компонент Dispatcher, который координирует взаимодействие между веб-приложением и бэкендом.
Dispatcher.svelte:
<script>
import { history, status } from './stores.js';
import { Command } from './helpers.js';
let promise = null;
async function getRandomNumber() {
const res = await fetch(`number`);
const text = await res.text();
if (res.ok) {
let i = parseInt(text);
if ($status === 1 || $history.state.squares[i])
return text + ' - busy';
history.push(new Command($history.state, i));
return text;
} else {
throw new Error(text);
}
}
function handleClick() {
promise = getRandomNumber();
}
//setInterval(handleClick, 500);
</script>
{#if $status > 0}
<button disabled>
Get random number
</button>
{:else}
<button on:click={handleClick}>
Get random number
</button>
{/if}
{#await promise}
<p>...подождите</p>
{:then number}
<p>Respond from backend: {number}</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
Код почти полностью взят из этого примера. По клику по кнопке Get random number в функции getRandomNumber() выполняется запрос по URI http://localhost/number, nginx передает запрос бэкенду, и он возвращает случайное число. Это число используется для добавления шага в историю.
Адрес http://localhost/number можно ввести в отдельной вкладке браузера и увидеть, что по запросу возвращаются разные числа.
В настройках веб-сервера nginx в файл конфигурации по-умолчанию default.conf добавили следующую настройку:
location /number {
proxy_pass http://flask:5000;
}
Благодаря этой настройке и производится передача запроса бэкенд серверу.
Бэкенд
Основа для настройки сервиса flask взята здесь: https://docs.docker.com/compose/gettingstarted/.
App.py:
from flask import Flask
from random import randrange
app = Flask(__name__)
@app.route('/number')
def number():
return str(randrange(9))
Когда приходит запрос на адрес /number вызывается функция number(). По коду видно, что выполняется возврат случайного числа в диапазоне от 0 до 8 включительно.
Заключение
Обычно сообщения в веб-приложениях передаются в формате JSON. Но такую не сложную вещь можно и так сделать.
В следующих статьях имеет смысл рассмотреть реализацию многопользовательского веб-приложения когда один игрок играет с другим игроком через общий веб-сервер. Можно рассмотреть вариант когда игрок играет с интеллектуальным агентом с реализацией логики приложения на самом сервере, а не в фронтенд-приложении.