This project is a .NET 8 ASP.NET Core Web API backed by PostgreSQL.
It supports:
- profile creation from external APIs
- persistent profile storage
- advanced filtering
- sorting
- pagination
- rule-based natural language search
- idempotent seeding of 2026 profiles
The Stage 2 query engine is built on a PostgreSQL profiles table with these persisted fields:
idnamegendergender_probabilityageage_groupcountry_idcountry_namecountry_probabilitycreated_at
Genderize-> gender and probabilityAgify-> ageNationalize-> top predicted country
The repository includes data/seed_profiles.json.
- The file contains
2026profiles - Startup seeding is enabled by default
- Re-running the application does not create duplicate seeded records
The seed path is configured through:
"SeedData": {
"Enabled": true,
"FilePath": "data/seed_profiles.json"
}Creates a profile from the external APIs. If the name already exists, the existing record is returned with:
{
"status": "success",
"message": "Profile already exists",
"data": { }
}Returns a single stored profile.
Deletes a stored profile and returns 204 No Content.
Supports combined filters, sorting, and pagination.
Supported filters:
genderage_groupcountry_idmin_agemax_agemin_gender_probabilitymin_country_probability
Sorting:
sort_by=age|created_at|gender_probabilityorder=asc|desc
Pagination:
pagedefault1limitdefault10limitmax50
Response shape:
{
"status": "success",
"page": 1,
"limit": 10,
"total": 2026,
"data": []
}Rule-based natural language search.
Query parameter:
q
Supported examples:
young malesfemales above 30people from angolaadult males from kenyamale and female teenagers above 17
Rules implemented:
young=>min_age=16andmax_age=24male and femalemeans no gender filter is applied- country names are mapped to ISO codes using a rule-based lookup
- queries that cannot be interpreted return:
{
"status": "error",
"message": "Unable to interpret query"
}All errors use:
{
"status": "error",
"message": "<error message>"
}Status behavior:
400for missing or empty parameters422for invalid parameter types404for missing profiles502for invalid upstream API responses500for unexpected server failures
Query validation failures return:
{
"status": "error",
"message": "Invalid query parameters"
}Invalid upstream responses return:
{
"status": "error",
"message": "Genderize returned an invalid response"
}or:
{
"status": "error",
"message": "Agify returned an invalid response"
}or:
{
"status": "error",
"message": "Nationalize returned an invalid response"
}The API allows:
Access-Control-Allow-Origin: *
Default connection string:
Host=localhost;Port=5432;Database=genderize_stage2_db;Username=postgres;Password=postgres
Run:
dotnet restore Genderize.sln
dotnet build Genderize.sln
dotnet run --project src/Genderize.Api/Genderize.Api.csprojDevelopment URL:
http://localhost:5073
Swagger:
http://localhost:5073/swagger
docker compose up --buildThat starts:
- PostgreSQL on
localhost:5432 - API on
http://localhost:8080
Swagger:
http://localhost:8080/swagger
Create a profile:
curl -X POST "http://localhost:5073/api/profiles" \
-H "Content-Type: application/json" \
-d '{"name":"ella"}'Filter and paginate:
curl "http://localhost:5073/api/profiles?gender=male&country_id=NG&min_age=25&page=1&limit=10"Sort by age descending:
curl "http://localhost:5073/api/profiles?sort_by=age&order=desc"Natural language search:
curl "http://localhost:5073/api/profiles/search?q=young%20males%20from%20nigeria&page=1&limit=10"- PostgreSQL persistence uses EF Core with Npgsql
- The schema is created automatically on startup with
EnsureCreated - Seed import runs at startup after schema creation
- Filters are combined with logical
AND - Sorting and pagination are executed at the database-query level
- The Stage 0
GET /api/classifyendpoint is still available