⚠️ not suited for first time contributors/beginners.
Is this change related to a problem? Please describe.
Goal
Public REST URL naming and availability are inconsistent across OpenWISP Django modules. This change establishes one convention for public REST URL patterns and removes unsupported settings that conditionally register REST APIs.
This applies to Django URL pattern names used by reverse() and {% url %}. It does not rename view classes unless a separate reason requires that.
Scope
Audit and harmonize public URLConfs in:
- openwisp-users
- openwisp-controller
- openwisp-radius
- openwisp-firmware-upgrader
- openwisp-monitoring
- openwisp-notifications
- openwisp-ipam
- openwisp-subscriptions
- openwisp-network-topology
- openwisp-utils
- django-x509 where applicable
Do not include non-Django projects such as openwisp-config.
Current State
URL naming is inconsistent:
- Firmware Upgrader and Monitoring use
api_ prefixes.
- Controller, IPAM, Notifications, Network Topology, and Utils use generic names inside API URLConfs.
- RADIUS mixes
rest_ and generic names.
- Subscriptions mixes
api_ and generic names.
The audit must identify every public route name, namespace, URL path, caller, test, documentation reference, and REST API route-gate setting before changing a module.
Describe the change
Decisions
Use the following conventions for implementation.
URL Naming
- Use one namespace per module for all public URLs:
users, controller, radius, upgrader, monitoring, notifications, ipam, subscriptions, topology, utils, and x509.
- Prefix every REST URL pattern name with
api_ to distinguish it from HTML and other non-REST views in the same namespace.
- Name a REST route
api_<resource>_<action>, using singular, snake-case resource names. Use list and detail for collection and object routes.
- For a nested resource, include every semantic parent that scopes it:
api_<parent>_<resource>_<action>.
- For an operation on a resource itself, use
api_<resource>_<action> without adding a child resource.
- Do not include transport-only path segments such as
api or v1 in the name.
Examples: users:api_user_list, users:api_user_email_detail, controller:api_device_connection_list, monitoring:api_location_indoor_coordinates_list, and upgrader:api_build_firmware_download.
This keeps one predictable namespace per module while preventing collisions between REST and non-REST views and between similarly named nested resources.
REST API Availability
OpenWISP relies on REST APIs for internal and cross-module behavior. Public REST API URLs are mandatory and cannot be disabled.
- Do not introduce module-level settings that conditionally register public REST URLConfs.
- Retire existing public REST API route gates:
OPENWISP_USERS_AUTH_API, OPENWISP_CONTROLLER_API, OPENWISP_CONTROLLER_PKI_API, OPENWISP_RADIUS_API, and OPENWISP_FIRMWARE_UPGRADER_API.
- Retain settings that configure a distinct concern, including API documentation, remote API URL configuration, API hosts, authentication requirements, and feature-specific registration behavior.
- Authentication, authorization, network controls, and rate limits remain the mechanisms for controlling API access.
Migration Policy
Treat renamed URL pattern names as a documented backward-incompatible change.
- Keep HTTP paths unchanged unless a separate API-versioning decision changes them.
- Publish a complete old-to-new
reverse() mapping in release notes and changelogs.
- Update all maintained OpenWISP modules and sample projects in the same release cycle.
- Update tests, templates, Python callers, JavaScript configuration, and documentation references.
- Do not introduce aliases unless the maintainers decide that the affected release requires a compatibility window.
- If aliases are used, test both names and state their removal version.
Treat removal of a REST API route gate as a documented configuration migration.
- Do not silently register routes for deployments that explicitly set a retiring setting to
False.
- Deprecate each setting before removal and provide a clear warning or configuration error that identifies the obsolete setting and its removal release.
- Update deployment templates and downstream settings that set a retiring setting.
Example mapping:
users:change_password -> users:api_user_password_change
users:user_list -> users:api_user_list
users:email_update -> users:api_user_email_detail
controller:deviceconnection_list -> controller:api_device_connection_list
upgrader:api_firmware_detail -> upgrader:api_build_firmware_detail
Implementation Plan
- Inventory every public production URLConf in scope.
- Record each route's path, current namespace, current name, view, callers, and documentation references.
- Confirm the canonical module namespace and naming convention, including semantic parents for nested routes.
- Inventory all settings, deployment templates, and downstream configuration that conditionally register public REST URLs.
- Define the old-to-new mapping for every affected module and the migration path for each retiring API route gate.
- Update each module's root URLConf and API URLConf consistently, removing public REST API route gates.
- Update all internal
reverse(), reverse_lazy(), templates, tests, and downstream OpenWISP callers.
- Add regression tests that assert each canonical name, including nested resource names, resolves to the expected path and callback.
- Add migration tests for retiring API route gates, including configured
False values and deployment-template coverage where applicable.
- If aliases are chosen, add equivalent regression tests for legacy names.
- Update module documentation and release notes with the complete migration mapping and configuration migration guidance.
- Run each affected module's focused URL tests, QA checks, and full suite.
Describe alternatives considered
A dedicated <module>_api namespace with unprefixed URL names would avoid collisions with non-REST views. One module namespace with api_-prefixed names provides the same protection with fewer namespaces and matches the existing module-level URL structure.
Making REST URLConfs independently optional was also considered. OpenWISP relies on REST APIs for internal and cross-module behavior, so omitting an API URLConf creates unsupported configurations that can fail when code reverses a required route. Access must instead be controlled through authentication, authorization, network controls, and rate limits.
Additional context
AGENTS.md Rule
Add this rule to every in-scope Django module's AGENTS.md:
Public REST URLConfs must use the module's project-wide namespace and snake-case api_<resource>_<action> names. Nested resources must include every semantic parent that scopes them: api_<parent>_<resource>_<action>. Do not use rest_ prefixes or include transport-only path segments such as api or v1 in names. Changes to public URL paths or URL pattern names require a documented migration map, updated downstream callers, and compatibility tests or an explicitly announced backward-incompatible release.
Public REST API URLs are mandatory. Do not add settings that conditionally register them. Retiring a public REST API route gate requires a documented configuration migration that does not silently expose routes for deployments that set it to False.
Completion Criteria
- Every in-scope Django module follows the selected convention.
- No maintained OpenWISP repository uses an obsolete URL name.
- No in-scope module conditionally registers public REST URLs through an API enablement setting.
- Deployment templates and downstream settings no longer use retired REST API route gates.
- Release notes contain the full migration mapping.
- Each changed module passes URL regression tests, QA checks, and its full suite.
Is this change related to a problem? Please describe.
Goal
Public REST URL naming and availability are inconsistent across OpenWISP Django modules. This change establishes one convention for public REST URL patterns and removes unsupported settings that conditionally register REST APIs.
This applies to Django URL pattern names used by
reverse()and{% url %}. It does not rename view classes unless a separate reason requires that.Scope
Audit and harmonize public URLConfs in:
Do not include non-Django projects such as openwisp-config.
Current State
URL naming is inconsistent:
api_prefixes.rest_and generic names.api_and generic names.The audit must identify every public route name, namespace, URL path, caller, test, documentation reference, and REST API route-gate setting before changing a module.
Describe the change
Decisions
Use the following conventions for implementation.
URL Naming
users,controller,radius,upgrader,monitoring,notifications,ipam,subscriptions,topology,utils, andx509.api_to distinguish it from HTML and other non-REST views in the same namespace.api_<resource>_<action>, using singular, snake-case resource names. Uselistanddetailfor collection and object routes.api_<parent>_<resource>_<action>.api_<resource>_<action>without adding a child resource.apiorv1in the name.Examples:
users:api_user_list,users:api_user_email_detail,controller:api_device_connection_list,monitoring:api_location_indoor_coordinates_list, andupgrader:api_build_firmware_download.This keeps one predictable namespace per module while preventing collisions between REST and non-REST views and between similarly named nested resources.
REST API Availability
OpenWISP relies on REST APIs for internal and cross-module behavior. Public REST API URLs are mandatory and cannot be disabled.
OPENWISP_USERS_AUTH_API,OPENWISP_CONTROLLER_API,OPENWISP_CONTROLLER_PKI_API,OPENWISP_RADIUS_API, andOPENWISP_FIRMWARE_UPGRADER_API.Migration Policy
Treat renamed URL pattern names as a documented backward-incompatible change.
reverse()mapping in release notes and changelogs.Treat removal of a REST API route gate as a documented configuration migration.
False.Example mapping:
Implementation Plan
reverse(),reverse_lazy(), templates, tests, and downstream OpenWISP callers.Falsevalues and deployment-template coverage where applicable.Describe alternatives considered
A dedicated
<module>_apinamespace with unprefixed URL names would avoid collisions with non-REST views. One module namespace withapi_-prefixed names provides the same protection with fewer namespaces and matches the existing module-level URL structure.Making REST URLConfs independently optional was also considered. OpenWISP relies on REST APIs for internal and cross-module behavior, so omitting an API URLConf creates unsupported configurations that can fail when code reverses a required route. Access must instead be controlled through authentication, authorization, network controls, and rate limits.
Additional context
AGENTS.md Rule
Add this rule to every in-scope Django module's
AGENTS.md:Completion Criteria