=============== LIBRARY RULES =============== From library maintainers: - Treat this repository as a production-oriented Go backend template for RESTful APIs. Follow the existing project structure and conventions when generating or modifying code. Preserve the separation between handlers, services, repositories, and database la ### Install Go Dependencies Source: https://github.com/gasyok/example/blob/main/README.md Standard command to download and install the required Go modules defined in the project's go.mod file. ```bash go mod download ``` -------------------------------- ### Initialize and Run Go Microservice with Graceful Shutdown Source: https://context7.com/gasyok/example/llms.txt This snippet demonstrates the main entry point for a Go application, including logger setup, configuration loading, database pool initialization, and HTTP server lifecycle management using signal notification for graceful shutdown. ```go package main import ( "context" "log/slog" "net/http" "os" "os/signal" "syscall" "time" "example/internal/config" "example/internal/controller" "example/pkg/pgxpool" userCtrl "example/internal/controller/user" txmanager "example/internal/infra/postgres/tx-manager" userRepo "example/internal/infra/postgres/user" userSvc "example/internal/service/user" ) func main() { // Инициализация логгера log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ Level: slog.LevelInfo, })) // Загрузка конфигурации cfg, _ := config.GetConfig() // Контекст с поддержкой graceful shutdown ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() // Подключение к БД pool, _ := pgxpool.NewPoolFromDSN(ctx, cfg.DatabaseURL) defer pool.Close() // Инициализация слоёв приложения userRepository := userRepo.New(pool) txm := txmanager.NewRepository(pool) userService := userSvc.New(userRepository, txm) userHandler := userCtrl.New(userService, log) // Настройка роутера и запуск сервера ctrl := controller.New(userHandler, log) router := ctrl.Setup() server := &http.Server{ Addr: ":" + cfg.HttpPort, Handler: router, ReadTimeout: 30 * time.Second, WriteTimeout: 30 * time.Second, } go server.ListenAndServe() <-ctx.Done() server.Shutdown(context.Background()) } ``` -------------------------------- ### GET /api/v1/users/ Source: https://context7.com/gasyok/example/llms.txt Retrieves a list of users with support for pagination via `limit` and `offset` query parameters. Results are sorted by ID in ascending order. ```APIDOC ## GET /api/v1/users/ ### Description Retrieves a list of users with support for pagination via `limit` and `offset` query parameters. Results are sorted by ID in ascending order. ### Method GET ### Endpoint /api/v1/users/ ### Query Parameters - **limit** (int) - Optional - The maximum number of users to return. - **offset** (int) - Optional - The number of users to skip before starting to collect the result set. ### Request Example ```bash curl -X GET "http://localhost:8080/api/v1/users/?limit=10&offset=0" \ -H "Content-Type: application/json" ``` ### Response #### Success Response (200 OK) - **id** (int) - The unique identifier of the user. - **name** (string) - The name of the user. - **email** (string) - The email address of the user. - **created_at** (string) - The timestamp when the user was created (ISO 8601 format). - **updated_at** (string) - The timestamp when the user was last updated (ISO 8601 format). #### Response Example ```json [ { "id": 1, "name": "Иван Петров", "email": "ivan@example.com", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" }, { "id": 2, "name": "Мария Сидорова", "email": "maria@example.com", "created_at": "2024-01-16T14:20:00Z", "updated_at": "2024-01-16T14:20:00Z" } ] ``` ``` -------------------------------- ### GET /api/v1/users/{id} Source: https://context7.com/gasyok/example/llms.txt Retrieves a specific user's data by their unique identifier. Returns a 404 error if the user is not found. ```APIDOC ## GET /api/v1/users/{id} ### Description Retrieves a specific user's data by their unique identifier. Returns a 404 error if the user is not found. ### Method GET ### Endpoint /api/v1/users/{id} ### Path Parameters - **id** (int) - Required - The unique identifier of the user. ### Response #### Success Response (200 OK) - **id** (int) - The unique identifier of the user. - **name** (string) - The name of the user. - **email** (string) - The email address of the user. - **created_at** (string) - The timestamp when the user was created (ISO 8601 format). - **updated_at** (string) - The timestamp when the user was last updated (ISO 8601 format). #### Error Response (404 Not Found) - **error** (string) - Description of the error. ### Request Example ```bash curl -X GET "http://localhost:8080/api/v1/users/1" \ -H "Content-Type: application/json" ``` ### Response Example #### Success ```json { "id": 1, "name": "Иван Петров", "email": "ivan@example.com", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" } ``` #### Not Found ```json {"error": "not found"} ``` ``` -------------------------------- ### Connect to PostgreSQL using pgxpool Source: https://context7.com/gasyok/example/llms.txt Demonstrates how to initialize a PostgreSQL connection pool using either a DSN string or a configuration structure. Requires the pgxpool package and a valid database connection string or credentials. ```go package main import ( "context" "log" "example/pkg/pgxpool" ) func main() { ctx := context.Background() // Вариант 1: Подключение через DSN pool, err := pgxpool.NewPoolFromDSN(ctx, "postgres://user:password@localhost:5432/mydb?sslmode=disable") if err != nil { log.Fatal(err) } defer pool.Close() // Вариант 2: Подключение через конфигурацию pool2, err := pgxpool.NewPool(ctx, pgxpool.Config{ Host: "localhost", Port: "5432", UserName: "user", Password: "password", DBName: "mydb", }) if err != nil { log.Fatal(err) } defer pool2.Close() } ``` -------------------------------- ### Configure Application Environment Variables Source: https://context7.com/gasyok/example/llms.txt Sets up the necessary environment variables for the Go application, including port configuration and PostgreSQL connection strings. Supports both direct DATABASE_URL and individual database parameter definitions. ```bash export APP_CONFIG_PORT=8080 export LOG_LEVEL=info # Option 1: Full DATABASE_URL export DATABASE_URL="postgres://user:password@localhost:5432/mydb?sslmode=disable" # Option 2: Separate PostgreSQL parameters export APP_CONFIG_POSTGRES_HOST=localhost export APP_CONFIG_POSTGRES_PORT=5432 export APP_CONFIG_POSTGRES_USERNAME=user export APP_CONFIG_POSTGRES_PASSWORD=password export APP_CONFIG_POSTGRES_DBNAME=mydb ``` -------------------------------- ### Implement User Service Layer Source: https://context7.com/gasyok/example/llms.txt Demonstrates the service layer pattern for user management, encapsulating business logic and utilizing repository and transaction manager interfaces for testability. ```go package main import ( "context" "log" userSvc "example/internal/service/user" userRepo "example/internal/infra/postgres/user" txmanager "example/internal/infra/postgres/tx-manager" ) func main() { repository := userRepo.New(pool) txm := txmanager.NewRepository(pool) service := userSvc.New(repository, txm) ctx := context.Background() user, err := service.Create(ctx, userSvc.CreateInput{ Name: "Тестовый Пользователь", Email: "test@example.com", }) if err != nil { log.Fatal(err) } foundUser, err := service.GetByID(ctx, user.ID) updatedUser, err := service.Update(ctx, user.ID, userSvc.UpdateInput{ Name: "Обновлённое Имя", Email: "updated@example.com", }) users, err := service.List(ctx, 10, 0) upsertedUser, err := service.Upsert(ctx, userSvc.CreateInput{ Name: "Upsert Пользователь", Email: "upsert@example.com", }) err = service.Delete(ctx, user.ID) } ``` -------------------------------- ### POST /api/v1/users/ Source: https://context7.com/gasyok/example/llms.txt Creates a new user with the provided name and email. Returns the newly created user object with an assigned ID and timestamps. ```APIDOC ## POST /api/v1/users/ ### Description Creates a new user with the provided name and email. Returns the newly created user object with an assigned ID and timestamps. ### Method POST ### Endpoint /api/v1/users/ ### Request Body - **name** (string) - Required - The name of the user. - **email** (string) - Required - The email address of the user. ### Request Example ```bash curl -X POST "http://localhost:8080/api/v1/users/" \ -H "Content-Type: application/json" \ -d '{ "name": "Алексей Козлов", "email": "alexey@example.com" }' ``` ### Response #### Success Response (201 Created) - **id** (int) - The unique identifier of the newly created user. - **name** (string) - The name of the user. - **email** (string) - The email address of the user. - **created_at** (string) - The timestamp when the user was created (ISO 8601 format). - **updated_at** (string) - The timestamp when the user was last updated (ISO 8601 format). #### Error Response (400 Bad Request) - **error** (string) - Description of the validation error. ### Response Example #### Success ```json { "id": 3, "name": "Алексей Козлов", "email": "alexey@example.com", "created_at": "2024-01-17T09:15:00Z", "updated_at": "2024-01-17T09:15:00Z" } ``` #### Validation Error ```json {"error": "invalid input: invalid body"} ``` ``` -------------------------------- ### Handle Errors and HTTP Responses Source: https://context7.com/gasyok/example/llms.txt Illustrates how to map domain-specific errors to standard HTTP status codes using the httputil utility to maintain consistent API responses. ```go package main import ( "errors" "net/http" "example/internal/domain" "example/internal/utils/httputil" ) func exampleHandler(w http.ResponseWriter, r *http.Request) { httputil.HandleFlow(w, logger, func() error { user, err := service.GetByID(r.Context(), id) if err != nil { return err } if user.Email == "" { return fmt.Errorf("%w: email is required", domain.ErrInvalidInput) } httputil.JSON(w, http.StatusOK, user) return nil }) } ``` -------------------------------- ### Application Configuration Source: https://context7.com/gasyok/example/llms.txt Details on how to configure the application using environment variables, including database connection parameters. ```APIDOC ## Application Configuration Configuration is loaded from environment variables using the `envconfig` library. Supports connection via `DATABASE_URL` or separate PostgreSQL parameters. ### Environment Variables - `APP_CONFIG_PORT` (int) - The port the application will listen on. - `LOG_LEVEL` (string) - The logging level (e.g., 'info', 'debug'). #### Database Connection (Choose one option) **Option 1: `DATABASE_URL`** - `DATABASE_URL` (string) - The full PostgreSQL connection URL. Example: `postgres://user:password@localhost:5432/mydb?sslmode=disable` **Option 2: Separate PostgreSQL Parameters** - `APP_CONFIG_POSTGRES_HOST` (string) - PostgreSQL host. - `APP_CONFIG_POSTGRES_PORT` (int) - PostgreSQL port. - `APP_CONFIG_POSTGRES_USERNAME` (string) - PostgreSQL username. - `APP_CONFIG_POSTGRES_PASSWORD` (string) - PostgreSQL password. - `APP_CONFIG_POSTGRES_DBNAME` (string) - PostgreSQL database name. ### Example Usage (Bash) ```bash export APP_CONFIG_PORT=8080 export LOG_LEVEL=info export DATABASE_URL="postgres://user:password@localhost:5432/mydb?sslmode=disable" ``` OR ```bash export APP_CONFIG_PORT=8080 export LOG_LEVEL=info export APP_CONFIG_POSTGRES_HOST=localhost export APP_CONFIG_POSTGRES_PORT=5432 export APP_CONFIG_POSTGRES_USERNAME=user export APP_CONFIG_POSTGRES_PASSWORD=password export APP_CONFIG_POSTGRES_DBNAME=mydb ``` ``` -------------------------------- ### Implement Transactional Workflows in Go Source: https://github.com/gasyok/example/blob/main/README.md Demonstrates the use of the transaction manager to wrap multi-step business operations within a single database transaction. This ensures data consistency across repository operations by utilizing a shared context. ```go err := txm.Do(ctx, func(ctx context.Context) error { // use repositories with the transactional context return nil }) ``` -------------------------------- ### Manage Database Transactions Source: https://context7.com/gasyok/example/llms.txt Shows how to use a transaction manager to execute atomic operations. Supports default settings and custom isolation levels for complex database interactions. ```go package main import ( "context" "fmt" "example/internal/domain" txmanager "example/internal/infra/postgres/tx-manager" ) func main() { // Инициализация менеджера транзакций txm := txmanager.NewRepository(pool) // Простая транзакция с настройками по умолчанию err := txm.Do(ctx, func(ctx context.Context) error { if err := repo.Create(ctx, user1); err != nil { return err } if err := repo.Create(ctx, user2); err != nil { return err } return nil }) // Транзакция с настройками изоляции err = txm.DoWithOptions(ctx, domain.TxOptions{ IsolationLevel: domain.IsolationSerializable, ReadOnly: false, }, func(ctx context.Context) error { return repo.Update(ctx, user) }) } ``` -------------------------------- ### Perform User Management API Operations Source: https://context7.com/gasyok/example/llms.txt A collection of cURL commands to interact with the User Management API. These snippets cover listing, retrieving, creating, updating, upserting, and deleting user records. ```bash # List users with pagination curl -X GET "http://localhost:8080/api/v1/users/" -H "Content-Type: application/json" -d '{"limit": 10, "offset": 0}' # Get user by ID curl -X GET "http://localhost:8080/api/v1/users/1" -H "Content-Type: application/json" # Create a new user curl -X POST "http://localhost:8080/api/v1/users/" -H "Content-Type: application/json" -d '{"name": "Алексей Козлов", "email": "alexey@example.com"}' # Update an existing user curl -X PUT "http://localhost:8080/api/v1/users/1" -H "Content-Type: application/json" -d '{"name": "Иван Иванович Петров", "email": "ivan.petrov@example.com"}' # Upsert user by email curl -X POST "http://localhost:8080/api/v1/users/upsert" -H "Content-Type: application/json" -d '{"name": "Новое Имя", "email": "existing@example.com"}' # Delete a user curl -X DELETE "http://localhost:8080/api/v1/users/1" -H "Content-Type: application/json" ``` -------------------------------- ### POST /api/v1/users/upsert Source: https://context7.com/gasyok/example/llms.txt Creates a new user or updates an existing one based on their email. This operation is performed within a transaction for atomicity. ```APIDOC ## POST /api/v1/users/upsert ### Description Creates a new user or updates an existing one based on their email. This operation is performed within a transaction for atomicity. ### Method POST ### Endpoint /api/v1/users/upsert ### Request Body - **name** (string) - Required - The name of the user. - **email** (string) - Required - The email address of the user, used for matching existing users. ### Request Example ```bash curl -X POST "http://localhost:8080/api/v1/users/upsert" \ -H "Content-Type: application/json" \ -d '{ "name": "Новое Имя", "email": "existing@example.com" }' ``` ### Response #### Success Response (200 OK) - **id** (int) - The unique identifier of the user (either newly created or updated). - **name** (string) - The name of the user. - **email** (string) - The email address of the user. - **created_at** (string) - The timestamp when the user was created (ISO 8601 format). - **updated_at** (string) - The timestamp when the user was last updated (ISO 8601 format). ### Response Example ```json { "id": 5, "name": "Новое Имя", "email": "existing@example.com", "created_at": "2024-01-10T08:00:00Z", "updated_at": "2024-01-17T12:30:00Z" } ``` ``` -------------------------------- ### PUT /api/v1/users/{id} Source: https://context7.com/gasyok/example/llms.txt Updates the data of an existing user identified by their ID. Checks for user existence before performing the update. ```APIDOC ## PUT /api/v1/users/{id} ### Description Updates the data of an existing user identified by their ID. Checks for user existence before performing the update. ### Method PUT ### Endpoint /api/v1/users/{id} ### Path Parameters - **id** (int) - Required - The unique identifier of the user to update. ### Request Body - **name** (string) - Optional - The updated name of the user. - **email** (string) - Optional - The updated email address of the user. ### Request Example ```bash curl -X PUT "http://localhost:8080/api/v1/users/1" \ -H "Content-Type: application/json" \ -d '{ "name": "Иван Иванович Петров", "email": "ivan.petrov@example.com" }' ``` ### Response #### Success Response (200 OK) - **id** (int) - The unique identifier of the updated user. - **name** (string) - The updated name of the user. - **email** (string) - The updated email address of the user. - **created_at** (string) - The timestamp when the user was created (ISO 8601 format). - **updated_at** (string) - The timestamp when the user was last updated (ISO 8601 format). #### Error Response (404 Not Found) - **error** (string) - Description of the error. ### Response Example #### Success ```json { "id": 1, "name": "Иван Иванович Петров", "email": "ivan.petrov@example.com", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-17T11:45:00Z" } ``` #### Not Found ```json {"error": "not found"} ``` ``` -------------------------------- ### DELETE /api/v1/users/{id} Source: https://context7.com/gasyok/example/llms.txt Deletes a user by their ID. The operation includes a preliminary check for the user's existence and is performed within a transaction. ```APIDOC ## DELETE /api/v1/users/{id} ### Description Deletes a user by their ID. The operation includes a preliminary check for the user's existence and is performed within a transaction. ### Method DELETE ### Endpoint /api/v1/users/{id} ### Path Parameters - **id** (int) - Required - The unique identifier of the user to delete. ### Request Example ```bash curl -X DELETE "http://localhost:8080/api/v1/users/1" \ -H "Content-Type: application/json" ``` ### Response #### Success Response (204 No Content) Indicates successful deletion. No response body is returned. #### Error Response (404 Not Found) - **error** (string) - Description of the error if the user is not found. ### Response Example #### Not Found ```json {"error": "not found"} ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.