Skip to content

[Enhancement] Migrate REST API library from Slim v2 to Slim v4 #1317

Description

@JohnVillalovos

Claude Code generated plan

Slim Framework v2 → v4 Upgrade Plan

Background

The project uses a vendored copy of Slim v2.0.0 (lib/external/Slim/) from ~2012.
This version is abandoned and does not follow modern PHP standards (PSR-7, PSR-15).

Slim v4.15+ is actively maintained, supports PHP 8.2+, and is a solid choice to stay with.
The project already has an IRestServer abstraction layer — the 14 WebService classes need zero changes.


Should We Do This?

Yes. Reasons:

  1. Slim v2 is ~14 years old and abandoned; it contains mcrypt polyfills for a long-removed PHP extension.
  2. Migration scope is small (~5 files) thanks to the existing IRestServer abstraction.
  3. All 14 WebService classes (AuthenticationWebService, ReservationsWebService, etc.) use only IRestServer — they are completely framework-agnostic.
  4. Slim v4 is actively maintained and receives security patches.
  5. Moving to Composer eliminates the burden of a vendored copy.
  6. Switching to a different framework would require learning new APIs for marginal benefit.

Current Slim v2 Usage

The entire Slim surface area is confined to 5 files (plus 1 test file):

File Slim API used
Web/Services/index.php App creation, autoloader, hooks, halt, error, run
lib/WebService/Slim/SlimServer.php (74 lines) request body/headers/query, response write/status/header, urlFor, environment
lib/WebService/Slim/SlimWebServiceRegistry.php $app->get/post/delete(), ->name()
lib/WebService/Slim/SlimServiceRegistration.php Route string definitions (:param syntax)
Pages/ApiHelpPage.php $app->urlFor()
tests/WebService/SlimWebServiceRegistryTest.php Extends Slim\Slim, constructs Slim\Route

Key API Differences (v2 → v4)

Feature Slim v2 Slim v4
Creation new \Slim\Slim() AppFactory::create()
Autoloading Slim::registerAutoloader() Composer
Route params /:param /{param} (~30 routes)
Named routes ->name('x') ->setName('x')
Hooks $app->hook('slim.before.dispatch', ...) PSR-15 middleware
Halt $app->halt(403) Throw HttpForbiddenException
Request/Response Proprietary mutable objects PSR-7 immutable interfaces
URL generation $app->urlFor() $routeParser->urlFor()

Upgrade Plan

Phase 0: Preparation

  • Ensure test coverage of the API endpoints exists before starting.
  • The existing SlimWebServiceRegistryTest is a good baseline, but consider adding a test that boots the real Slim app.
  • Create a feature branch: feature/slim-v4-upgrade.

Phase 1: Install Slim v4 via Composer

Add to composer.json:

"slim/slim": "^4.15",
"slim/psr7": "^1.7"

Run composer install. Keep lib/external/Slim/ in place during the migration.

Phase 2: Rewrite lib/WebService/Slim/SlimServer.php

Rewrite the ~74-line adapter to use PSR-7 objects:

  • Constructor receives Slim\App and a RouteParserInterface.
  • Add setRequest(ServerRequestInterface $request) and setResponse(ResponseInterface $response) methods called from route callbacks.
  • GetRequest()json_decode($this->request->getBody()->getContents())
  • WriteResponse() → write to $this->response->getBody(), use withStatus() and withHeader() (immutable — store the new response object).
  • GetHeader($name)$this->request->getHeaderLine($name)
  • GetQueryString($key)$this->request->getQueryParams()[$key] ?? null
  • GetUrl()$this->request->getUri()->getScheme() . '://' . $this->request->getUri()->getHost()
  • GetServiceUrl($name, $params)$this->routeParser->urlFor($name, $params)

Phase 3: Rewrite lib/WebService/Slim/SlimWebServiceRegistry.php

  • Constructor: change type hint from Slim\Slim to Slim\App.
  • Named route chaining: ->name('x')->setName('x').
  • Route callbacks need to receive ($request, $response, $args) and call $server->setRequest($request) / $server->setResponse($response) before invoking the existing callback.

Phase 4: Rewrite Web/Services/index.php

  1. Replace autoloader + instantiation:

    // Before
    \Slim\Slim::registerAutoloader();
    $app = new \Slim\Slim();
    
    // After
    use Slim\Factory\AppFactory;
    $app = AppFactory::create();
    $app->addRoutingMiddleware();
  2. Replace $app->hook('slim.before.dispatch', ...) with a PSR-15 middleware class (e.g., ApiAuthMiddleware) that:

    • Checks if the API is enabled (returns 503 if not).
    • Looks up route name via $request->getAttribute('__route__')->getName().
    • Runs WebServiceSecurity checks.
    • Throws HttpUnauthorizedException / HttpForbiddenException instead of $app->halt().
  3. Replace $app->error(...) with:

    $errorMiddleware = $app->addErrorMiddleware(true, true, true);
    $errorMiddleware->setDefaultErrorHandler(function (...) { ... });
  4. Keep $app->run().

Phase 5: Update Pages/ApiHelpPage.php

  • Change constructor/method signature from Slim\Slim $app to accept Slim\App $app or just a RouteParserInterface.
  • Replace $app->urlFor() with $routeParser->urlFor().

Phase 6: Update Route Parameter Syntax

In SlimServiceRegistration.php (or wherever route strings are defined), change all patterns:

  • /:param/{param}

Approximately 30 route strings across the registration functions in index.php and related files.

Phase 7: Update Tests

  • tests/WebService/SlimWebServiceRegistryTest.php: The TestSlim class extends Slim\Slim — rewrite to use Slim\App or mock the Slim v4 App. The Slim\Route constructor used in tests also changed.
  • FakeRestServer: No changes needed.
  • All other WebService tests: No changes needed.

Phase 8: Delete Vendored Slim v2

git rm -r lib/external/Slim/

Phase 9: Verify

composer phpcsfixer:fix
composer phpstan
composer phpunit
./ci/ci-phplint

Risks

Risk Severity Mitigation
Route parameter passing changes (v2: function args, v4: $args array) Medium Trace each WebService method's route param usage; bridge in callback wrapper
Middleware execution order is LIFO in v4 Medium Test authentication flow carefully
PSR-7 immutable responses Low SlimServer::WriteResponse() must store the returned response object
Named route URL generation differences Low RouteParser::urlFor() is a direct replacement; test API help page
.htaccess / web server routing Low Existing rewrite rules to index.php should work unchanged

Effort Estimate

Component Effort
SlimServer.php rewrite 1-2 hours
SlimWebServiceRegistry.php rewrite 1 hour
Web/Services/index.php rewrite (middleware is the complex part) 2-3 hours
Route syntax + SlimServiceRegistration.php 30 minutes
ApiHelpPage.php update 30 minutes
Test updates 1-2 hours
Integration testing and debugging 2-4 hours
Total ~8-12 hours

References

Metadata

Metadata

Labels

staleNo activity

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions