# PIP-457: Remove support for V1 topic names and V1 Admin API

## Background knowledge

Apache Pulsar historically supported two topic naming formats:

- **V1 format**: `persistent://tenant/cluster/namespace/topic` — includes the cluster name in the topic path
- **V2 format**: `persistent://tenant/namespace/topic` — omits the cluster name, making all namespaces implicitly "global"

The V1 format was the original naming convention from Pulsar's early days. PIP-10 introduced V2 topic names in Pulsar 2.0 (released June 2018) by removing the cluster component, and PIP-11 further simplified naming with short topic names defaulting to `persistent://public/default/`. V1 topic names have been deprecated since Pulsar 2.0 — nearly 8 years ago at the time of this proposal.

The V1 naming format also implied a separate set of Admin REST API endpoints, Lookup endpoints, and WebSocket paths that include `{property}/{cluster}/{namespace}` in their URL structure, as opposed to the V2 paths using `{tenant}/{namespace}`.

These V1 APIs have been deprecated and hidden from the API documentation for many years. The V2 format has been the recommended and default format since Pulsar 2.0.

## Motivation

The continued presence of V1 topic name support imposes several costs on the project:

1. **Maintenance burden**: Every Admin API operation must be duplicated across V1 and V2 endpoint classes (`v1.PersistentTopics`, `v1.NonPersistentTopics`, `v1.Namespaces`, `v1.TopicLookup` alongside their V2 counterparts). Bug fixes and new features touching admin APIs must account for both code paths.

2. **Increased attack surface**: The V1 endpoints are hidden from documentation but still active and routable, creating undocumented API surface area that must be secured, tested, and maintained.

3. **Code complexity in TopicName parsing**: The `TopicName` class must handle both 3-part (V2) and 4-part (V1) name parsing, and the `isV2()` check propagates throughout the broker, lookup, and client code.

4. **WebSocket handler complexity**: WebSocket paths must support both `/ws/producer/persistent/{property}/{cluster}/{namespace}/{topic}` (V1) and `/ws/v2/producer/persistent/{tenant}/{namespace}/{topic}` (V2).

5. **Confusion for new contributors and operators**: The existence of two naming schemes and two sets of admin APIs creates unnecessary confusion and cognitive overhead.

6. **Test matrix expansion**: V1 paths must be covered by integration and unit tests, expanding the test matrix without providing value to modern deployments.

V1 topics have been deprecated since Pulsar 2.0, released in June 2018. With nearly 8 years having passed and the project now on the 4.x release line, it is time to complete this deprecation and remove V1 support entirely.

## Goals

### In Scope

- Remove all V1 Admin REST API endpoint classes and their registrations:
    - `org.apache.pulsar.broker.admin.v1.PersistentTopics`
    - `org.apache.pulsar.broker.admin.v1.NonPersistentTopics`
    - `org.apache.pulsar.broker.admin.v1.Namespaces`
    - `org.apache.pulsar.broker.admin.v1.Clusters` (if present)
- Remove V1 topic lookup endpoint:
    - `org.apache.pulsar.broker.lookup.v1.TopicLookup`
- Remove V1 WebSocket handler paths
- Remove V1 (4-part) topic name parsing from `TopicName` and related classes
- Remove `isV2()` method and all conditional branching based on V1 vs V2 topic format
- Remove `LOOKUP_PATH_V1` constant and related redirect logic
- Remove or update all tests that exercise V1 code paths
- Update CLI tools that may still reference V1 format
- Log a clear error message if a client attempts to use a V1-style topic name, to aid migration

### Out of Scope

- Removal of the V2 Admin API in favor of V4 (that would be a separate PIP)
- Changes to the binary protocol wire format
- Metadata store migration of existing V1 topic metadata (this PIP covers code removal; data migration would be addressed separately if needed)

## High Level Design

The removal will be executed in a single coordinated change:

1. **Admin API**: Delete the `v1` package under `pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v1/` and remove the registration of V1 REST resources from the broker's web server initialization.

2. **Lookup**: Delete `pulsar-broker/src/main/java/org/apache/pulsar/broker/lookup/v1/TopicLookup.java` and remove its registration.

3. **TopicName parsing**: Simplify `TopicName` to only accept the 3-part V2 format (`domain://tenant/namespace/localName`). If a 4-part name is provided, throw a clear `IllegalArgumentException` with a message explaining V1 names are no longer supported and how to convert.

4. **WebSocket**: Remove V1 URI parsing paths from `AbstractWebSocketHandler` and related classes.

5. **Tests**: Remove or convert all V1-specific test cases. Tests that coincidentally use V1 names should be updated to V2 format.

## Detailed Design

### Admin API Removal

The following classes will be deleted:
- `pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v1/PersistentTopics.java`
- `pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v1/NonPersistentTopics.java`
- `pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v1/Namespaces.java`

Their registration in the broker's Jersey/JAX-RS application configuration will be removed.

