Перейти к содержанию

Add endpoint

Рецепт: создать новый Serverpod endpoint с нуля.

Шаг 1: Создать YAML модель (если нужна новая таблица)

# onewallet_base_server/lib/src/models/my_model.spy.yaml
class: MyModel
table: my_model
fields:
  userId: int
  value: String
  createdAt: DateTime
indexes:
  my_model_user_idx:
    fields: userId

Правила YAML: - Тип поля — Dart-синтаксис: int, String, DateTime, bool, double - Для nullable: String? - id генерируется автоматически, не объявлять - Имена полей — camelCase; в SQL Serverpod процитирует как "userId", "createdAt" (всегда цитировать в raw SQL)

Шаг 2: Запустить codegen

cd onewallet_base_server
serverpod generate

После этого в lib/src/generated/ появится Dart-класс модели. Если модель с таблицей — в migrations/ появится SQL-миграция.

Шаг 3: Создать endpoint файл

// onewallet_base_server/lib/src/endpoints/my_endpoint.dart
import 'package:serverpod/serverpod.dart';
import '../util/endpoint_guard.dart';
import '../generated/my_model.dart';

class MyEndpoint extends Endpoint {
  @override
  bool get requireLogin => true;

  Future<String> doSomething(Session session, String param) async {
    // requireAccountType выбросит NotAuthorizedException если тип не совпадает
    final user = await requireAccountType(session, ['consumer', 'wallet']);

    // Бизнес-логика
    final row = await MyModel.db.findFirstRow(
      session,
      where: (t) => t.userId.equals(user.id!),
    );

    return row?.value ?? 'default';
  }

  Future<void> createSomething(Session session, String value) async {
    final user = await requireAccountType(session, ['consumer']);

    await MyModel.db.insertRow(
      session,
      MyModel(
        userId: user.id!,
        value: value,
        createdAt: DateTime.now().toUtc(),
      ),
    );
  }
}

Типы account для requireAccountType: - 'consumer' — пользователи wallet и closeloop - 'wallet' — только основной кошелёк - 'merchant' — мерчант - 'agent' — агент

Шаг 4: Регистрация в endpoints

Не редактировать lib/src/generated/endpoints.dart вручную. Serverpod находит эндпоинты автоматически по наследованию от Endpoint. Повторно запустите codegen:

serverpod generate

Имя эндпоинта на клиенте = имя класса в camelCase без суффикса Endpoint: MyEndpointendpoints.my (или endpoints.myEndpoint в зависимости от версии Serverpod).

Шаг 5: Применить миграцию (если создана новая модель с таблицей)

dart bin/main.dart --apply-migrations

Шаг 6: Написать тест

// test/integration/my_endpoint_test.dart
import 'package:test/test.dart';
import 'package:serverpod/serverpod.dart';
import 'package:uuid/uuid.dart';
import '../test_tools/serverpod_test_tools.dart';
import 'package:onewallet_base_server/src/generated/user.dart';

void main() {
  withServerpod('MyEndpoint',
      rollbackDatabase: RollbackDatabase.afterEach,
      (sessionBuilder, endpoints) {

    // Создать тестового пользователя с authUserId для аутентификации
    Future<String> seedUser(Session session) async {
      final authUuidStr = const Uuid().v4();
      await User.db.insertRow(session, User(
        email: 'test-${authUuidStr}@test.local',
        passwordHash: '',
        status: 'active',
        accountType: 'consumer',
        authUserId: UuidValue.fromString(authUuidStr),
        createdAt: DateTime.now(),
        isArchived: false,
      ));
      return authUuidStr;
    }

    test('doSomething returns default when no row', () async {
      final session = sessionBuilder.build();
      final authUuid = await seedUser(session);

      final authedSession = sessionBuilder.copyWith(
        authentication: AuthenticationOverride.authenticationInfo(authUuid, const {}),
      ).build();

      final result = await endpoints.my.doSomething(authedSession, 'param');
      expect(result, equals('default'));
    });
  });
}