|
1 |
| -# ht_api (Headlines Toolkit API) |
| 1 | +# ht_api |
2 | 2 |
|
3 |
| - |
| 3 | +<!-- Badges (Update coverage XX value after running tests) --> |
| 4 | + |
4 | 5 | [](https://pub.dev/packages/very_good_analysis)
|
5 | 6 | [](https://polyformproject.org/licenses/free-trial/1.0.0)
|
6 | 7 |
|
7 | 8 | ## Overview
|
8 | 9 |
|
9 |
| -`ht_api` is the backend API component of the **Headlines Toolkit (HT)** project. Built with Dart Frog, it serves data and functionality to the corresponding HT Flutter mobile application and web dashboard. |
| 10 | +`ht_api` is the backend API component of the Headlines Toolkit (HT) project. It serves as the central data provider for HT applications (like the mobile app and web dashboard), offering access to various data models required by the toolkit. Built with Dart using the Dart Frog framework, it prioritizes simplicity, maintainability, and scalability through a generic API design. |
10 | 11 |
|
11 | 12 | ## Features
|
12 | 13 |
|
13 |
| -### Current |
| 14 | +* **Generic Data Endpoint (`/api/v1/data`):** Provides a unified RESTful interface for performing CRUD (Create, Read, Update, Delete) operations on multiple data models. |
| 15 | +* **Model Agnostic Design:** Supports various data types through a single endpoint structure, determined by the `?model=` query parameter. |
| 16 | +* **Currently Supported Models:** |
| 17 | + * `headline` |
| 18 | + * `category` |
| 19 | + * `source` |
| 20 | + * `country` |
| 21 | +* **In-Memory Demo Mode:** Utilizes pre-loaded fixture data (`lib/src/fixtures/`) for demonstration and development purposes, simulating a live backend without external dependencies. |
| 22 | +* **Standardized Error Handling:** Returns consistent JSON error responses via centralized middleware (`lib/src/middlewares/error_handler.dart`) for predictable client-side handling. |
14 | 23 |
|
15 |
| -* **🏠 API v1 Root:** Provides a base endpoint for API version 1 (`GET /api/v1/`). |
| 24 | +## Technical Overview |
16 | 25 |
|
17 |
| -* **🌍 Country Endpoints (`/api/v1/countries`)** |
18 |
| - * 📜 **List All:** Retrieve a list of all available countries (`GET`). |
19 |
| - * 🔍 **Get by ISO Code:** Retrieve details for a specific country (`GET /{isoCode}`). |
20 |
| - * ➕ **Create:** Add a new country (`POST`). |
21 |
| - * 🔄 **Update:** Modify an existing country (`PUT` or `PATCH /{isoCode}`). |
22 |
| - * 🗑️ **Delete:** Remove a country (`DELETE /{isoCode}`). |
| 26 | +* **Language:** Dart (`>=3.0.0 <4.0.0`) |
| 27 | +* **Framework:** Dart Frog (`^1.1.0`) |
| 28 | +* **Architecture:** Layered architecture leveraging shared packages and a generic API pattern. |
| 29 | +* **Key Packages & Shared Core:** |
| 30 | + * `dart_frog`: The web framework foundation. |
| 31 | + * `ht_shared`: Contains shared data models (`Headline`, `Category`, `Source`, `Country`, etc.) used across the HT ecosystem. |
| 32 | + * `ht_data_client`: Defines the generic `HtDataClient<T>` interface for data access operations. |
| 33 | + * `ht_data_inmemory`: Provides the `HtDataInMemoryClient<T>` implementation, used here for the demo mode, seeded with fixture data. |
| 34 | + * `ht_data_repository`: Defines the generic `HtDataRepository<T>` which abstracts the data client, providing a clean interface to the API route handlers. |
| 35 | + * `ht_http_client`: Provides custom HTTP exceptions (`HtHttpException` subtypes) used for consistent error signaling, even by the in-memory client. |
| 36 | +* **Key Patterns:** |
| 37 | + * **Generic Repository Pattern:** `HtDataRepository<T>` provides a type-safe abstraction over data fetching logic. Route handlers interact with repositories, not directly with data clients. |
| 38 | + * **Generic Data Endpoint:** A single set of route handlers (`/api/v1/data/index.dart`, `/api/v1/data/[id].dart`) serves multiple data models. |
| 39 | + * **Model Registry:** A central map (`lib/src/registry/model_registry.dart`) links model name strings (from the `?model=` query parameter) to model-specific configurations (`ModelConfig`), primarily containing serialization/deserialization functions (`fromJson`, `toJson`) and ID extraction logic (`getId`). |
| 40 | + * **Dependency Injection (Dart Frog Providers):** Middleware (`routes/_middleware.dart`) is used to instantiate and provide singleton instances of each `HtDataRepository<T>` (configured with the in-memory client and fixture data) and the `ModelRegistryMap`. Route-specific middleware (`routes/api/v1/data/_middleware.dart`) resolves the requested model, validates it, and provides the corresponding `ModelConfig` and model name string to the handler. |
| 41 | + * **Centralized Error Handling:** The `errorHandler` middleware intercepts exceptions (especially `HtHttpException` subtypes and `FormatException`) and maps them to standardized JSON error responses with appropriate HTTP status codes. |
23 | 42 |
|
24 |
| -### Planned |
| 43 | +## API Endpoint: `/api/v1/data` |
25 | 44 |
|
26 |
| -* (No specific planned features identified yet - can be updated as needed) |
| 45 | +This endpoint serves as the single entry point for accessing different data models. The specific model is determined by the `model` query parameter. |
27 | 46 |
|
28 |
| -## Technical Overview |
| 47 | +**Supported `model` values:** `headline`, `category`, `source`, `country` |
| 48 | + |
| 49 | +**Operations:** |
| 50 | + |
| 51 | +1. **Get All Items (Collection)** |
| 52 | + * **Method:** `GET` |
| 53 | + * **Path:** `/api/v1/data?model=<model_name>` |
| 54 | + * **Optional Query Parameters:** |
| 55 | + * `limit=<int>`: Limit the number of items returned. |
| 56 | + * `startAfterId=<string>`: Paginate results, starting after the item with this ID. |
| 57 | + * *Other query parameters*: Passed directly to the repository's `readAllByQuery` method for filtering (e.g., `?model=headline&category=Technology`). |
| 58 | + * **Success Response:** `200 OK` with JSON array of items. |
| 59 | + * **Example:** `GET /api/v1/data?model=headline&limit=10` |
| 60 | + |
| 61 | +2. **Create Item** |
| 62 | + * **Method:** `POST` |
| 63 | + * **Path:** `/api/v1/data?model=<model_name>` |
| 64 | + * **Request Body:** JSON object representing the item to create (ID is usually omitted if auto-generated). |
| 65 | + * **Success Response:** `201 Created` with JSON object of the created item (including its ID). |
| 66 | + * **Example:** `POST /api/v1/data?model=category` with body `{"name": "Sports", "description": "News about sports"}` |
| 67 | + |
| 68 | +3. **Get Item by ID** |
| 69 | + * **Method:** `GET` |
| 70 | + * **Path:** `/api/v1/data/<item_id>?model=<model_name>` |
| 71 | + * **Success Response:** `200 OK` with JSON object of the requested item. |
| 72 | + * **Error Response:** `404 Not Found` if the ID doesn't exist for the given model. |
| 73 | + * **Example:** `GET /api/v1/data/some-headline-id?model=headline` |
29 | 74 |
|
30 |
| -* **Language:** Dart |
31 |
| -* **Framework:** Dart Frog |
32 |
| -* **Architecture:** Follows standard Dart Frog structure with route-based handlers and middleware. Uses dependency injection to provide the `HtCountriesClient`. Part of the larger Headlines Toolkit ecosystem. |
33 |
| -* **Key Libraries/Packages:** |
34 |
| - * `dart_frog`: Core backend framework. |
35 |
| - * `ht_countries_client`: Shared package used as the data source for country information. |
36 |
| - * `very_good_analysis`: Linting rules. |
37 |
| -* **Error Handling:** Centralized error handling middleware is implemented. |
| 75 | +4. **Update Item by ID** |
| 76 | + * **Method:** `PUT` |
| 77 | + * **Path:** `/api/v1/data/<item_id>?model=<model_name>` |
| 78 | + * **Request Body:** JSON object representing the complete updated item (must include the correct `id`). |
| 79 | + * **Success Response:** `200 OK` with JSON object of the updated item. |
| 80 | + * **Error Response:** `404 Not Found`, `400 Bad Request` (e.g., ID mismatch). |
| 81 | + * **Example:** `PUT /api/v1/data/some-category-id?model=category` with updated category JSON in the body. |
| 82 | + |
| 83 | +5. **Delete Item by ID** |
| 84 | + * **Method:** `DELETE` |
| 85 | + * **Path:** `/api/v1/data/<item_id>?model=<model_name>` |
| 86 | + * **Success Response:** `204 No Content`. |
| 87 | + * **Error Response:** `404 Not Found`. |
| 88 | + * **Example:** `DELETE /api/v1/data/some-source-id?model=source` |
38 | 89 |
|
39 | 90 | ## Setup & Running
|
40 | 91 |
|
41 |
| -1. **Clone the repository:** |
| 92 | +1. **Prerequisites:** |
| 93 | + * Dart SDK (`>=3.0.0`) |
| 94 | + * Dart Frog CLI (`dart pub global activate dart_frog_cli`) |
| 95 | +2. **Clone the repository:** |
42 | 96 | ```bash
|
43 |
| - git clone https://github.com/headlines-toolkit/ht-api |
44 |
| - cd ht_api |
| 97 | + git clone https://github.com/headlines-toolkit/ht-api.git |
| 98 | + cd ht-api |
45 | 99 | ```
|
46 |
| -2. **Get dependencies:** |
| 100 | +3. **Get dependencies:** |
47 | 101 | ```bash
|
48 | 102 | dart pub get
|
49 | 103 | ```
|
50 |
| -3. **Run the development server:** |
| 104 | +4. **Run the development server:** |
51 | 105 | ```bash
|
52 | 106 | dart_frog dev
|
53 | 107 | ```
|
54 |
| - The API will typically be available at `http://localhost:8080`. |
| 108 | + The API will typically be available at `http://localhost:8080`. Fixture data from `lib/src/fixtures/` will be loaded into the in-memory repositories on startup. |
| 109 | + |
| 110 | +## Testing |
| 111 | + |
| 112 | +* Run tests and check coverage (aim for >= 90%): |
| 113 | + ```bash |
| 114 | + # Ensure very_good_cli is activated: dart pub global activate very_good_cli |
| 115 | + very_good test --min-coverage 90 |
| 116 | + ``` |
| 117 | +* Update the coverage badge in this README after tests pass. |
55 | 118 |
|
56 | 119 | ## License
|
57 | 120 |
|
58 |
| -This package is licensed under the [PolyForm Free Trial](LICENSE). Please review the terms before use. |
| 121 | +This package is licensed under the [PolyForm Free Trial 1.0.0](LICENSE). Please review the terms before use. |
0 commit comments