### TopicName Simplification

In `pulsar-common`, the `TopicName` class will be modified:

```java
// Before: accepts both V1 (4 parts) and V2 (3 parts)
// After: only accepts V2 (3 parts)
private TopicName(String completeTopicName) {
    // ... parse domain://
    String[] parts = rest.split("/", 3); // tenant/namespace/localName
    if (parts.length != 3) {
        throw new IllegalArgumentException(
            "Invalid topic name '" + completeTopicName + "'. "
            + "Expected format: 'persistent://tenant/namespace/topic'. "
            + "V1 topic names (with cluster component) are no longer supported. "
            + "Please use the V2 format without the cluster name.");
    }
    this.tenant = parts[0];
    this.namespace = parts[1];
    this.localName = parts[2];
    // cluster field removed entirely
}
```

The `isV2()` method and `cluster` field will be removed from `TopicName`. All call sites that branch on `isV2()` will be simplified.

The `NamespaceName` class will similarly be simplified to remove V1 support.

### Lookup Simplification

The `LOOKUP_PATH_V1` constant and any conditional logic choosing between V1/V2 redirect paths will be removed. Lookups will only use V2 paths.

### WebSocket Simplification

The `getTopic()` method in WebSocket handler classes will be simplified to only parse V2-style URIs (`/ws/v2/...`).

## Public-facing Changes

### REST API

The following REST API paths will be **removed**:

**Persistent Topics (V1)**:
- `GET /admin/persistent/{property}/{cluster}/{namespace}` — list topics
- `GET/PUT/DELETE /admin/persistent/{property}/{cluster}/{namespace}/{topic}/...` — all topic operations
- `GET/PUT/DELETE /admin/persistent/{property}/{cluster}/{namespace}/partitioned` — partitioned topic operations

**Non-Persistent Topics (V1)**:
- `GET /admin/non-persistent/{property}/{cluster}/{namespace}` — list topics
- `GET/PUT/DELETE /admin/non-persistent/{property}/{cluster}/{namespace}/{topic}/...` — all topic operations

**Namespaces (V1)**:
- `GET/PUT/DELETE /admin/namespaces/{property}/{cluster}/{namespace}` — all namespace operations

**Lookup (V1)**:
- `GET /lookup/v2/destination/{topic-domain}/{property}/{cluster}/{namespace}/{topic}` — topic lookup

### Binary Protocol

No changes to the binary protocol.

### Configuration

No new configuration. The broker configuration key `allowV1Topics` may be considered for a transitional release but is **not** proposed here — the removal is clean and complete.

### CLI

`pulsar-admin` and `pulsar-client` CLI tools will only accept V2 topic names. Passing a V1 topic name will produce a clear error message with migration guidance.

### Metrics

No metrics changes.

## Monitoring

Operators should monitor for client errors after the upgrade. Clients attempting to use V1 topic names will receive clear error responses (HTTP 404 for V1 admin paths, or client-side `IllegalArgumentException` for V1 topic names).

## Security Considerations

This change reduces the API attack surface by removing undocumented but active REST endpoints. No new security considerations are introduced.

## Backward & Forward Compatibility

### Upgrade

This is a **breaking change** for any deployment still using V1 topic names or V1 Admin API paths.

Before upgrading to the version containing this change, operators must:
1. Ensure all topic names in use follow the V2 format (`persistent://tenant/namespace/topic`)
2. Ensure all Admin API clients use V2 endpoints (`/admin/v2/...`)
3. Ensure all WebSocket clients use V2 paths (`/ws/v2/...`)

The V1 format has been deprecated since Pulsar 2.0, released in June 2018 — nearly 8 years ago. Any deployment that has been maintained on a supported Pulsar version should already be using V2 format exclusively.

### Downgrade / Rollback

Rolling back to a prior version that supports V1 topic names will work without issues, as no data format changes are involved.

### Geo-Replication

No impact. Geo-replication already uses V2 topic names. The cluster component in V1 topic names was originally related to replication configuration but has been decoupled since V2 was introduced.

## General Notes

### Related PIPs
- PIP-10: Remove cluster from topic name (introduced V2 naming)
- PIP-11: Short topic name (further simplified topic naming)
- PIP-48: Proposed V4 admin API (future direction for admin APIs)

### Migration Guide

For any users who may still be using V1 topic names, the migration is straightforward:

| V1 Format | V2 Format |
|---|---|
| `persistent://my-tenant/my-cluster/my-namespace/my-topic` | `persistent://my-tenant/my-namespace/my-topic` |
| `/admin/persistent/my-tenant/my-cluster/my-namespace` | `/admin/v2/persistent/my-tenant/my-namespace` |
| `/ws/producer/persistent/my-tenant/my-cluster/my-ns/my-topic` | `/ws/v2/producer/persistent/my-tenant/my-ns/my-topic` |

Simply remove the cluster component from the topic name path.

