Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/locations_api"
PORT="8080"
PAGE_SIZE="10"
24 changes: 0 additions & 24 deletions .eslintrc.js

This file was deleted.

33 changes: 33 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
day: monday
time: '06:00'
timezone: Africa/Dar_es_Salaam
open-pull-requests-limit: 10
groups:
npm-minor-patch:
patterns:
- '*'
update-types:
- minor
- patch

- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
day: monday
time: '06:15'
timezone: Africa/Dar_es_Salaam
open-pull-requests-limit: 5
groups:
github-actions-minor-patch:
patterns:
- '*'
update-types:
- minor
- patch
64 changes: 64 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: CI

on:
pull_request:
push:
branches:
- main
- master

jobs:
verify:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version:
- '20.19.0'
- '22'
services:
postgres:
image: postgres:16
env:
POSTGRES_DB: locations_api
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
options: >-
--health-cmd="pg_isready -U postgres -d locations_api"
--health-interval=10s
--health-timeout=5s
--health-retries=5
ports:
- 5432:5432
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/locations_api
NODE_ENV: test
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.7.0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Lint, typecheck, and build
run: pnpm build:ci

- name: Run migrations
run: pnpm db:migrate

- name: Seed database
run: pnpm db:seed

- name: Run tests
run: pnpm test
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
/dist
/node_modules
/prisma/node_modules
/src/generated
/generated
/coverage

# Logs
logs
Expand Down
188 changes: 103 additions & 85 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,135 +1,153 @@
# Location Data API

A RESTful API for Tanzania location data including countries, regions, districts, wards, and places.
Compatibility-first REST API for Tanzania location data backed by PostgreSQL and Prisma ORM 7.

## Features
## What Changed

- Hierarchical location data with proper relationships
- RESTful API with clean structure
- Input validation and error handling
- Pagination and search support
- Prisma ORM 7 with a generated client in `src/generated/prisma`
- Dual API base paths: `/v1` is canonical and `/api` remains as a compatibility alias
- Reproducible Prisma migration + seed flow for local development and CI
- Request IDs, structured HTTP logs, cache headers, and safer full-text search
- Dependabot and GitHub Actions for ongoing dependency updates and verification

## Tech Stack
## Requirements

- Node.js / Express
- PostgreSQL
- Prisma ORM
- Jest & Supertest for testing
- Node.js `>=20.19.0`
- pnpm `10.7.0+`
- PostgreSQL `16+` recommended

## Getting Started
## Quick Start

### Prerequisites
1. Install dependencies.

