Locations
Introduction
The Locations module provides read-only access to Indonesian province and city data. Data is sourced from pipe-delimited seed files on disk, not from the database. This feature is used by the frontend for organization address selection and asset location assignment. Business logic is encapsulated in LocationService.
Controller
File: API/Controllers/Locations/LocationsController.cs
Route: api/locations
Inherits: ControllerBase
Auth: None (public endpoints)
Delegates to: ILocationService
Endpoints
| Endpoint | Method | Auth | Description |
|---|---|---|---|
api/locations/provinces | GET | Public | List all provinces ordered by name |
api/locations/provinces/{provinceId}/cities | GET | Public | List cities in a specific province |
api/locations/cities | GET | Public | Search all cities with optional filters |
Query Parameters (GET cities)
| Parameter | Type | Required | Description |
|---|---|---|---|
search | string | No | Filter by city name (case-insensitive contains) |
provinceId | int | No | Filter by province ID |
Response Format
All endpoints return the standard ApiEnvelope response:
{
"success": true,
"data": {
"items": [...],
"count": 42
},
"errors": []
}
Service
File: Infrastructure/Services/LocationService.cs
Interface: ILocationService
Lifetime: Scoped
Data Source
Location data is loaded from pipe-delimited text files in the Seed/ directory:
| File | Size | Content |
|---|---|---|
province.txt | ~1 KB | Province data (34 provinces) |
city.txt | ~14 KB | City/regency data |
Additional seed files exist (country.txt, district.txt, subdistricts.txt) but are not currently used by the API.
File Format
province.txt: id|unknown|code|name|abbreviation
city.txt: id|province_id|type_code|unknown|code|name|unknown
type_code:1= Kabupaten (regency), other = Kota (city)
Service Methods
| Method | Returns | Description |
|---|---|---|
GetProvinces() | IReadOnlyList<ProvinceDto> | All provinces, ordered by name |
GetCitiesByProvince(int) | IReadOnlyList<CityDto> | Cities in a province, ordered by name |
GetAllCities(string?, int?) | IReadOnlyList<CityDto> | Filterable city search, ordered by name |
DTOs
File: Application/DTOs/LocationDtos.cs
public sealed record ProvinceDto(int Id, string Code, string Name, string Abbreviation);
public sealed record CityDto(int Id, int ProvinceId, string Type, string Code, string Name, string FullName);
CityDto.Type: Either"Kabupaten"or"Kota"CityDto.FullName: Prefixed with type, e.g."Kabupaten Bandung","Kota Bandung"
Design Notes
- No database dependency — Location data is static and read from disk files, keeping the database focused on dynamic entities.
- Synchronous reads — File I/O is performed synchrounously since the data files are small
- No caching — Files are re-read on every request. Given the small file sizes and typical call frequency, this is acceptable but could be optimized with an in-memory cache.
- No authentication — Location endpoints are public since they contain only reference data.
Future Improvements
Open
- Add in-memory caching to avoid re-reading seed files on every request.
- Support district and subdistrict lookups using existing seed data.