Loading
task: #3629746: Move the Graph API client to the base module and add a typed API exception
Closes #3629746
What this does
- Moves
MapillaryApiClient,MapillaryApiCallEventandMissingAccessTokenExceptionfrommapillary_fieldto the base module. The client is now themapillary.api_clientservice. - Adds
MapillaryApiException(extends\RuntimeException), thrown for every failed request. It carries the HTTP status, the Graph API error code andRetry-After, and answersisNotFound(),isBadId()andisServiceWide().MissingAccessTokenExceptionextends it. - Adds typed methods that check the ID format before the ID becomes part of the path:
getImage(),getImages(),getSequenceImageIds(),getMapFeature(),getDetections(). An input such asmeor123/detectionsis rejected without a request.get()stays for other paths. - Adds
checkToken().ApiSettingsFormuses it instead of building the request itself. - Dispatches
MapillaryApiCallEventonce, in afinallyblock, also when the token is missing. - The client no longer logs. The callers that run unattended (queue workers, thumbnail refresher, Drush) already log the failures they handle, the forms and widgets show them, and Mapillary Logs records each failed request. A failed request was logged up to three times before.
MapillaryThumbnailRefresheruses the exception methods instead of unwrapping Guzzle exceptions.
Backwards compatibility
mapillary_field.api_clientis a deprecated alias ofmapillary.api_client.- The old class names in
mapillary_fieldkeep working, also incatchblocks and type hints. Neither of these triggers the autoloader, so each new class file registers the old name withclass_alias(). The old files only trigger a deprecation and load the new class, for code that uses an old name first. - The constructor still accepts the old signature
(factory, config, logger, dispatcher), with a deprecation, so code that builds the client by hand and a container cached beforedrush updbkeep working. MapillaryThumbnailRefresher::isServiceWideFailure()is deprecated in favour ofMapillaryApiException::isServiceWide().- The event name
mapillary_field.api_calldoes not change. - An empty post_update rebuilds the container. No schema or config change.
All deprecations are removed in 1.0.0-beta1.
Also in this MR
- The ID patterns use the
Dmodifier, so"123\n"is rejected too. - PHPStan level 6 warnings in the touched importer files are fixed (
ContentEntityInterfacereturn types). - CHANGELOG and AGENTS.md are updated.
Testing
- Unit tests for the client and the exception: every status and Graph API error code,
Retry-Afterin seconds and as an HTTP date, invalid IDs sending no request, the event dispatched once on every path including a missing token, the old constructor signature. - Legacy tests for the old class names (catch, type hints, old name used first) and the old service ID.
- Kernel tests: a failed request reaches the system log once; a missing token is logged by Mapillary Logs; the image and sequence import forms send no request for
me,123/detectionsorabc/def. - The full PHPUnit suites of
mapillary,mapillary_field,mapillary_logs,mapillary_detection,mapillary_map_feature,mapillary_leaflet(without FunctionalJavascript) andmapillary_entitypass locally on PostgreSQL. - Manual check against the live Graph API: an unknown ID gives HTTP 400 with code 100 (
isBadId()), an invalid token gives HTTP 401 with code 190 (isServiceWide()).
Follow-ups
- Moving the image and sequence importer to
mapillary_entity. After that,mapillary_detectionandmapillary_map_featureno longer needmapillary_field. - Queue and cascade failure policy, which builds on
isBadId()andisServiceWide().