Files
sh0rt.kr-pdns/README.md
T
dalbodeule 47461c505f feat: Add script to refresh README from OpenAPI document
refactor: Improve error handling in PowerDNSAPIClient and streamline response processing

fix: Update RecordController to directly return records without unnecessary mapping

refactor: Update DomainRepository and RecordRepository to remove nullable types for IDs

fix: Change User domains fetch strategy to lazy loading for performance improvement

fix: Enhance user authentication handling in UserFilter to ensure authenticated user presence

refactor: Improve DomainService to enforce ownership checks before domain deletion

refactor: Update RecordService to streamline record retrieval and ensure proper domain association

test: Add OpenAPI generation test to validate API documentation endpoint

test: Implement PowerDNSAPIClient tests to verify HTTP method usage and error handling

test: Create DomainService tests to validate domain ownership and deletion logic

test: Add application-test.properties for in-memory database configuration during tests
2026-10-29 23:11:21 +09:00

177 lines
7.1 KiB
Markdown

# Cloudflare compatible PowerDNS API Server
[![Discord](https://img.shields.io/discord/630271953806295051)](https://discord.gg/EPnCfz7xx5) [![Build Status](https://teamcity.mori.space/app/rest/builds/buildType:PdnsApi_Build/statusIcon)](https://teamcity.mori.space/project/PdnsApi)
A Kotlin and Spring Boot API that exposes Cloudflare-style zone and DNS record endpoints backed by PowerDNS and MariaDB. API requests use `Authorization: Bearer <API_KEY>`.
## Build and run
Use JDK 25. The Gradle wrapper selects the Java 25 toolchain for compilation.
```sh
./gradlew test bootJar
./gradlew bootRun
```
`bootRun` activates the `dev` profile. Supply the environment variables below before starting the app. Tests use an in-memory H2 database and do not require MariaDB or PowerDNS.
| Variable | Description |
| --- | --- |
| `DB_HOST` | MariaDB host |
| `DB_PORT` | MariaDB port, usually `3306` |
| `DB_NAME` | Database name |
| `DB_USER` | Database user |
| `DB_PASSWORD` | Database password |
| `PDNS_API_KEY` | PowerDNS HTTP API key |
| `PDNS_API_URL` | PowerDNS HTTP API base URL, for example `http://pdns:8081` |
| `PDNS_NS` | Comma-separated nameservers, for example `ns1.example.com,ns2.example.com` |
## Update API documentation
```sh
./gradlew updateDocs
```
This task starts the app in a test context, writes the current OpenAPI 3.1 specification to [openapi.json](openapi.json), and refreshes the generated API section below. `generateOpenApi` and `updateReadme` are also available separately. The documentation task uses H2 and does not contact PowerDNS.
## API reference
<!-- BEGIN GENERATED API -->
Generated from [openapi.json](openapi.json). Do not edit this section by hand.
### Endpoints
| Method | Path | Summary | Request body | Success response |
| --- | --- | --- | --- | --- |
| `GET` | `/zones` | Get all domains | — | 200: [ApiResponseDTOListDomainResponseDTO](#apiresponsedtolistdomainresponsedto) |
| `POST` | `/zones` | Create domain | [DomainRequestDTO](#domainrequestdto) | 200: [ApiResponseDTODomainResponseDTO](#apiresponsedtodomainresponsedto) |
| `GET` | `/zones/{cfid}` | Get domain | — | 200: [ApiResponseDTODomainResponseDTO](#apiresponsedtodomainresponsedto) |
| `DELETE` | `/zones/{domain_id}` | Delete domain | — | 200: [ApiResponseDTODeleteResponseWithId](#apiresponsedtodeleteresponsewithid) |
| `GET` | `/zones/{zone_id}/dns_records` | Get all records | — | 200: [ApiResponseDTOListRecordResponseDTO](#apiresponsedtolistrecordresponsedto) |
| `POST` | `/zones/{zone_id}/dns_records` | Add Record by ID | [RecordRequestDTO](#recordrequestdto) | 200: [ApiResponseDTORecordResponseDTO](#apiresponsedtorecordresponsedto) |
| `GET` | `/zones/{zone_id}/dns_records/{dns_record_id}` | Get Record by ID | — | 200: [ApiResponseDTORecordResponseDTO](#apiresponsedtorecordresponsedto) |
| `PUT` | `/zones/{zone_id}/dns_records/{dns_record_id}` | Update Record by ID | [RecordRequestDTO](#recordrequestdto) | 200: [ApiResponseDTORecordResponseDTO](#apiresponsedtorecordresponsedto) |
| `DELETE` | `/zones/{zone_id}/dns_records/{dns_record_id}` | Remove Record by ID | — | 200: [ApiResponseDTODeleteResponseWithId](#apiresponsedtodeleteresponsewithid) |
### Schemas
#### ApiResponseDTO
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `success` | boolean | No | — |
| `errors` | array of [ErrorOrMessage](#errorormessage) | No | — |
| `messages` | array of [ErrorOrMessage](#errorormessage) | No | — |
| `result` | — | No | — |
#### ApiResponseDTODeleteResponseWithId
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `success` | boolean | No | — |
| `errors` | array of [ErrorOrMessage](#errorormessage) | No | — |
| `messages` | array of [ErrorOrMessage](#errorormessage) | No | — |
| `result` | [DeleteResponseWithId](#deleteresponsewithid) or null | No | — |
#### ApiResponseDTODomainResponseDTO
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `success` | boolean | No | — |
| `errors` | array of [ErrorOrMessage](#errorormessage) | No | — |
| `messages` | array of [ErrorOrMessage](#errorormessage) | No | — |
| `result` | [DomainResponseDTO](#domainresponsedto) or null | No | — |
#### ApiResponseDTOListDomainResponseDTO
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `success` | boolean | No | — |
| `errors` | array of [ErrorOrMessage](#errorormessage) | No | — |
| `messages` | array of [ErrorOrMessage](#errorormessage) | No | — |
| `result` | array of [DomainResponseDTO](#domainresponsedto) or null | No | — |
#### ApiResponseDTOListRecordResponseDTO
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `success` | boolean | No | — |
| `errors` | array of [ErrorOrMessage](#errorormessage) | No | — |
| `messages` | array of [ErrorOrMessage](#errorormessage) | No | — |
| `result` | array of [RecordResponseDTO](#recordresponsedto) or null | No | — |
#### ApiResponseDTORecordResponseDTO
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `success` | boolean | No | — |
| `errors` | array of [ErrorOrMessage](#errorormessage) | No | — |
| `messages` | array of [ErrorOrMessage](#errorormessage) | No | — |
| `result` | [RecordResponseDTO](#recordresponsedto) or null | No | — |
#### DeleteResponseWithId
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | No | — |
#### DomainRequestDTO
Request DTO for Domain
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | No | Domain name(TLD) |
#### DomainResponseDTO
Response DTO for Domain
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | No | Domain CFID |
| `name` | string | No | Domain name(TLD) |
#### ErrorOrMessage
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `code` | integer | No | — |
| `message` | string | No | — |
#### RecordRequestDTO
Request DTO for Record
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `type` | string | No | Record type |
| `name` | string | No | Host name |
| `value` | string | No | Record data |
| `ttl` | integer | No | TTL (Time to Live) |
| `priority` | integer or null | No | Priority |
| `proxied` | boolean | No | Proxied: cloudflare api compatibility |
| `comment` | string | No | comment |
#### RecordResponseDTO
Response DTO for Record
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | No | Record ID |
| `type` | string | No | Record type |
| `name` | string | No | Record name |
| `content` | string | No | Record content |
| `zoneId` | string | No | Zone(TLD) ID |
| `zoneName` | string | No | Zone name(TLD) |
| `createdOn` | string | No | Record creation time |
| `modifiedOn` | string | No | Record modification time |
| `priority` | integer or null | No | Record priority |
| `proxiable` | boolean | No | is proxyable: must false |
| `proxied` | boolean | No | is proxied: must false |
| `ttl` | integer | No | Record TTL |
| `locked` | boolean | No | Record is locked: must false |
| `comment` | string or null | No | Record comments |
<!-- END GENERATED API -->