- Node.js LTS
- [Tanzania Locations Database](https://github.com/HackEAC/tanzania-locations-db) running 🏃🏿‍♂️🏃🏿‍♀️
- npm or yarn

### Installation
```bash
pnpm install
```

1. Clone the repository
2. Create your environment file.

```bash
git clone https://github.com/yourusername/locations-API.git
cd locations-API
cp .env.example .env
```

2. Install dependencies
3. Start PostgreSQL and update `DATABASE_URL` if needed.

4. Apply the checked-in schema and seed deterministic fixture data.

```bash
npm install
pnpm db:migrate
pnpm db:seed
```

3. Create `.env` for your environment
> ⚠️ **WARNING**: `pnpm db:seed` is destructive — it truncates all tables before inserting fixture data. Do not run it against a database you need to preserve.

5. Start the development server.

```bash
echo DATABASE_URL="postgresql://postgres:password@localhost:5433/locations" > .env
pnpm dev
```

The above `DATABASE_URL` is for the [Tanzania-locations-database](https://github.com/HackEAC/tanzania-locations-db) Docker container provision.
## Useful Scripts

4. Sync up your API with the locations database:
```bash
pnpm db:migrate
pnpm db:seed
pnpm lint
pnpm typecheck
pnpm build
pnpm test
pnpm test:ci
pnpm openapi:json
```

- **a.** Pull existing DB schema into your Prisma schema
## Migration Behavior

```bash
pnpx prisma db pull
```
- `pnpm db:migrate` is the supported entrypoint for schema changes in this repo
- On a fresh database it bootstraps the historical `init` migration, marks that baseline as applied, and then deploys later migrations
- On an existing database that already has the older Prisma migration history, it only applies the new additive migrations
- Prefer `pnpm db:migrate` over calling `prisma migrate deploy` directly

- **b.** Create migration init files
## Testing

```bash
mkdir prisma/migrations/init
```
- `pnpm test` expects a database that has already been migrated and seeded
- `pnpm test:ci` runs `generate`, `db:migrate`, `db:seed`, and the Jest suite in one command
- For a clean local verification flow, run:

- **c.** Mark the current schema as baseline
```bash
pnpm db:migrate
pnpm db:seed
pnpm test
```

```bash
pnpx prisma migrate diff \
--from-empty \
--to-schema-datamodel prisma/schema.prisma \
--script > prisma/migrations/init/migration.sql
```
## API Base Paths

- **d.** Create migration history manually
- `/v1`: canonical path for current integrations
- `/api`: compatibility alias for older consumers

```bash
pnpx prisma migrate resolve --applied init
```
Both base paths return the same payload shapes.

✅ Now you're synced! Future `prisma migrate dev` or `migrate deploy` will work cleanly.
## Main Endpoints

5. Start development server
### Collections

```bash
npm run dev
```
- `GET /v1/countries`
- `GET /v1/regions`
- `GET /v1/districts`
- `GET /v1/wards`
- `GET /v1/places`

6. Build application
### Detail Routes

```bash
npm run build
```
- `GET /v1/countries/:id`
- `GET /v1/regions/:regionCode`
- `GET /v1/districts/:districtCode`
- `GET /v1/wards/:wardCode`
- `GET /v1/places/:id`

7. Start production server
### Nested Routes

```bash
npm run start
```
- `GET /v1/countries/:countryCode/regions`
- `GET /v1/regions/:regionCode/districts`
- `GET /v1/districts/:districtCode/wards`
- `GET /v1/wards/:wardCode/places`

## API Endpoints
### Search

### Countries
- `GET /v1/countries` - Get all countries
- `GET /v1/countries/:id` - Get country by ID
- `GET /v1/search?q=nzuguni`

### Regions
- `GET /v1/regions` - Get all regions
- `GET /v1/regions/:regionCode` - Get region by code
- `GET /v1/regions/:regionCode/districts` - Get districts in a region
## Collection Query Parameters

### Districts
- `GET /v1/districts` - Get all districts
- `GET /v1/districts/:districtCode` - Get district by code
- `GET /v1/districts/:districtCode/wards` - Get wards in a district
All collection endpoints support:

### Wards
- `GET /v1/wards` - Get all wards
- `GET /v1/wards/:wardCode` - Get ward by code
- `GET /v1/wards/:wardCode/places` - Get places in a ward
- `page`
- `limit`
- `search`

### Places
- `GET /v1/places` - Get all places
- `GET /v1/places/:id` - Get place by ID
Additional filters:

### Search
- `GET /v1/search?q=nzuguni` - Fulltext search for locations by name
- `/regions`: `countryId`
- `/districts`: `countryId`, `regionCode`
- `/wards`: `countryId`, `regionCode`, `districtCode`
- `/places`: `countryId`, `regionCode`, `districtCode`, `wardCode`

## Running Tests
## Docs

```bash
npm test
```
- Swagger UI: `http://localhost:8080/api-docs`
- OpenAPI JSON: `http://localhost:8080/openapi.json`
- `pnpm openapi:json` exports the spec to `generated/openapi/openapi.json`

## Database Notes

- Prisma configuration lives in [prisma.config.ts](./prisma.config.ts)
- The checked-in migration chain now creates the `general.search_vector` column, trigger, and GIN index used by `/search`
- Seed data is intentionally small and deterministic so CI and tests can assert exact results
- The seed is destructive by design for local/CI fixture setup; do not run it against a database you expect to preserve unchanged

## Dependency Automation

- `.github/dependabot.yml` opens weekly update PRs for npm packages and GitHub Actions
- `.github/workflows/ci.yml` validates every PR against Postgres on Node `20.19.0` and `22`

## License

This project is licensed under the CopyLeft License – see the LICENSE file for details.
This project is licensed under the CopyLeft License. See [LICENSE](./LICENSE).
Loading
Loading