diff --git a/.github/workflows/build-api.yml b/.github/workflows/build-api.yml index 07fbdb9..02ad683 100644 --- a/.github/workflows/build-api.yml +++ b/.github/workflows/build-api.yml @@ -25,6 +25,7 @@ jobs: run: | cd apps/api bun i + npx prisma generate - name: API build run: bun run build:api diff --git a/.gitignore b/.gitignore index 30b891f..43e3a91 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .idea **/.env .env -apps/api/.env -apps/shared/.env -apps/web/.env + +**/.env + +**/dist diff --git a/apps/api/README.md b/apps/api/README.md index 97f26da..1851b96 100644 --- a/apps/api/README.md +++ b/apps/api/README.md @@ -9,9 +9,10 @@ - bunx (обычно скачивается вместе с bun) - Docker -**Если вы сделали это еще в самом корне проекта, то отдельно делеть этого не надо** -### Скачать зависимости: +> **_NOTE:_** Если установили зависимости в корне, то отдельно ставить не надо. + +##### Скачать зависимости: ```bash bun i @@ -44,3 +45,17 @@ bun run migrate ![img_2.png](images/img_2.png) #### API доступен по урлу http://localhost:3000/ + +# Возможные ошибки + +- Ругается на `@prisma/client` + +Необходимо в `apps/api` запустить команду +```bash +cd apps/api +npx prisma generate +``` +or +```bash +npx prisma generate +``` diff --git a/apps/api/__tests__/README.md b/apps/api/__tests__/README.md new file mode 100644 index 0000000..bfb84f7 --- /dev/null +++ b/apps/api/__tests__/README.md @@ -0,0 +1,18 @@ +# Тесты + +- Для тестов использовать ЧИСТУЮ ТЕСТОВУЮ БД +- Запускать БД как обычно в докере +- После запуска тестов надо удалить БД, иначе след. запуск тестов может упасть из-за повторяющихся данных + +### Как очистить БД + +#### Запуск studio +```bash +cd apps/api +npx prisma studio +``` + +![img.png](../images/run-studio.png) + +#### Удаление +![img.png](../images/remove-data-from-db.png) diff --git a/apps/api/__tests__/i.test.ts b/apps/api/__tests__/i.test.ts new file mode 100644 index 0000000..f1a31d8 --- /dev/null +++ b/apps/api/__tests__/i.test.ts @@ -0,0 +1,5 @@ +import { expect, test } from 'bun:test' + +test('2 + 2', () => { + expect(2 + 2).toBe(4) +}) diff --git a/apps/api/__tests__/services/user.test.ts b/apps/api/__tests__/services/user.test.ts new file mode 100644 index 0000000..bcd92ab --- /dev/null +++ b/apps/api/__tests__/services/user.test.ts @@ -0,0 +1,48 @@ +import { afterAll, describe, expect, it } from 'bun:test' +import { PrismaClient } from '@prisma/client' +import { getAllUsers, getUserById } from '@services' +import { getRandomID } from '@utils' + +const testDb = new PrismaClient() + +describe('userService', () => { + afterAll(async () => { + await testDb.$disconnect() + }) + + it('getAllUsers should return an array of users', async () => { + await testDb.user.createMany({ + data: [ + { + id: getRandomID(), + name: 'User 1', + email: 'testuser1@example.com' + }, + { + id: getRandomID(), + name: 'User 2', + email: 'testuser2@example.com' + } + ], + skipDuplicates: true + }) + + const users = await getAllUsers() + expect(users).toHaveLength(2) + expect(users[0].name).toBe('User 1') + expect(users[1].name).toBe('User 2') + }) + + it('getUserById should return a user by ID', async () => { + const id = getRandomID() + + await testDb.user.create({ + data: { id: id, name: 'Test User', email: 'testuser3@example.com' } + }) + + const user = await getUserById(id) + expect(user).not.toBeNull() + expect(user?.name).toBe('Test User') + }) + +}) diff --git a/apps/api/images/remove-data-from-db.png b/apps/api/images/remove-data-from-db.png new file mode 100644 index 0000000..c6b444a Binary files /dev/null and b/apps/api/images/remove-data-from-db.png differ diff --git a/apps/api/images/run-studio.png b/apps/api/images/run-studio.png new file mode 100644 index 0000000..18f284b Binary files /dev/null and b/apps/api/images/run-studio.png differ diff --git a/apps/api/package.json b/apps/api/package.json index 5a6c9ed..be377f0 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -9,10 +9,12 @@ "lint": "biome lint . --apply", "format": "biome format . --write", "build": "bun build ./src/index.ts --outdir dist --minify --target bun --splitting", - "build:types": "tsc --noEmit" + "build:types": "tsc --noEmit", + "tests": "bun test --coverage" }, "dependencies": { "@elysiajs/swagger": "^0.7.4", + "@prisma/client": "5.7.0", "elysia": "latest", "postgres": "^3.4.3" }, diff --git a/apps/api/src/handlers/README.md b/apps/api/src/handlers/README.md new file mode 100644 index 0000000..3a18c21 --- /dev/null +++ b/apps/api/src/handlers/README.md @@ -0,0 +1,37 @@ +# Хендлеры (контроллеры) + +Хендлеры отвечают за обработку запросов от клиента и взаимодействие с сервисами для получения необходимых данных. + +Они управляют потоком выполнения и возвращают ответы клиенту. Пример: + +```ts +// handlers/userHandler.ts +fastify.get('/users/:id', async (request, reply) => { + const userId = request.params.id + const user = await userService.getUserById(userId) + + if (!user) { + reply.code(404).send({ error: 'User not found' }) + } + + reply.send(user) +}) +``` + +### Памятка + +##### Что должно быть: + +- Обработка HTTP-запросов и формирование HTTP-ответов: Контроллеры отвечают за обработку HTTP-запросов, извлечение необходимых данных, вызов соответствующих сервисов и формирование HTTP-ответов для клиента. + +- Маршрутизация запросов: Контроллеры определяют, какие сервисы должны быть вызваны в ответ на различные HTTP-запросы. Они выполняют маршрутизацию запросов. + +- Валидация входных данных: Контроллеры могут осуществлять валидацию входных данных, чтобы обеспечить корректное выполнение запросов и предотвратить ошибки. + +##### Чего быть не должно: + +- Бизнес-логика: Контроллеры не должны содержать сложную бизнес-логику. + +- Прямое взаимодействие с базой данных: Контроллеры не должны напрямую взаимодействовать с базой данных. + +- Смешивание ответственностей: Контроллеры не должны заниматься деталями представления или другими аспектами, не связанными с обработкой HTTP-запросов. diff --git a/apps/api/src/services/README.md b/apps/api/src/services/README.md new file mode 100644 index 0000000..3feba4d --- /dev/null +++ b/apps/api/src/services/README.md @@ -0,0 +1,37 @@ +# Сервисы + +Сервисы отвечают за бизнес-логику и выполнение операций приложения. + +Они служат абстракцией для выполнения конкретных задач, таких как взаимодействие с базой данных, обработка данных и другие сложные операции. Ниже приведен пример простого сервиса с использованием Fastify и PostgreSQL: + +```ts +// services/userService.ts +export const userService = { + getAllUsers: async () => { + const client = await pool.connect() + try { + const result = await client.query('SELECT * FROM users') + return result.rows + } finally { + client.release() + } + }, +} +``` + +### Памятка + +##### Что должно быть: + +- Бизнес-логика: Сервисы должны содержать бизнес-логику приложения. Это могут быть функции для обработки данных, взаимодействия с базой данных, выполнения сложных операций и тд. + +- Абстракция от инфраструктуры: Сервисы должны предоставлять абстракцию от деталей инфраструктуры, таких как база данных или сторонние API. + +- Модульность: Сервисы должны быть модульными и выполнять конкретные задачи. Их легко переиспользовать в разных частях приложения. + +- Тестирование: Сервисы должны быть легко тестируемыми. Использование зависимостей и внедрение зависимостей помогают создать тестируемый код. + +##### Чего быть не должно: +- Прямое взаимодействие с HTTP-запросами: Сервисы не должны напрямую обрабатывать HTTP-запросы или отдавать HTTP-ответы. Эта ответственность лежит на контроллерах (хендлерах). + +- Смешивание ответственностей: Сервисы не должны содержать код, который не относится к их бизнес-логике. Например, код обработки HTTP-запросов или взаимодействия с пользовательским интерфейсом. diff --git a/apps/api/src/services/index.ts b/apps/api/src/services/index.ts new file mode 100644 index 0000000..c812d82 --- /dev/null +++ b/apps/api/src/services/index.ts @@ -0,0 +1 @@ +export * from './userService' diff --git a/apps/api/src/services/userService.ts b/apps/api/src/services/userService.ts index ecc2247..9e72620 100644 --- a/apps/api/src/services/userService.ts +++ b/apps/api/src/services/userService.ts @@ -1,4 +1,4 @@ -import { PrismaClient } from 'prisma/prisma-client/scripts/default-index' +import { PrismaClient } from '@prisma/client' import { User } from 'shared' const db = new PrismaClient() diff --git a/apps/api/src/utils/getRandomNumber.ts b/apps/api/src/utils/getRandomNumber.ts new file mode 100644 index 0000000..00ffc18 --- /dev/null +++ b/apps/api/src/utils/getRandomNumber.ts @@ -0,0 +1,7 @@ +export const getRandomID = () => { + let array = new Uint32Array(1) + crypto.getRandomValues(array) + + const maxIntValue = 2147483647 + return array[0] % maxIntValue +} diff --git a/apps/api/src/utils/index.ts b/apps/api/src/utils/index.ts index 9d30fd5..1de1acb 100644 --- a/apps/api/src/utils/index.ts +++ b/apps/api/src/utils/index.ts @@ -1 +1,2 @@ export * from './handleErrors' +export * from './getRandomNumber' diff --git a/apps/api/tsconfig.json b/apps/api/tsconfig.json index 40d80e6..3c5f6f1 100644 --- a/apps/api/tsconfig.json +++ b/apps/api/tsconfig.json @@ -6,9 +6,10 @@ "types": ["bun-types"], "paths": { "@utils": ["src/utils"], - "@handlers": ["src/handlers"] + "@handlers": ["src/handlers"], + "@services": ["src/services"] } }, "extends": "../../tsconfig.base.json", - "include": ["src"] + "include": ["src", "__tests__"] } diff --git a/apps/shared/README.md b/apps/shared/README.md new file mode 100644 index 0000000..5f75cb3 --- /dev/null +++ b/apps/shared/README.md @@ -0,0 +1,4 @@ +[![Build Web](https://github.com/Diary-SPO/diary-admin/actions/workflows/build-web.yml/badge.svg)](https://github.com/Diary-SPO/diary-admin/actions/workflows/build-shared.yml) +# Shared + +Тут все типы и утилиты, которые используются и на сервере (API) и на клиенте (Web) diff --git a/apps/web/README.md b/apps/web/README.md index d335595..f6879b7 100644 --- a/apps/web/README.md +++ b/apps/web/README.md @@ -3,7 +3,9 @@ ### Запуск проекта -### Установка зависимостей +> **_NOTE:_** Если установили зависимости в корне, то отдельно ставить не надо. + +##### Установка зависимостей ```bash bun i diff --git a/bun.lockb b/bun.lockb index 8ba70fe..f3e129b 100644 Binary files a/bun.lockb and b/bun.lockb differ