This repository contains a solution to the backend developer challenge. The project implements a JSON API to manage a collection of Farms and their associated Crop Productions. The solution demonstrates backend development best practices, including modular code structure, environment configuration, and optional stretch goal implementations.
- Create a Farm with nested Crop Productions.
- Delete a Farm by its ID.
- List all Farms with pagination and filtering.
- Fiber: A fast web framework for building APIs.
- Fx: A dependency injection framework to manage services and their lifecycle.
- Gorm: ORM for interacting with the PostgreSQL database.
- go-playground/validator/v10: A popular validation library for Go that simplifies struct validation with customizable tags and built-in rules.
- Zap: A popular logging library.
- PostgreSQL is used for data storage and management of farm and crop records.
- Docker is used to containerize both the application and database, ensuring consistency across environments.
- testcontainers-go: Spins up containerized dependencies for integration tests.
- go-sqlmock: Mocks database interactions for unit testing.
- testify: Provides testing utilities like assertions and test suites.
├── Dockerfile
├── README.md
├── cmd
│ └── main.go
├── docker-compose.dev.yml
├── docker-compose.local.yml
├── docker-compose.yml
├── docs
│ ├── docs.go
│ ├── swagger.json
│ └── swagger.yaml
├── go.mod
├── go.sum
├── integration_tests
│ └── farm_repository_integration_test.go
├── internal
│ └── app
│ ├── domain
│ │ ├── crop_production.go
│ │ ├── farm.go
│ │ ├── farm_repository.go
│ │ └── usecases
│ │ ├── create_farm.go
│ │ ├── create_farm_test.go
│ │ ├── delete_farm.go
│ │ ├── list_farms.go
│ │ └── module.go
│ ├── dto
│ │ └── create_farm_dto.go
│ ├── infra
│ │ ├── config
│ │ │ ├── config.go
│ │ │ └── module.go
│ │ ├── database
│ │ │ ├── database.go
│ │ │ ├── entities
│ │ │ │ ├── crop_production_entity.go
│ │ │ │ └── farm_entity.go
│ │ │ ├── mappers
│ │ │ │ ├── mappers.go
│ │ │ │ └── mappers_test.go
│ │ │ ├── module.go
│ │ │ └── repositories
│ │ │ ├── farm_repository.go
│ │ │ ├── farm_repository_test.go
│ │ │ └── module.go
│ │ └── httpapi
│ │ ├── controllers
│ │ │ ├── farm_controller.go
│ │ │ ├── farm_controller_test.go
│ │ │ └── module.go
│ │ ├── middlewares
│ │ │ └── request_logging_middleware.go
│ │ ├── module.go
│ │ ├── routers
│ │ │ ├── farm.go
│ │ │ ├── module.go
│ │ │ └── router.go
│ │ └── server.go
│ ├── models
│ │ └── models.go
│ └── shared
│ ├── errors
│ │ └── errors.go
│ ├── logger
│ │ ├── logger.go
│ │ └── module.go
│ ├── utils
│ └── validation
│ └── validation.go
└── testutils
├── fakes.go
├── helpers.go
└── matchers.go
Contains the entry point of the application. The main.go
file initializes and runs the API, pulling together configurations, dependencies, and modules.
Contains the autogenerated Swagger api docs and configuration.
Contains the test container integration tests.
Houses the core logic, domain models, infrastructure code, and shared utilities for the application. It is structured to follow a modular architecture, separating concerns between domain, infrastructure, and HTTP API layers.
Defines the domain layer of the application, including:
- Business Logic (
usecases
): Implements core use cases likecreate_farm
andlist_farms
. - Domain Entities: Represents business concepts (e.g.,
farm.go
,crop_production.go
). - Interfaces: Includes repository interfaces (e.g.,
farm_repository.go
).
Implements infrastructure concerns such as configuration, database interactions, and HTTP APIs. It bridges the domain layer and external systems.
config
: Handles application configuration (e.g., environment variables and settings).database
:- Manages database connections and schema definitions (entities).
- Includes mappers for converting between database models and domain models.
- Contains repository implementations.
httpapi
:- Middlewares: Common middlewares used across multiple endpoints (e.g.
request_logging_middleware.go
). - Controllers: API route handlers (e.g.,
farm_controller.go
). - Routers: Defines API routes and sets up routing logic.
- Server: Handles HTTP server setup.
- Middlewares: Common middlewares used across multiple endpoints (e.g.
Defines Data Transfer Objects (DTOs) used for API requests and responses. These objects provide a clear contract for data structures exchanged between the API and its consumers.
Contains shared data structures and models used across the application. These models represent business objects and are independent of infrastructure concerns.
Includes shared utilities and components used across the application:
errors
: Custom error types and error-handling logic.utils
: General-purpose utility functions.validation
: Input validation logic for various application components.logger
: production ready logger implementation built on top of Zap.
Provides helper functions, fake objects, and custom matchers to facilitate writing and organizing tests across the application.
Defines the instructions to build a Docker image for the application.
Contains configurations for running the application in different environments (dev
, local
, etc.) using Docker Compose.
Provides an overview of the project, including setup instructions, usage examples, and other relevant details.
Manage dependencies and module requirements for the Go application.
The API documentation is available via Swagger. It is automatically generated based on the code annotations and can be accessed at the following endpoint:
- Swagger UI:
http://localhost:PORT/swagger/index.html
The API includes the following endpoints:
- URL:
/farms
- Method:
POST
- Payload:
{ "name": "test2", "land_area": 550.5, "unit_measure": "hectares", "address": "123 Farm Lane, Countryside", "crop_productions": [ { "crop_type": "COFFEE", "is_irrigated": true, "is_insured": false }, { "crop_type": "CORN", "is_irrigated": false, "is_insured": true } ] }
- Response: Returns the created farm object.
- URL:
/farms/{id}
- Method:
DELETE
- Response: Confirmation of deletion.
- URL:
/farms
- Method:
GET
- Query Parameters (optional):
crop_type
(filter by crop type)minimum_land_area
(filter farms with land area greater than or equal to this value)maximum_land_area
(filter farms with land area less than or equal to this value)page
(pagination page number)per_page
(number of records per page)
- Response:
{ "items": [ { "id": "264e0463-0d15-410b-9bc5-17e5e0741519", "name": "Sunny Farm", "land_area": 120.5, "unit_measure": "hectares", "address": "123 Farm Lane, Countryside", "created_at": "2024-12-09T22:07:44.357163-03:00", "updated_at": "2024-12-09T22:07:44.357163-03:00", "crop_productions": [ { "id": "05ef1eac-a763-4f1e-9556-1010d9f0c879", "farm_id": "264e0463-0d15-410b-9bc5-17e5e0741519", "crop_type": "CORN", "is_irrigated": false, "is_insured": true }, { "id": "bcf21d06-8fd6-4eea-b347-21f4d28fc7e1", "farm_id": "264e0463-0d15-410b-9bc5-17e5e0741519", "crop_type": "COFFEE", "is_irrigated": true, "is_insured": false } ] } ], "total_count": 4, "current_page": 1, "per_page": 1
}
- Go 1.23+
- Docker
-
Clone the repository:
git clone https://github.com/arthurgavazza/farm-api-challenge.git cd farm-api-challenge
-
Install dependencies:
go mod tidy
-
Set up the environment variables:
- Copy
.env.example
to.env
and configure the values.cp .env.example .env
- Copy
-
Choose a setup option:
Depending on your use case, follow one of the approaches below:
This option is ideal when you are actively developing and testing the Go application. It starts only the database container while you run the API locally, allowing for faster iterations without rebuilding the API container.
Steps:
- Start the local database container:
docker compose -f docker-compose.local.yml up --build -d
- Run the Go API locally:
go run cmd/main.go
- Access the API at
http://localhost:PORT
(default:http://localhost:8080
).
This option is suitable when you want to test changes with the API running inside a container. It builds the API image from your local source code and runs the entire stack (API and database).
Steps:
- Start the stack (API and database):
docker compose -f docker-compose.dev.yml up --build
- Access the API at
http://localhost:PORT
(default:http://localhost:8080
).
This option is best if you want to run the current stable version of the API using the prebuilt image from DockerHub. It doesn’t require building the API locally.
Steps:
- Start the stack (API and database):
docker compose up -d
- Access the API at
http://localhost:PORT
(default:http://localhost:8080
).
Option | When to Use |
---|---|
Option 1: Local | Actively developing and want faster feedback without rebuilding the API container. |
Option 2: Dev | Testing API changes within a container built from your local source code. |
Option 3: Prebuilt Image | Running the current stable version of the API without modifying the source code. |
Run the test suite with:
go test ./...
Thank you for reviewing this solution! Please feel free to reach out with any feedback or questions.