Skip to content

Commit ce3a25a

Browse files
committed
Initial commit
0 parents  commit ce3a25a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+3095
-0
lines changed

.github/workflows/ci.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
permissions:
14+
contents: read
15+
16+
jobs:
17+
test:
18+
name: Java ${{ matrix.java-version }}
19+
runs-on: ubuntu-latest
20+
strategy:
21+
fail-fast: false
22+
matrix:
23+
java-version: ["11", "17", "21"]
24+
25+
steps:
26+
- uses: actions/checkout@v4
27+
28+
- name: Set up Java ${{ matrix.java-version }}
29+
uses: actions/setup-java@v4
30+
with:
31+
distribution: temurin
32+
java-version: ${{ matrix.java-version }}
33+
34+
- name: Set up Gradle
35+
uses: gradle/actions/setup-gradle@v4
36+
37+
- name: Lint
38+
run: ./gradlew spotlessCheck
39+
40+
- name: Run tests
41+
run: ./gradlew test

.github/workflows/release.yml

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
test:
13+
name: Test (Java ${{ matrix.java-version }})
14+
runs-on: ubuntu-latest
15+
strategy:
16+
fail-fast: true
17+
matrix:
18+
java-version: ["11", "21"]
19+
20+
steps:
21+
- uses: actions/checkout@v4
22+
23+
- name: Set up Java ${{ matrix.java-version }}
24+
uses: actions/setup-java@v4
25+
with:
26+
distribution: temurin
27+
java-version: ${{ matrix.java-version }}
28+
29+
- name: Set up Gradle
30+
uses: gradle/actions/setup-gradle@v4
31+
32+
- name: Lint
33+
run: ./gradlew spotlessCheck
34+
35+
- name: Run tests
36+
run: ./gradlew test
37+
38+
publish:
39+
name: Publish to Maven Central
40+
needs: test
41+
runs-on: ubuntu-latest
42+
43+
steps:
44+
- uses: actions/checkout@v4
45+
46+
- name: Set up Java
47+
uses: actions/setup-java@v4
48+
with:
49+
distribution: temurin
50+
java-version: 21
51+
52+
- name: Set up Gradle
53+
uses: gradle/actions/setup-gradle@v4
54+
55+
- name: Publish
56+
run: ./gradlew publishAllPublicationsToMavenCentral
57+
env:
58+
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
59+
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
60+
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_SIGNING_KEY }}
61+
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_SIGNING_PASSWORD }}
62+
63+
release:
64+
name: GitHub Release
65+
needs: publish
66+
runs-on: ubuntu-latest
67+
68+
steps:
69+
- uses: actions/checkout@v4
70+
71+
- name: Create GitHub Release
72+
uses: softprops/action-gh-release@v2
73+
with:
74+
generate_release_notes: true

.gitignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Gradle
2+
.gradle/
3+
build/
4+
!gradle/wrapper/gradle-wrapper.jar
5+
6+
# IDE
7+
.idea/
8+
*.iml
9+
.vscode/
10+
.classpath
11+
.project
12+
.settings/
13+
14+
# OS
15+
.DS_Store
16+
Thumbs.db

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 RDAP API
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Makefile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.PHONY: test lint format clean
2+
3+
test:
4+
./gradlew test
5+
6+
lint:
7+
./gradlew spotlessCheck
8+
9+
format:
10+
./gradlew spotlessApply
11+
12+
clean:
13+
./gradlew clean

