diff options
author | Jon Bratseth <bratseth@oath.com> | 2019-04-29 11:41:50 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-29 11:41:50 +0200 |
commit | d26962c2102e9b38004035bb9876326d1c92722f (patch) | |
tree | 420b0c331590f6de40d0a2bdca8749f871236dd7 | |
parent | c9f9f467df69a65fe1a403f58411259e3c0fa823 (diff) | |
parent | 8cbc4e04c8caf10222e00e203cc8e0b1ea569087 (diff) |
Merge pull request #9220 from vespa-engine/bratseth/document-api-dont-blame-users
Bratseth/document api dont blame users
12 files changed, 137 insertions, 91 deletions
diff --git a/document/src/main/java/com/yahoo/document/TestAndSetCondition.java b/document/src/main/java/com/yahoo/document/TestAndSetCondition.java index 78e75ba8e95..767fd6672d4 100644 --- a/document/src/main/java/com/yahoo/document/TestAndSetCondition.java +++ b/document/src/main/java/com/yahoo/document/TestAndSetCondition.java @@ -16,6 +16,7 @@ import java.util.Optional; */ @Beta public class TestAndSetCondition { + public static final TestAndSetCondition NOT_PRESENT_CONDITION = new TestAndSetCondition(); private final String conditionStr; @@ -33,9 +34,9 @@ public class TestAndSetCondition { public boolean isPresent() { return !conditionStr.isEmpty(); } /** - * Maps and optional test and set conditiong string to a TestAndSetCondition. + * Maps and optional test and set condition string to a TestAndSetCondition. * If the condition string is not present, a "not present" condition is returned - * @param conditionString test and set conditiong string (document selection) + * @param conditionString test and set condition string (document selection) * @return a TestAndSetCondition representing the condition string or a "not present" condition */ public static TestAndSetCondition fromConditionString(Optional<String> conditionString) { @@ -43,4 +44,5 @@ public class TestAndSetCondition { .map(TestAndSetCondition::new) .orElse(TestAndSetCondition.NOT_PRESENT_CONDITION); } + } diff --git a/document/src/main/java/com/yahoo/document/json/JsonFeedReader.java b/document/src/main/java/com/yahoo/document/json/JsonFeedReader.java index be4aa6cfb41..5da6b58ac98 100644 --- a/document/src/main/java/com/yahoo/document/json/JsonFeedReader.java +++ b/document/src/main/java/com/yahoo/document/json/JsonFeedReader.java @@ -52,7 +52,7 @@ public class JsonFeedReader implements FeedReader { } else if (documentOperation instanceof DocumentPut) { return new DocumentFeedOperation(((DocumentPut) documentOperation).getDocument(), documentOperation.getCondition()); } else { - throw new IllegalStateException("Got unknown class from JSON reader: " + documentOperation.getClass().getName()); + throw new IllegalArgumentException("Got unknown class from JSON reader: " + documentOperation.getClass().getName()); } } diff --git a/document/src/main/java/com/yahoo/document/json/JsonReader.java b/document/src/main/java/com/yahoo/document/json/JsonReader.java index d512fd3a6d1..79e435b6d9d 100644 --- a/document/src/main/java/com/yahoo/document/json/JsonReader.java +++ b/document/src/main/java/com/yahoo/document/json/JsonReader.java @@ -49,7 +49,7 @@ public class JsonReader { parser = parserFactory.createParser(input); } catch (IOException e) { state = END_OF_FEED; - throw new RuntimeException(e); + throw new IllegalArgumentException(e); } } @@ -61,13 +61,13 @@ public class JsonReader { */ public DocumentOperation readSingleDocument(DocumentParser.SupportedOperation operationType, String docIdString) { DocumentId docId = new DocumentId(docIdString); - final DocumentParseInfo documentParseInfo; + DocumentParseInfo documentParseInfo; try { DocumentParser documentParser = new DocumentParser(parser); documentParseInfo = documentParser.parse(Optional.of(docId)).get(); } catch (IOException e) { state = END_OF_FEED; - throw new RuntimeException(e); + throw new IllegalArgumentException(e); } documentParseInfo.operationType = operationType; VespaJsonDocumentReader vespaJsonDocumentReader = new VespaJsonDocumentReader(); @@ -96,9 +96,9 @@ public class JsonReader { } catch (IOException r) { // Jackson is not able to recover from structural parse errors state = END_OF_FEED; - throw new RuntimeException(r); + throw new IllegalArgumentException(r); } - if (! documentParseInfo.isPresent()) { + if ( ! documentParseInfo.isPresent()) { state = END_OF_FEED; return null; } @@ -117,9 +117,8 @@ public class JsonReader { private static DocumentType getDocumentTypeFromString(String docTypeString, DocumentTypeManager typeManager) { final DocumentType docType = typeManager.getDocumentType(docTypeString); - if (docType == null) { + if (docType == null) throw new IllegalArgumentException(String.format("Document type %s does not exist", docTypeString)); - } return docType; } @@ -129,7 +128,7 @@ public class JsonReader { } catch (IOException e) { // Jackson is not able to recover from structural parse errors state = END_OF_FEED; - throw new RuntimeException(e); + throw new IllegalArgumentException(e); } } } diff --git a/document/src/main/java/com/yahoo/document/json/JsonReaderException.java b/document/src/main/java/com/yahoo/document/json/JsonReaderException.java index f919d00d20c..2363df30374 100644 --- a/document/src/main/java/com/yahoo/document/json/JsonReaderException.java +++ b/document/src/main/java/com/yahoo/document/json/JsonReaderException.java @@ -7,7 +7,8 @@ import com.yahoo.document.Field; /** * @author bjorncs */ -public class JsonReaderException extends RuntimeException { +public class JsonReaderException extends IllegalArgumentException { + public final DocumentId docId; public final Field field; public final Throwable cause; @@ -32,7 +33,7 @@ public class JsonReaderException extends RuntimeException { private static String createErrorMessage(DocumentId docId, Field field, Throwable cause) { return String.format("Error in document '%s' - could not parse field '%s' of type '%s': %s", - docId, field.getName(), field.getDataType().getName(), cause.getMessage()); + docId, field.getName(), field.getDataType().getName(), cause.getMessage()); } public DocumentId getDocId() { @@ -42,4 +43,5 @@ public class JsonReaderException extends RuntimeException { public Field getField() { return field; } + } diff --git a/document/src/main/java/com/yahoo/document/json/SingleDocumentParser.java b/document/src/main/java/com/yahoo/document/json/SingleDocumentParser.java index 28aa9ed1d8d..b57b55c9d73 100644 --- a/document/src/main/java/com/yahoo/document/json/SingleDocumentParser.java +++ b/document/src/main/java/com/yahoo/document/json/SingleDocumentParser.java @@ -20,6 +20,7 @@ import java.io.InputStream; * @author dybis */ public class SingleDocumentParser { + private static final JsonFactory jsonFactory = new JsonFactory().disable(JsonFactory.Feature.CANONICALIZE_FIELD_NAMES); private DocumentTypeManager docMan; @@ -36,12 +37,12 @@ public class SingleDocumentParser { } private FeedOperation parse(InputStream inputStream, String docId, DocumentParser.SupportedOperation supportedOperation) { - final JsonReader reader = new JsonReader(docMan, inputStream, jsonFactory); - final DocumentOperation documentOperation = reader.readSingleDocument(supportedOperation, docId); + JsonReader reader = new JsonReader(docMan, inputStream, jsonFactory); + DocumentOperation documentOperation = reader.readSingleDocument(supportedOperation, docId); try { inputStream.close(); } catch (IOException e) { - throw new RuntimeException(e); + throw new IllegalStateException(e); } if (supportedOperation == DocumentParser.SupportedOperation.PUT) { return new DocumentFeedOperation(((DocumentPut) documentOperation).getDocument(), documentOperation.getCondition()); @@ -49,4 +50,5 @@ public class SingleDocumentParser { return new DocumentUpdateFeedOperation((DocumentUpdate) documentOperation, documentOperation.getCondition()); } } + } diff --git a/document/src/main/java/com/yahoo/document/json/readers/AddRemoveCreator.java b/document/src/main/java/com/yahoo/document/json/readers/AddRemoveCreator.java index a5af14a1cde..73be43ca9d9 100644 --- a/document/src/main/java/com/yahoo/document/json/readers/AddRemoveCreator.java +++ b/document/src/main/java/com/yahoo/document/json/readers/AddRemoveCreator.java @@ -60,7 +60,7 @@ public class AddRemoveCreator { List<FieldValue> arrayContents = new ArrayList<>(); ArrayReader.fillArrayUpdate(buffer, initNesting, valueType, arrayContents); if (buffer.currentToken() != JsonToken.END_ARRAY) { - throw new IllegalStateException("Expected END_ARRAY. Got '" + buffer.currentToken() + "'."); + throw new IllegalArgumentException("Expected END_ARRAY. Got '" + buffer.currentToken() + "'."); } if (isRemove) { singleUpdate = FieldUpdate.createRemoveAll(field, arrayContents); diff --git a/document/src/main/java/com/yahoo/document/json/readers/JsonParserHelpers.java b/document/src/main/java/com/yahoo/document/json/readers/JsonParserHelpers.java index e3bfdb7bb2c..6339add222e 100644 --- a/document/src/main/java/com/yahoo/document/json/readers/JsonParserHelpers.java +++ b/document/src/main/java/com/yahoo/document/json/readers/JsonParserHelpers.java @@ -6,27 +6,59 @@ import com.fasterxml.jackson.core.JsonToken; import com.google.common.base.Preconditions; public class JsonParserHelpers { + public static void expectArrayStart(JsonToken token) { - Preconditions.checkState(token == JsonToken.START_ARRAY, "Expected start of array, got %s", token); + try { + Preconditions.checkState(token == JsonToken.START_ARRAY, "Expected start of array, got %s", token); + } + catch (IllegalStateException e) { + throw new IllegalArgumentException(e); + } } public static void expectArrayEnd(JsonToken token) { - Preconditions.checkState(token == JsonToken.END_ARRAY, "Expected start of array, got %s", token); + try { + Preconditions.checkState(token == JsonToken.END_ARRAY, "Expected start of array, got %s", token); + } + catch (IllegalStateException e) { + throw new IllegalArgumentException(e); + } } public static void expectObjectStart(JsonToken token) { - Preconditions.checkState(token == JsonToken.START_OBJECT, "Expected start of JSON object, got %s", token); + try { + Preconditions.checkState(token == JsonToken.START_OBJECT, "Expected start of JSON object, got %s", token); + } + catch (IllegalStateException e) { + throw new IllegalArgumentException(e); + } } public static void expectObjectEnd(JsonToken token) { - Preconditions.checkState(token == JsonToken.END_OBJECT, "Expected end of JSON object, got %s", token); + try { + Preconditions.checkState(token == JsonToken.END_OBJECT, "Expected end of JSON object, got %s", token); + } + catch (IllegalStateException e) { + throw new IllegalArgumentException(e); + } } public static void expectCompositeEnd(JsonToken token) { - Preconditions.checkState(token.isStructEnd(), "Expected end of composite, got %s", token); + try { + Preconditions.checkState(token.isStructEnd(), "Expected end of composite, got %s", token); + } + catch (IllegalStateException e) { + throw new IllegalArgumentException(e); + } } public static void expectScalarValue(JsonToken token) { - Preconditions.checkState(token.isScalarValue(), "Expected to be scalar value, got %s", token); + try { + Preconditions.checkState(token.isScalarValue(), "Expected to be scalar value, got %s", token); + } + catch (IllegalStateException e) { + throw new IllegalArgumentException(e); + } } + } diff --git a/document/src/main/java/com/yahoo/document/json/readers/StructReader.java b/document/src/main/java/com/yahoo/document/json/readers/StructReader.java index cab55903b76..dc2c001672d 100644 --- a/document/src/main/java/com/yahoo/document/json/readers/StructReader.java +++ b/document/src/main/java/com/yahoo/document/json/readers/StructReader.java @@ -11,6 +11,7 @@ import com.yahoo.document.json.TokenBuffer; import static com.yahoo.document.json.readers.SingleValueReader.readSingleValue; public class StructReader { + public static void fillStruct(TokenBuffer buffer, StructuredFieldValue parent) { // do note the order of initializing initNesting and token is relevant for empty docs int initNesting = buffer.nesting(); @@ -32,12 +33,11 @@ public class StructReader { } public static Field getField(TokenBuffer buffer, StructuredFieldValue parent) { - Field f = parent.getField(buffer.currentName()); - if (f == null) { - throw new NullPointerException("Could not get field \"" + buffer.currentName() + - "\" in the structure of type \"" + parent.getDataType().getDataTypeName() + "\"."); - } - return f; + Field field = parent.getField(buffer.currentName()); + if (field == null) + throw new IllegalArgumentException("No field '" + buffer.currentName() + "' in the structure of type '" + + parent.getDataType().getDataTypeName() + "'"); + return field; } } diff --git a/document/src/main/java/com/yahoo/document/json/readers/VespaJsonDocumentReader.java b/document/src/main/java/com/yahoo/document/json/readers/VespaJsonDocumentReader.java index 2aeab67f290..e252e71407a 100644 --- a/document/src/main/java/com/yahoo/document/json/readers/VespaJsonDocumentReader.java +++ b/document/src/main/java/com/yahoo/document/json/readers/VespaJsonDocumentReader.java @@ -40,6 +40,7 @@ import static com.yahoo.document.json.readers.TensorRemoveUpdateReader.createTen * @author freva */ public class VespaJsonDocumentReader { + private static final String UPDATE_REMOVE = "remove"; private static final String UPDATE_ADD = "add"; @@ -67,8 +68,8 @@ public class VespaJsonDocumentReader { throw JsonReaderException.addDocId(e, documentParseInfo.documentId); } if (documentParseInfo.create.isPresent()) { - if (!(documentOperation instanceof DocumentUpdate)) { - throw new RuntimeException("Could not set create flag on non update operation."); + if (! ( documentOperation instanceof DocumentUpdate)) { + throw new IllegalArgumentException("Could not set create flag on non update operation."); } DocumentUpdate update = (DocumentUpdate) documentOperation; update.setCreateIfNonExistent(documentParseInfo.create.get()); diff --git a/document/src/test/java/com/yahoo/document/json/JsonReaderTestCase.java b/document/src/test/java/com/yahoo/document/json/JsonReaderTestCase.java index 15d1e859f73..9df7d1f91c1 100644 --- a/document/src/test/java/com/yahoo/document/json/JsonReaderTestCase.java +++ b/document/src/test/java/com/yahoo/document/json/JsonReaderTestCase.java @@ -914,16 +914,17 @@ public class JsonReaderTestCase { } @Test - public final void misspelledFieldTest() throws IOException{ - JsonReader r = createReader(inputJson("{ 'put': 'id:unittest:smoke::whee',", + public void misspelledFieldTest() throws IOException{ + JsonReader r = createReader(inputJson( + "{ 'put': 'id:unittest:smoke::whee',", " 'fields': {", " 'smething': 'smoketest',", " 'nalle': 'bamse' }}")); DocumentParseInfo parseInfo = r.parseDocument().get(); DocumentType docType = r.readDocumentType(parseInfo.documentId); DocumentPut put = new DocumentPut(new Document(docType, parseInfo.documentId)); - exception.expect(NullPointerException.class); - exception.expectMessage("Could not get field \"smething\" in the structure of type \"smoke\"."); + exception.expect(IllegalArgumentException.class); + exception.expectMessage("No field 'smething' in the structure of type 'smoke'"); new VespaJsonDocumentReader().readPut(parseInfo.fieldsBuffer, put); } @@ -954,9 +955,9 @@ public class JsonReaderTestCase { } private void testFeedWithTestAndSetCondition(String jsonDoc) { - final ByteArrayInputStream parseInfoDoc = new ByteArrayInputStream(Utf8.toBytes(jsonDoc)); - final JsonReader reader = new JsonReader(types, parseInfoDoc, parserFactory); - final int NUM_OPERATIONS_IN_FEED = 3; + ByteArrayInputStream parseInfoDoc = new ByteArrayInputStream(Utf8.toBytes(jsonDoc)); + JsonReader reader = new JsonReader(types, parseInfoDoc, parserFactory); + int NUM_OPERATIONS_IN_FEED = 3; for (int i = 0; i < NUM_OPERATIONS_IN_FEED; i++) { DocumentOperation operation = reader.next(); @@ -1005,7 +1006,7 @@ public class JsonReaderTestCase { } @Test - public final void testFeedWithTestAndSetConditionOrderingTwo() { + public void testFeedWithTestAndSetConditionOrderingTwo() { testFeedWithTestAndSetCondition( inputJson("[", " {", @@ -1037,7 +1038,7 @@ public class JsonReaderTestCase { } @Test - public final void testFeedWithTestAndSetConditionOrderingThree() { + public void testFeedWithTestAndSetConditionOrderingThree() { testFeedWithTestAndSetCondition( inputJson("[", " {", @@ -1108,7 +1109,7 @@ public class JsonReaderTestCase { @Test(expected = IllegalArgumentException.class) public void testInvalidFieldWithoutFieldsFieldShouldFailParse() { - final String jsonData = inputJson( + String jsonData = inputJson( "[", " {", " 'remove': 'id:unittest:smoke::whee',", diff --git a/vespaclient-container-plugin/src/main/java/com/yahoo/document/restapi/resource/RestApi.java b/vespaclient-container-plugin/src/main/java/com/yahoo/document/restapi/resource/RestApi.java index 873b0569553..b4992fb519b 100644 --- a/vespaclient-container-plugin/src/main/java/com/yahoo/document/restapi/resource/RestApi.java +++ b/vespaclient-container-plugin/src/main/java/com/yahoo/document/restapi/resource/RestApi.java @@ -36,6 +36,7 @@ import com.yahoo.vespaclient.ClusterList; import com.yahoo.vespaxmlparser.DocumentFeedOperation; import com.yahoo.vespaxmlparser.FeedOperation; import com.yahoo.vespaxmlparser.VespaXMLFeedReader; +import com.yahoo.yolean.Exceptions; import java.io.IOException; import java.io.OutputStream; @@ -79,16 +80,14 @@ public class RestApi extends LoggingRequestHandler { public RestApi(LoggingRequestHandler.Context parentCtx, DocumentmanagerConfig documentManagerConfig, LoadTypeConfig loadTypeConfig, ThreadpoolConfig threadpoolConfig, AllClustersBucketSpacesConfig bucketSpacesConfig, - ClusterListConfig clusterListConfig, MetricReceiver metricReceiver) - { + ClusterListConfig clusterListConfig, MetricReceiver metricReceiver) { super(parentCtx); MessageBusParams params = new MessageBusParams(new LoadTypeSet(loadTypeConfig)); params.setDocumentmanagerConfig(documentManagerConfig); - this.operationHandler = new OperationHandlerImpl( - new MessageBusDocumentAccess(params), - fixedClusterEnumeratorFromConfig(clusterListConfig), - fixedBucketSpaceResolverFromConfig(bucketSpacesConfig), - metricReceiver); + this.operationHandler = new OperationHandlerImpl(new MessageBusDocumentAccess(params), + fixedClusterEnumeratorFromConfig(clusterListConfig), + fixedBucketSpaceResolverFromConfig(bucketSpacesConfig), + metricReceiver); this.singleDocumentParser = new SingleDocumentParser(new DocumentTypeManager(documentManagerConfig)); // 40% of the threads can be blocked before we deny requests. if (threadpoolConfig != null) { @@ -100,11 +99,10 @@ public class RestApi extends LoggingRequestHandler { } // For testing and development - public RestApi( - Executor executor, - AccessLog accessLog, - OperationHandler operationHandler, - int threadsAvailable) { + public RestApi(Executor executor, + AccessLog accessLog, + OperationHandler operationHandler, + int threadsAvailable) { super(executor, accessLog, null); this.operationHandler = operationHandler; this.threadsAvailableForApi = new AtomicInteger(threadsAvailable); @@ -121,12 +119,11 @@ public class RestApi extends LoggingRequestHandler { } private static OperationHandlerImpl.ClusterEnumerator fixedClusterEnumeratorFromConfig(ClusterListConfig config) { - final List<ClusterDef> clusters = Collections.unmodifiableList(new ClusterList(config).getStorageClusters()); + List<ClusterDef> clusters = Collections.unmodifiableList(new ClusterList(config).getStorageClusters()); return () -> clusters; } - private static OperationHandlerImpl.BucketSpaceResolver fixedBucketSpaceResolverFromConfig( - AllClustersBucketSpacesConfig bucketSpacesConfig) { + private static OperationHandlerImpl.BucketSpaceResolver fixedBucketSpaceResolverFromConfig(AllClustersBucketSpacesConfig bucketSpacesConfig) { return (clusterId, docType) -> Optional.ofNullable(bucketSpacesConfig.cluster(clusterId)) .map(cluster -> cluster.documentType(docType)) @@ -134,7 +131,7 @@ public class RestApi extends LoggingRequestHandler { } private static Optional<String> requestProperty(String parameter, HttpRequest request) { - final String property = request.getProperty(parameter); + String property = request.getProperty(parameter); if (property != null && ! property.isEmpty()) { return Optional.of(property); } @@ -151,8 +148,15 @@ public class RestApi extends LoggingRequestHandler { } private static Optional<Boolean> parseBoolean(String parameter, HttpRequest request) { - Optional<String> property = requestProperty(parameter, request); - return property.map(RestApi::parseBooleanStrict); + try { + Optional<String> property = requestProperty(parameter, request); + return property.map(RestApi::parseBooleanStrict); + } + catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Invalid value for '" + parameter + "' parameter: " + + "Must be empty, true, or false but was '" + + request.getProperty(parameter) + "'"); + } } private static int parsePositiveInt(String str) throws NumberFormatException { @@ -167,9 +171,9 @@ public class RestApi extends LoggingRequestHandler { public HttpResponse handle(HttpRequest request) { try { if (threadsAvailableForApi.decrementAndGet() < 1) { - return Response.createErrorResponse( - 429 /* Too Many Requests */, - "Too many parallel requests, consider using http-vespa-java-client. Please try again later.", RestUri.apiErrorCodes.TOO_MANY_PARALLEL_REQUESTS); + return Response.createErrorResponse(429 /* Too Many Requests */, + "Too many parallel requests, consider using http-vespa-java-client. Please try again later.", + RestUri.apiErrorCodes.TOO_MANY_PARALLEL_REQUESTS); } return handleInternal(request); } finally { @@ -177,11 +181,12 @@ public class RestApi extends LoggingRequestHandler { } } - private static void validateUriStructureForRequestMethod(RestUri uri, com.yahoo.jdisc.http.HttpRequest.Method method) throws RestApiException { + private static void validateUriStructureForRequestMethod(RestUri uri, com.yahoo.jdisc.http.HttpRequest.Method method) + throws RestApiException { if ((method != com.yahoo.jdisc.http.HttpRequest.Method.GET) && uri.isRootOnly()) { throw new RestApiException(Response.createErrorResponse(BAD_REQUEST, - "Root /document/v1/ requests only supported for HTTP GET", - RestUri.apiErrorCodes.ERROR_ID_BASIC_USAGE)); + "Root /document/v1/ requests only supported for HTTP GET", + RestUri.apiErrorCodes.ERROR_ID_BASIC_USAGE)); } } @@ -191,28 +196,23 @@ public class RestApi extends LoggingRequestHandler { // protected for testing protected HttpResponse handleInternal(HttpRequest request) { - final RestUri restUri; + RestUri restUri = null; try { restUri = new RestUri(request.getUri()); validateUriStructureForRequestMethod(restUri, request.getMethod()); - } catch (RestApiException e) { - return e.getResponse(); - } catch (Exception e2) { - return Response.createErrorResponse(500, "Exception while parsing URI: " + e2.getMessage(), RestUri.apiErrorCodes.URL_PARSING); - } - final Optional<Boolean> create; - try { - create = parseBoolean(CREATE_PARAMETER_NAME, request); - } catch (IllegalArgumentException e) { - return Response.createErrorResponse(400, "Non valid value for 'create' parameter, must be empty, true, or " + - "false: " + request.getProperty(CREATE_PARAMETER_NAME), RestUri.apiErrorCodes.INVALID_CREATE_VALUE); - } - String condition = request.getProperty(CONDITION_PARAMETER_NAME); - Optional<String> route = Optional.ofNullable(request.getProperty(ROUTE_PARAMETER_NAME)); + Optional<Boolean> create; + try { + create = parseBoolean(CREATE_PARAMETER_NAME, request); + } + catch (IllegalArgumentException e) { + return Response.createErrorResponse(400, e.getMessage(), RestUri.apiErrorCodes.INVALID_CREATE_VALUE); + } - Optional<ObjectNode> resultJson = Optional.empty(); - try { + String condition = request.getProperty(CONDITION_PARAMETER_NAME); + Optional<String> route = Optional.ofNullable(request.getProperty(ROUTE_PARAMETER_NAME)); + + Optional<ObjectNode> resultJson = Optional.empty(); switch (request.getMethod()) { case GET: // Vespa Visit/Get return isVisitRequestUri(restUri) ? handleVisit(restUri, request) : handleGet(restUri, request); @@ -228,14 +228,21 @@ public class RestApi extends LoggingRequestHandler { default: return new Response(405, Optional.empty(), Optional.of(restUri)); } - } catch (RestApiException e) { + return new Response(200, resultJson, Optional.of(restUri)); + } + catch (RestApiException e) { return e.getResponse(); - } catch (Exception e2) { - // We always blame the user. This might be a bit nasty, but the parser throws various kind of exception - // types, but with nice descriptions. - return Response.createErrorResponse(400, e2.getMessage(), restUri, RestUri.apiErrorCodes.PARSER_ERROR); } - return new Response(200, resultJson, Optional.of(restUri)); + catch (IllegalArgumentException userException) { + return Response.createErrorResponse(400, Exceptions.toMessageString(userException), + restUri, + RestUri.apiErrorCodes.PARSER_ERROR); + } + catch (RuntimeException systemException) { + return Response.createErrorResponse(500, Exceptions.toMessageString(systemException), + restUri, + RestUri.apiErrorCodes.UNSPECIFIED); + } } private FeedOperation createPutOperation(HttpRequest request, String id, String condition) { @@ -401,8 +408,8 @@ public class RestApi extends LoggingRequestHandler { } catch (BadRequestParameterException e) { return createInvalidParameterResponse(e.getParameter(), e.getMessage()); } - final OperationHandler.VisitResult visit = operationHandler.visit(restUri, documentSelection, options); - final ObjectNode resultNode = mapper.createObjectNode(); + OperationHandler.VisitResult visit = operationHandler.visit(restUri, documentSelection, options); + ObjectNode resultNode = mapper.createObjectNode(); visit.token.ifPresent(t -> resultNode.put(CONTINUATION, t)); resultNode.putArray(DOCUMENTS).addPOJO(visit.documentsAsJsonList); resultNode.put(PATH_NAME, restUri.getRawPath()); diff --git a/vespaclient-container-plugin/src/test/java/com/yahoo/document/restapi/resource/RestApiTest.java b/vespaclient-container-plugin/src/test/java/com/yahoo/document/restapi/resource/RestApiTest.java index 94bc8deb47a..773d45b6b18 100644 --- a/vespaclient-container-plugin/src/test/java/com/yahoo/document/restapi/resource/RestApiTest.java +++ b/vespaclient-container-plugin/src/test/java/com/yahoo/document/restapi/resource/RestApiTest.java @@ -197,7 +197,7 @@ public class RestApiTest { HttpPut httpPut = new HttpPut(request.getUri()); StringEntity entity = new StringEntity(update_test_doc, ContentType.create("application/json")); httpPut.setEntity(entity); - assertHttp400ResponseContains(doRest(httpPut), "Non valid value for 'create' parameter, must be empty, true, or false: batman"); + assertHttp400ResponseContains(doRest(httpPut), "Invalid value for 'create' parameter: Must be empty, true, or false but was 'batman'"); } // Get logs through some hackish fetch method. Logs is something the mocked backend write. |