Skip to content

Commit

Permalink
Merge "REST: Add a new GetPropertyLabelWithFallback route"
Browse files Browse the repository at this point in the history
  • Loading branch information
jenkins-bot authored and Gerrit Code Review committed Oct 2, 2024
2 parents f08a648 + 7e6100c commit 27ddce7
Show file tree
Hide file tree
Showing 18 changed files with 623 additions and 0 deletions.
5 changes: 5 additions & 0 deletions repo/rest-api/routes.dev.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,10 @@
"path": "/wikibase/v0/entities/items/{item_id}/labels_with_language_fallback/{language_code}",
"method": "GET",
"factory": "Wikibase\\Repo\\RestApi\\RouteHandlers\\GetItemLabelWithFallbackRouteHandler::factory"
},
{
"path": "/wikibase/v0/entities/properties/{property_id}/labels_with_language_fallback/{language_code}",
"method": "GET",
"factory": "Wikibase\\Repo\\RestApi\\RouteHandlers\\GetPropertyLabelWithFallbackRouteHandler::factory"
}
]
3 changes: 3 additions & 0 deletions repo/rest-api/specs/resources/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@
"/entities/properties/{property_id}/labels/{language_code}": {
"$ref": "./labels/label-in-language-for-property.json"
},
"/entities/properties/{property_id}/labels_with_language_fallback/{language_code}": {
"$ref": "./labels/label-with-fallback-for-property.json"
},
"/entities/items/{item_id}/aliases": {
"$ref": "./aliases/list-for-item.json"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"get": {
"operationId": "getPropertyLabelWithFallback",
"tags": [ "labels" ],
"summary": "[WIP] Retrieve a Property's label in a specific language, with language fallback",
"description": "This endpoint is currently in development and is not recommended for production use",
"parameters": [
{ "$ref": "../../global/parameters.json#/PropertyId" },
{ "$ref": "../../global/parameters.json#/LanguageCode" },
{ "$ref": "../../global/parameters.json#/IfNoneMatch" },
{ "$ref": "../../global/parameters.json#/IfModifiedSince" },
{ "$ref": "../../global/parameters.json#/IfMatch" },
{ "$ref": "../../global/parameters.json#/IfUnmodifiedSince" },
{ "$ref": "../../global/parameters.json#/Authorization" }
],
"responses": {
"200": { "$ref": "../../global/responses.json#/Label" },
"304": { "$ref": "../../global/responses.json#/NotModified" },
"400": { "$ref": "../../global/responses.json#/InvalidTermByLanguageInput" },
"404": { "$ref": "../../global/responses.json#/ResourceNotFound" },
"412": { "$ref": "../../global/responses.json#/PreconditionFailedError" },
"500": { "$ref": "../../global/responses.json#/UnexpectedError" }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
use Wikibase\Repo\RestApi\Application\UseCases\GetPropertyDescriptions\DeserializedGetPropertyDescriptionsRequest;
use Wikibase\Repo\RestApi\Application\UseCases\GetPropertyLabel\DeserializedGetPropertyLabelRequest;
use Wikibase\Repo\RestApi\Application\UseCases\GetPropertyLabels\DeserializedGetPropertyLabelsRequest;
use Wikibase\Repo\RestApi\Application\UseCases\GetPropertyLabelWithFallback\DeserializedGetPropertyLabelWithFallbackRequest;
use Wikibase\Repo\RestApi\Application\UseCases\GetPropertyStatement\DeserializedGetPropertyStatementRequest;
use Wikibase\Repo\RestApi\Application\UseCases\GetPropertyStatements\DeserializedGetPropertyStatementsRequest;
use Wikibase\Repo\RestApi\Application\UseCases\GetSitelink\DeserializedGetSitelinkRequest;
Expand Down Expand Up @@ -106,6 +107,7 @@ class DeserializedRequestAdapter implements
DeserializedSetItemLabelRequest,
DeserializedSetItemDescriptionRequest,
DeserializedGetPropertyLabelRequest,
DeserializedGetPropertyLabelWithFallbackRequest,
DeserializedGetPropertyDescriptionRequest,
DeserializedSetPropertyDescriptionRequest,
DeserializedPatchPropertyRequest,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php declare( strict_types = 1 );

namespace Wikibase\Repo\RestApi\Application\UseCases\GetPropertyLabelWithFallback;

use Wikibase\Repo\RestApi\Application\UseCaseRequestValidation\DeserializedLanguageCodeRequest;
use Wikibase\Repo\RestApi\Application\UseCaseRequestValidation\DeserializedPropertyIdRequest;

/**
* @license GPL-2.0-or-later
*/
interface DeserializedGetPropertyLabelWithFallbackRequest extends DeserializedPropertyIdRequest, DeserializedLanguageCodeRequest {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php declare( strict_types = 1 );

namespace Wikibase\Repo\RestApi\Application\UseCases\GetPropertyLabelWithFallback;

use Wikibase\Repo\RestApi\Application\UseCases\GetLatestPropertyRevisionMetadata;
use Wikibase\Repo\RestApi\Application\UseCases\UseCaseError;
use Wikibase\Repo\RestApi\Domain\Services\PropertyLabelRetriever;

/**
* @license GPL-2.0-or-later
*/
class GetPropertyLabelWithFallback {

private PropertyLabelRetriever $labelRetriever;
private GetLatestPropertyRevisionMetadata $getRevisionMetadata;
private GetPropertyLabelWithFallbackValidator $validator;

public function __construct(
GetPropertyLabelWithFallbackValidator $validator,
GetLatestPropertyRevisionMetadata $getRevisionMetadata,
PropertyLabelRetriever $labelRetriever
) {
$this->labelRetriever = $labelRetriever;
$this->getRevisionMetadata = $getRevisionMetadata;
$this->validator = $validator;
}

/**
* @throws UseCaseError
*/
public function execute( GetPropertyLabelWithFallbackRequest $request ): GetPropertyLabelWithFallbackResponse {
$deserializedRequest = $this->validator->validateAndDeserialize( $request );
$propertyId = $deserializedRequest->getPropertyId();
$languageCode = $deserializedRequest->getLanguageCode();

[ $revisionId, $lastModified ] = $this->getRevisionMetadata->execute( $propertyId );

$label = $this->labelRetriever->getLabel( $propertyId, $languageCode );
if ( !$label ) {
throw UseCaseError::newResourceNotFound( 'label' );
}

return new GetPropertyLabelWithFallbackResponse( $label, $lastModified, $revisionId );
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php declare( strict_types = 1 );

namespace Wikibase\Repo\RestApi\Application\UseCases\GetPropertyLabelWithFallback;

use Wikibase\Repo\RestApi\Application\UseCaseRequestValidation\LabelLanguageCodeRequest;
use Wikibase\Repo\RestApi\Application\UseCaseRequestValidation\PropertyIdRequest;
use Wikibase\Repo\RestApi\Application\UseCaseRequestValidation\UseCaseRequest;

/**
* @license GPL-2.0-or-later
*/
class GetPropertyLabelWithFallbackRequest implements UseCaseRequest, PropertyIdRequest, LabelLanguageCodeRequest {

private string $propertyId;
private string $languageCode;

public function __construct( string $propertyId, string $languageCode ) {
$this->propertyId = $propertyId;
$this->languageCode = $languageCode;
}

public function getPropertyId(): string {
return $this->propertyId;
}

public function getLanguageCode(): string {
return $this->languageCode;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php declare( strict_types = 1 );

namespace Wikibase\Repo\RestApi\Application\UseCases\GetPropertyLabelWithFallback;

use Wikibase\Repo\RestApi\Domain\ReadModel\Label;

/**
* @license GPL-2.0-or-later
*/
class GetPropertyLabelWithFallbackResponse {

private Label $label;
private string $lastModified;
private int $revisionId;

public function __construct( Label $label, string $lastModified, int $revisionId ) {
$this->label = $label;
$this->lastModified = $lastModified;
$this->revisionId = $revisionId;
}

public function getLabel(): Label {
return $this->label;
}

public function getLastModified(): string {
return $this->lastModified;
}

public function getRevisionId(): int {
return $this->revisionId;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php declare( strict_types = 1 );

namespace Wikibase\Repo\RestApi\Application\UseCases\GetPropertyLabelWithFallback;

use Wikibase\Repo\RestApi\Application\UseCases\UseCaseError;

/**
* @license GPL-2.0-or-later
*/
interface GetPropertyLabelWithFallbackValidator {

/**
* @throws UseCaseError
*/
public function validateAndDeserialize( GetPropertyLabelWithFallbackRequest $request ): DeserializedGetPropertyLabelWithFallbackRequest;

}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
use Wikibase\Repo\RestApi\Application\UseCases\GetPropertyDescriptions\GetPropertyDescriptionsValidator;
use Wikibase\Repo\RestApi\Application\UseCases\GetPropertyLabel\GetPropertyLabelValidator;
use Wikibase\Repo\RestApi\Application\UseCases\GetPropertyLabels\GetPropertyLabelsValidator;
use Wikibase\Repo\RestApi\Application\UseCases\GetPropertyLabelWithFallback\GetPropertyLabelWithFallbackValidator;
use Wikibase\Repo\RestApi\Application\UseCases\GetPropertyStatement\GetPropertyStatementValidator;
use Wikibase\Repo\RestApi\Application\UseCases\GetPropertyStatements\GetPropertyStatementsValidator;
use Wikibase\Repo\RestApi\Application\UseCases\GetSitelink\GetSitelinkValidator;
Expand Down Expand Up @@ -132,6 +133,7 @@ class ValidatingRequestDeserializer implements
SetItemLabelValidator,
SetItemDescriptionValidator,
GetPropertyLabelValidator,
GetPropertyLabelWithFallbackValidator,
GetPropertyDescriptionValidator,
SetPropertyDescriptionValidator,
PatchPropertyLabelsValidator,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php declare( strict_types = 1 );

namespace Wikibase\Repo\RestApi\RouteHandlers;

use MediaWiki\Rest\RequestInterface;
use MediaWiki\Rest\Response;
use MediaWiki\Rest\ResponseInterface;
use MediaWiki\Rest\SimpleHandler;
use MediaWiki\Rest\StringStream;
use Wikibase\Repo\RestApi\Application\UseCases\GetPropertyLabelWithFallback\GetPropertyLabelWithFallback;
use Wikibase\Repo\RestApi\Application\UseCases\GetPropertyLabelWithFallback\GetPropertyLabelWithFallbackRequest;
use Wikibase\Repo\RestApi\Application\UseCases\GetPropertyLabelWithFallback\GetPropertyLabelWithFallbackResponse;
use Wikibase\Repo\RestApi\Application\UseCases\UseCaseError;
use Wikibase\Repo\RestApi\RouteHandlers\Middleware\AuthenticationMiddleware;
use Wikibase\Repo\RestApi\RouteHandlers\Middleware\MiddlewareHandler;
use Wikibase\Repo\RestApi\RouteHandlers\Middleware\UserAgentCheckMiddleware;
use Wikibase\Repo\RestApi\WbRestApi;
use Wikimedia\ParamValidator\ParamValidator;
use function json_encode;

/**
* @license GPL-2.0-or-later
*/
class GetPropertyLabelWithFallbackRouteHandler extends SimpleHandler {

private const PROPERTY_ID_PATH_PARAM = 'property_id';
private const LANGUAGE_CODE_PATH_PARAM = 'language_code';

private GetPropertyLabelWithFallback $useCase;
private MiddlewareHandler $middlewareHandler;
private ResponseFactory $responseFactory;

public function __construct(
GetPropertyLabelWithFallback $useCase,
MiddlewareHandler $middlewareHandler,
ResponseFactory $responseFactory
) {
$this->useCase = $useCase;
$this->middlewareHandler = $middlewareHandler;
$this->responseFactory = $responseFactory;
}

public static function factory(): self {
$responseFactory = new ResponseFactory();
return new self(
WbRestApi::getGetPropertyLabelWithFallback(),
new MiddlewareHandler( [
WbRestApi::getUnexpectedErrorHandlerMiddleware(),
new UserAgentCheckMiddleware(),
new AuthenticationMiddleware(),
WbRestApi::getPreconditionMiddlewareFactory()->newPreconditionMiddleware(
fn( RequestInterface $request ): string => $request->getPathParam( self::PROPERTY_ID_PATH_PARAM )
),
] ),
$responseFactory
);
}

/**
* @param mixed ...$args
*/
public function run( ...$args ): Response {
return $this->middlewareHandler->run( $this, [ $this, 'runUseCase' ], $args );
}

public function runUseCase( string $propertyId, string $languageCode ): Response {
try {
$useCaseResponse = $this->useCase->execute( new GetPropertyLabelWithFallbackRequest( $propertyId, $languageCode ) );
return $this->newSuccessResponse( $useCaseResponse );
} catch ( UseCaseError $e ) {
return $this->responseFactory->newErrorResponseFromException( $e );
}
}

public function getParamSettings(): array {
return [
self::PROPERTY_ID_PATH_PARAM => [
self::PARAM_SOURCE => 'path',
ParamValidator::PARAM_TYPE => 'string',
ParamValidator::PARAM_REQUIRED => true,
],
self::LANGUAGE_CODE_PATH_PARAM => [
self::PARAM_SOURCE => 'path',
ParamValidator::PARAM_TYPE => 'string',
ParamValidator::PARAM_REQUIRED => true,
],
];
}

private function newSuccessResponse( GetPropertyLabelWithFallbackResponse $useCaseResponse ): Response {
$httpResponse = $this->getResponseFactory()->create();
$httpResponse->setHeader( 'Content-Type', 'application/json' );
$httpResponse->setHeader( 'Last-Modified', wfTimestamp( TS_RFC2822, $useCaseResponse->getLastModified() ) );
$httpResponse->setHeader( 'ETag', "\"{$useCaseResponse->getRevisionId()}\"" );
$httpResponse->setBody(
new StringStream( json_encode( $useCaseResponse->getLabel()->getText() ) )
);

return $httpResponse;
}

/**
* @inheritDoc
*/
public function needsWriteAccess(): bool {
return false;
}

/**
* Preconditions are checked via {@link PreconditionMiddleware}
*/
public function checkPreconditions(): ?ResponseInterface {
return null;
}

}
53 changes: 53 additions & 0 deletions repo/rest-api/src/RouteHandlers/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -2555,6 +2555,59 @@
}
}
},
"/entities/properties/{property_id}/labels_with_language_fallback/{language_code}": {
"get": {
"operationId": "getPropertyLabelWithFallback",
"tags": [
"labels"
],
"summary": "[WIP] Retrieve a Property's label in a specific language, with language fallback",
"description": "This endpoint is currently in development and is not recommended for production use",
"parameters": [
{
"$ref": "#/components/parameters/PropertyId"
},
{
"$ref": "#/components/parameters/LanguageCode"
},
{
"$ref": "#/components/parameters/IfNoneMatch"
},
{
"$ref": "#/components/parameters/IfModifiedSince"
},
{
"$ref": "#/components/parameters/IfMatch"
},
{
"$ref": "#/components/parameters/IfUnmodifiedSince"
},
{
"$ref": "#/components/parameters/Authorization"
}
],
"responses": {
"200": {
"$ref": "#/components/responses/Label"
},
"304": {
"$ref": "#/components/responses/NotModified"
},
"400": {
"$ref": "#/components/responses/InvalidTermByLanguageInput"
},
"404": {
"$ref": "#/components/responses/ResourceNotFound"
},
"412": {
"$ref": "#/components/responses/PreconditionFailedError"
},
"500": {
"$ref": "#/components/responses/UnexpectedError"
}
}
}
},
"/entities/items/{item_id}/aliases": {
"get": {
"operationId": "getItemAliases",
Expand Down
Loading

0 comments on commit 27ddce7

Please sign in to comment.