API v2 Redux - #2645
Draft
jnovack wants to merge 11 commits into
Draft
Conversation
jnovack
force-pushed
the
api-v2
branch
2 times, most recently
from
May 16, 2026 22:19
00353bb to
777994e
Compare
Contributor
|
@jnovack Did you want to leave this open or do something else with it? |
Member
Author
|
Is it worth revisiting? We've talked about versioning the API, so we can start upgrading them, it's sat here for 3 months getting stale (though no direct fault of anyone). Are we happy with this direction, is this a good step in a direction? If so, I'll continue to spend time addressing the conflicts and we can at least get v2 in alpha/testing. |
jnovack
force-pushed
the
api-v2
branch
2 times, most recently
from
August 1, 2026 15:54
2a25b78 to
439473c
Compare
The api-v2 rewrite renamed every route's dispatch-table target in index.php
to PascalCase, but never touched the function definitions in these three
controllers, which still used their old names:
- effects.php: effects_list() -> EffectsList()
effects_list_ALL() -> EffectsListAll()
- stats.php: stats_get_last_file() -> StatsGetLastFile()
stats_publish_stats_file() -> StatsPublishStatsFile()
stats_delete_last_file() -> StatsDeleteLastFile()
- testmode.php: testMode_Get() -> TestModeGet()
testMode_Set() -> TestModeSet()
Each affected route (GET/ALL /effects, GET/POST/DELETE /statistics/usage,
GET/POST /testmode) called a function that didn't exist, so hitting any of
them threw a fatal "call to undefined function" error. Also updated the one
internal caller (StatsPublishStatsFile -> StatsGetLastFile) affected by the
stats.php rename.
Verified by cross-checking every dispatch_* target in index.php against the
functions actually defined in controllers/*.php -- no dangling routes remain.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR: Consolidate v1/v2 API into single router
The SHORT SHORT Version
/api/v2routes (currently only some verb changes)WWWAPI-GUIDELINES.mdoutlines the details of why this change is so wordy, as all the files were re-written to comply with the formatting, style and structure to maintain consistency between files (there's still more work to do...)What changed
www/api/index.php$apiVersionPrefixes = ['', '/v2']array anddispatch_all(string $path, string $method, string $fn)helper that registers a route under every version prefix in one call.require_once 'controllers/helpers.php'for the newgetJsonBody()utility.snake_case/ mixed-case to PascalCase (public functions) and camelCase (helpers), matching the merged controllers. No behavioral change.dispatch_get(...)calls todispatch_all(...)calls.dispatch_post('/v2/...')lines for routes that changed from GET to POST in v2 (all state-changing operations: start/stop/pause/resume playlist, sequence control, fppd restart/start/stop, system reboot/shutdown, git reset, event trigger, script run, file move/onUpload, network interface add).remoteActionGET handler toRemoteAction_v1(query-param format). Addeddispatch_post('/v2/remoteAction', 'RemoteAction')for the JSON-body v2 variant.addPluginEndpoints()to calldispatch_all()so plugins are automatically registered under both/plugin/...and/v2/plugin/....www/api/controllers/(16 files replaced)Replaced each v1 controller with its v2 counterpart. All changes are naming convention only — no behavioral differences:
snake_case→PascalCasecamelCaseEvery controller function's docblock now uses version-tagged route annotations instead of a single
@routetag:@route-v1 METHOD /pathand@route-v2 METHOD /pathdeclare per-version routes (paths are prefix-free; the generator prepends the server base URL).@badge-v1 "DEPRECATED" warningmarks v1-only GET variants as deprecated in the generated OpenAPI spec.@body-vN,@response-vN, and@deprecated-vNare also supported for version-specific overrides.Affected files:
cape,network,system,sequence,backups,playlist,settings,channel,configfile,files,events,scripts,git,plugin,audioaliases,pipewirewww/api/controllers/helpers.php(new)Moved from
www/api/v2/controllers/helpers.php. ContainsgetJsonBody(bool $required = true): ?array, a centralized JSON request-body parser used by POST handlers that previously calledfile_get_contents('php://input')ad hoc.www/api/controllers/proxies.phpAdded
RemoteAction_v1()shim that readsipandactionfrom$_GETquery parameters (v1 GET behavior). The existingRemoteAction()function reads from the JSON request body (v2 POST behavior).www/api/controllers/help.phpandwww/apihelp.php(removed)The legacy help controller and its front-end entry point have been deleted. API documentation is now served exclusively from the OpenAPI spec.
Spec/doc file reorganization
Moved v1 static files into a
www/api/v1/subdirectory to match the v2 layout:www/api/openapi.json→www/api/v1/openapi.jsonwww/api/api.html→www/api/v1/api.htmlOpenAPI tooling (
www/api/tools/)generate_openapi.pyrenamed togenerate_openapi_v1.py.generate_openapi_base.py— shared generator logic imported by bothgenerate_openapi_v1.pyandgenerate_openapi_v2.py. Parses the@route-vN/@badge-vN/@deprecated-vNdocblock tags and builds version-filtered specs from a single controller source.convert_endpoints.pydeleted (one-off migration tool, no longer needed).Test infrastructure
tests/playwright/fixtures/version.ts(new): exportsV1 = '/api',V2 = '/api/v2', andtestBothVerbVersions()helper. For routes where only the verb changed (identical logic), one assertion function is shared by two thin@v1/@v2tagged test wrappers. Routes where behavior changed (e.g.remoteAction) keep separate test functions.tests/playwright/tests/api-v2/*.spec.ts: verb-changed routes updated to usetestBothVerbVersions(); individual tests carry@coveredtags for coverage tracking.tests/playwright/scripts/check-api-coverage.ts: router path updated fromwww/api/v2/index.phptowww/api/index.php; filter updated to only match/v2/prefixed routes when diffing againstAPI_COVERAGE.md.tests/playwright/package.json: addedtest:api:v1andtest:api:v2scripts.@e2e,@security,@full,@schema...Backward compatibility
All v1 routes continue to respond at their original paths and with their original HTTP verbs. No v1 client is broken (hopefully...)
Fixed
v2/index.phpv2/sequence/{SequenceName}v2/controllers/files.phpv2/file/move/{fileName},v2/file/onUpload/{ext}/**GETv2/controllers/network.phpv2/network/interface/add/{interface}GETv2/controllers/plugin.phpv2/plugin/{RepoName}/upgradeGETfor a mutating operationv2/controllers/system.phpv2/system/reboot,v2/system/shutdown,v2/system/fppd/*GETv2/controllers/playlist.phpv2/playlists/*,v2/playlist/{PlaylistName}/start*GETinstead of a mutating verbv2/controllers/events.phpv2/events/{eventId}/triggerGETv2/controllers/proxies.phpv2/remoteActionGETquery endpointv2/controllers/scripts.phpv2/scripts/{scriptName}/run,v2/scripts/installRemote/{category}/{filename}GETv2/controllers/git.phpv2/git/resetGETv2/controllers/sequence.phpv2/sequence/{SequenceName}/start/{startSecond},v2/sequence/current/*GET