113 lines
4.1 KiB
Markdown
113 lines
4.1 KiB
Markdown
# Notes App — Flutter + Go + gRPC (Protobuf)
|
||
|
||
Fullstack приложение-пример: **единая типизация** между Flutter фронтендом и Go бекендом через Protocol Buffers.
|
||
|
||
## Структура
|
||
|
||
```
|
||
.
|
||
├── proto/ # ЕДИНЫЙ ИСТОЧНИК ПРАВДЫ
|
||
│ ├── notes/v1/notes.proto # Типы + API контракт
|
||
│ ├── buf.yaml # Конфиг Buf (линтинг, deps)
|
||
│ └── buf.gen.yaml # Конфиг кодогенерации
|
||
│
|
||
├── backend/ # Go gRPC сервер
|
||
│ ├── main.go # Точка входа, запуск gRPC
|
||
│ ├── service/note_service.go # Реализация NoteService
|
||
│ └── gen/notes/v1/ # Сгенерированный Go код
|
||
│ ├── notes.pb.go # Структуры (Note, Request, Response)
|
||
│ └── notes_grpc.pb.go # gRPC интерфейсы и регистрация
|
||
│
|
||
├── frontend/ # Flutter приложение
|
||
│ └── lib/
|
||
│ ├── main.dart # Точка входа
|
||
│ ├── screens/notes_screen.dart
|
||
│ ├── services/grpc_client.dart
|
||
│ └── gen/notes/v1/ # Сгенерированный Dart код
|
||
│ ├── notes.pb.dart # Классы (Note, Request, Response)
|
||
│ └── notes.pbgrpc.dart # gRPC клиент NoteServiceClient
|
||
│
|
||
└── generate.sh # Скрипт кодогенерации
|
||
```
|
||
|
||
## Как это работает
|
||
|
||
```
|
||
notes.proto (единый контракт)
|
||
│
|
||
buf generate
|
||
┌─┴─┐
|
||
│ │
|
||
Go structs Dart classes
|
||
+ gRPC server + gRPC client
|
||
│ │
|
||
backend/gen frontend/lib/gen
|
||
```
|
||
|
||
1. Все типы и API описаны в одном `.proto` файле
|
||
2. Из него генерируется типизированный код для **обоих** языков
|
||
3. Изменил proto → перегенерировал → **ошибки компиляции** на той стороне, где контракт нарушен
|
||
4. Невозможно отправить запрос с неверным типом — Dart не скомпилируется
|
||
5. Невозможно вернуть ответ с неверной структурой — Go не скомпилируется
|
||
|
||
## Быстрый старт
|
||
|
||
### 1. Запуск Go бекенда
|
||
|
||
```bash
|
||
cd backend
|
||
go run main.go
|
||
# → gRPC server listening on :50051
|
||
```
|
||
|
||
### 2. Запуск Flutter фронтенда
|
||
|
||
```bash
|
||
cd frontend
|
||
flutter run -d windows # или -d chrome, -d android и т.д.
|
||
```
|
||
|
||
### 3. Перегенерация кода (после изменения proto)
|
||
|
||
```bash
|
||
# Установи buf (один раз):
|
||
npm install -g @bufbuild/buf
|
||
|
||
# Генерация:
|
||
bash generate.sh
|
||
```
|
||
|
||
Или через protoc напрямую:
|
||
```bash
|
||
# Установи плагины (один раз):
|
||
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
|
||
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
|
||
dart pub global activate protoc_plugin
|
||
|
||
# Генерация:
|
||
bash generate.sh
|
||
```
|
||
|
||
## Ключевая идея
|
||
|
||
Представь, что ты добавил новое поле `priority` в заметку:
|
||
|
||
```protobuf
|
||
message Note {
|
||
string id = 1;
|
||
string title = 2;
|
||
string content = 3;
|
||
google.protobuf.Timestamp created_at = 4;
|
||
google.protobuf.Timestamp updated_at = 5;
|
||
int32 priority = 6; // ← НОВОЕ ПОЛЕ
|
||
}
|
||
```
|
||
|
||
После `buf generate`:
|
||
- В Go: `note.Priority` доступно сразу
|
||
- В Dart: `note.priority` доступно сразу
|
||
- Оба языка знают о новом поле на этапе **компиляции**
|
||
- Если забыл его обработать — компилятор предупредит
|
||
|
||
Это аналог того, что Next.js делает для TS фронта/бека, но для **разных языков**.
|