README.md

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
# rdapapi-java
2+
3+
Official Java SDK for the [RDAP API](https://rdapapi.io) — look up domains, IP addresses, ASNs, nameservers, and entities via the RDAP protocol.
4+
5+
[![Maven Central](https://img.shields.io/maven-central/v/io.rdapapi/rdapapi-java.svg)](https://central.sonatype.com/artifact/io.rdapapi/rdapapi-java)
6+
[![CI](https://github.com/rdapapi/java-sdk/actions/workflows/ci.yml/badge.svg)](https://github.com/rdapapi/java-sdk/actions/workflows/ci.yml)
7+
8+
## Installation
9+
10+
### Gradle
11+
12+
```kotlin
13+
implementation("io.rdapapi:rdapapi-java:0.1.0")
14+
```
15+
16+
### Maven
17+
18+
```xml
19+
<dependency>
20+
<groupId>io.rdapapi</groupId>
21+
<artifactId>rdapapi-java</artifactId>
22+
<version>0.1.0</version>
23+
</dependency>
24+
```
25+
26+
Requires Java 11 or later.
27+
28+
## Quick Start
29+
30+
```java
31+
import io.rdapapi.client.RdapClient;
32+
import io.rdapapi.client.responses.DomainResponse;
33+
34+
try (RdapClient client = new RdapClient("your-api-key")) {
35+
DomainResponse domain = client.domain("google.com");
36+
37+
System.out.println(domain.getRegistrar().getName()); // "MarkMonitor Inc."
38+
System.out.println(domain.getDates().getRegistered()); // "1997-09-15T04:00:00Z"
39+
System.out.println(domain.getDates().getExpires()); // "2028-09-14T04:00:00Z"
40+
System.out.println(domain.getNameservers()); // ["ns1.google.com", ...]
41+
}
42+
```
43+
44+
## Usage
45+
46+
### Configuration
47+
48+
```java
49+
import io.rdapapi.client.RdapClient;
50+
import io.rdapapi.client.RdapClientOptions;
51+
import java.time.Duration;
52+
53+
// Default configuration
54+
RdapClient client = new RdapClient("your-api-key");
55+
56+
// Custom timeout
57+
RdapClient client = new RdapClient("your-api-key",
58+
new RdapClientOptions().timeout(Duration.ofSeconds(10)));
59+
60+
// Custom base URL
61+
RdapClient client = new RdapClient("your-api-key",
62+
new RdapClientOptions().baseUrl("https://custom.api.com/v1"));
63+
```
64+
65+
The client implements `AutoCloseable` and can be used with try-with-resources.
66+
67+
### Domain Lookup
68+
69+
```java
70+
DomainResponse domain = client.domain("example.com");
71+
domain.getDomain(); // "example.com"
72+
domain.getRegistrar().getName(); // Registrar name
73+
domain.getRegistrar().getIanaId(); // IANA registrar ID
74+
domain.isDnssec(); // true/false
75+
76+
// With registrar follow-through (for thin registries)
77+
DomainResponse domain = client.domain("example.com", new DomainOptions().follow(true));
78+
domain.getMeta().getFollowed(); // true
79+
```
80+
81+
### IP Address Lookup
82+
83+
```java
84+
IpResponse ip = client.ip("8.8.8.8");
85+
ip.getName(); // "LVLT-GOGL-8-8-8"
86+
ip.getCountry(); // "US"
87+
ip.getCidr(); // ["8.8.8.0/24"]
88+
ip.getStartAddress(); // "8.8.8.0"
89+
ip.getEndAddress(); // "8.8.8.255"
90+
```
91+
92+
### ASN Lookup
93+
94+
```java
95+
AsnResponse asn = client.asn(15169); // integer
96+
AsnResponse asn = client.asn("AS15169"); // string with prefix (stripped automatically)
97+
98+
asn.getName(); // "GOOGLE"
99+
asn.getStartAutnum(); // 15169
100+
```
101+
102+
### Nameserver Lookup
103+
104+
```java
105+
NameserverResponse ns = client.nameserver("ns1.google.com");
106+
ns.getLdhName(); // "ns1.google.com"
107+
ns.getIpAddresses().getV4(); // ["216.239.32.10"]
108+
ns.getIpAddresses().getV6(); // ["2001:4860:4802:32::a"]
109+
```
110+
111+
### Entity Lookup
112+
113+
```java
114+
EntityResponse entity = client.entity("GOGL");
115+
entity.getName(); // "Google LLC"
116+
entity.getAutnums().get(0).getHandle(); // "AS15169"
117+
entity.getNetworks().get(0).getCidr(); // ["8.8.8.0/24"]
118+
```
119+
120+
### Bulk Domain Lookup
121+
122+
Requires a Pro or Business plan. Up to 10 domains per call.
123+
124+
```java
125+
BulkDomainResponse resp = client.bulkDomains(
126+
List.of("google.com", "github.com", "example.com"),
127+
new DomainOptions().follow(true));
128+
129+
resp.getSummary().getTotal(); // 3
130+
resp.getSummary().getSuccessful(); // 3
131+
132+
for (BulkDomainResult result : resp.getResults()) {
133+
if ("success".equals(result.getStatus())) {
134+
System.out.println(result.getDomain() + "" + result.getData().getRegistrar().getName());
135+
} else {
136+
System.out.println(result.getDomain() + " — error: " + result.getMessage());
137+
}
138+
}
139+
```
140+
141+
## Error Handling
142+
143+
All API errors are thrown as unchecked exceptions that extend `RdapApiException`:
144+
145+
```java
146+
import io.rdapapi.client.exceptions.*;
147+
148+
try {
149+
client.domain("example.com");
150+
} catch (NotFoundException e) {
151+
System.out.println("Not found: " + e.getMessage());
152+
} catch (RateLimitException e) {
153+
System.out.println("Rate limited, retry after " + e.getRetryAfter() + " seconds");
154+
} catch (AuthenticationException e) {
155+
System.out.println("Invalid API key");
156+
} catch (SubscriptionRequiredException e) {
157+
System.out.println("Subscription required");
158+
}
159+
```
160+
161+
| Exception | HTTP Status | Description |
162+
|---|---|---|
163+
| `ValidationException` | 400 | Invalid input |
164+
| `AuthenticationException` | 401 | Invalid or missing API key |
165+
| `SubscriptionRequiredException` | 403 | No active subscription |
166+
| `NotFoundException` | 404 | No RDAP data found |
167+
| `RateLimitException` | 429 | Rate limit or quota exceeded |
168+
| `UpstreamException` | 502 | Upstream RDAP server failure |
169+
170+
All exceptions expose `getStatusCode()`, `getErrorCode()`, and `getMessage()`. `RateLimitException` also has `getRetryAfter()` (Integer or null).
171+
172+
Network errors (`IOException`, `InterruptedException`) are checked exceptions that propagate from `java.net.http.HttpClient`.
173+
174+
## Nullable Fields
175+
176+
Fields that may be absent in API responses return `null`. Check before using:
177+
178+
```java
179+
if (domain.getDates().getExpires() != null) {
180+
System.out.println("Expires: " + domain.getDates().getExpires());
181+
}
182+
183+
// Contact fields may be null
184+
if (domain.getEntities().getRegistrant() != null) {
185+
System.out.println("Registrant: " + domain.getEntities().getRegistrant().getName());
186+
}
187+
```
188+
189+
List fields (`getStatus()`, `getNameservers()`, `getCidr()`, etc.) never return null — they return an empty unmodifiable list when absent.
190+
191+
## License
192+
193+
MIT — see [LICENSE](LICENSE).

0 commit comments

Comments
 (0)