diff --git a/src/main/java/io/stargate/sgv2/jsonapi/api/configuration/CommandObjectMapperHandler.java b/src/main/java/io/stargate/sgv2/jsonapi/api/configuration/CommandObjectMapperHandler.java index 7869ed6fc5..caee2bf9ee 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/api/configuration/CommandObjectMapperHandler.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/api/configuration/CommandObjectMapperHandler.java @@ -1,13 +1,35 @@ package io.stargate.sgv2.jsonapi.api.configuration; +import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler; import com.fasterxml.jackson.databind.jsontype.TypeIdResolver; import io.stargate.sgv2.jsonapi.exception.ErrorCode; import io.stargate.sgv2.jsonapi.exception.JsonApiException; +import java.io.IOException; public class CommandObjectMapperHandler extends DeserializationProblemHandler { + + @Override + public boolean handleUnknownProperty( + DeserializationContext ctxt, + JsonParser p, + JsonDeserializer deserializer, + Object beanOrClass, + String propertyName) + throws IOException { + if (deserializer.handledType().toString().endsWith("CreateCollectionCommand$Options")) { + throw ErrorCode.INVALID_CREATE_COLLECTION_OPTIONS.toApiException( + "No option \"%s\" found as createCollectionCommand option (known options: \"indexing\", \"vector\")", + propertyName); + } + // false means if not matched by above handle logic, object mapper will + // FAIL_ON_UNKNOWN_PROPERTIES. + return false; + } + @Override public JavaType handleUnknownTypeId( DeserializationContext ctxt, diff --git a/src/main/java/io/stargate/sgv2/jsonapi/exception/ErrorCode.java b/src/main/java/io/stargate/sgv2/jsonapi/exception/ErrorCode.java index 7f0352aa8d..2dd34bed11 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/exception/ErrorCode.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/exception/ErrorCode.java @@ -5,6 +5,7 @@ public enum ErrorCode { /** Command error codes. */ COUNT_READ_FAILED("Unable to count documents"), COMMAND_NOT_IMPLEMENTED("The provided command is not implemented."), + INVALID_CREATE_COLLECTION_OPTIONS("The provided options are invalid"), NO_COMMAND_MATCHED("Unable to find the provided command"), COMMAND_ACCEPTS_NO_OPTIONS("Command accepts no options"), diff --git a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/CreateCollectionIntegrationTest.java b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/CreateCollectionIntegrationTest.java index 5e3dbe5ee7..33b0bf3619 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/CreateCollectionIntegrationTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/CreateCollectionIntegrationTest.java @@ -508,6 +508,36 @@ public void failWithInvalidNameInIndexingDeny() { .body("errors[0].errorCode", is("INVALID_INDEXING_DEFINITION")) .body("errors[0].exceptionClass", is("JsonApiException")); } + + @Test + public void failWithInvalidOption() { + given() + .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) + .contentType(ContentType.JSON) + .body( + """ + { + "createCollection": { + "name": "collection_with_invalid_option", + "options" : { + "InDex" : {} + } + } + } + """) + .when() + .post(NamespaceResource.BASE_PATH, namespaceName) + .then() + .statusCode(200) + .body("status", is(nullValue())) + .body("data", is(nullValue())) + .body( + "errors[0].message", + startsWith( + "The provided options are invalid: No option \"InDex\" found as createCollectionCommand option (known options: \"indexing\", \"vector\")")) + .body("errors[0].errorCode", is("INVALID_CREATE_COLLECTION_OPTIONS")) + .body("errors[0].exceptionClass", is("JsonApiException")); + } } private void deleteCollection(String collectionName) {