This is an automated email from the ASF dual-hosted git repository. xiangfu pushed a commit to branch fixing_post_requests in repository https://gitbox.apache.org/repos/asf/incubator-pinot.git
commit 46f8da502420d2663fa9a861517d25770f07a752 Author: Xiang Fu <[email protected]> AuthorDate: Tue Sep 24 15:09:51 2019 -0700 Support HTTP POST JSON schema --- .../api/resources/PinotSchemaRestletResource.java | 51 +++++++++++++++++++++- .../api/PinotSchemaRestletResourceTest.java | 32 ++++++++++++++ .../pinot/controller/helix/ControllerTest.java | 11 +++++ 3 files changed, 92 insertions(+), 2 deletions(-) diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotSchemaRestletResource.java b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotSchemaRestletResource.java index 82a4841..8f3c221 100644 --- a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotSchemaRestletResource.java +++ b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotSchemaRestletResource.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.Map; import javax.annotation.Nullable; import javax.inject.Inject; +import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; @@ -120,16 +121,38 @@ public class PinotSchemaRestletResource { return addOrUpdateSchema(schemaName, multiPart); } + @PUT + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + @Path("/schemas/{schemaName}") + @ApiOperation(value = "Update a schema", notes = "Updates a schema") + @ApiResponses(value = {@ApiResponse(code = 200, message = "Successfully updated schema"), @ApiResponse(code = 404, message = "Schema not found"), @ApiResponse(code = 400, message = "Missing or invalid request body"), @ApiResponse(code = 500, message = "Internal error")}) + public SuccessResponse updateSchema(@ApiParam(value = "Name of the schema", required = true) @PathParam("schemaName") String schemaName, + Schema schema) { + return addOrUpdateSchema(schemaName, schema); + } + // TODO: This should not update if the schema already exists @POST @Produces(MediaType.APPLICATION_JSON) @Path("/schemas") @ApiOperation(value = "Add a new schema", notes = "Adds a new schema") - @ApiResponses(value = {@ApiResponse(code = 200, message = "Successfully deleted schema"), @ApiResponse(code = 404, message = "Schema not found"), @ApiResponse(code = 400, message = "Missing or invalid request body"), @ApiResponse(code = 500, message = "Internal error")}) + @ApiResponses(value = {@ApiResponse(code = 200, message = "Successfully created schema"), @ApiResponse(code = 404, message = "Schema not found"), @ApiResponse(code = 400, message = "Missing or invalid request body"), @ApiResponse(code = 500, message = "Internal error")}) public SuccessResponse addSchema(FormDataMultiPart multiPart) { return addOrUpdateSchema(null, multiPart); } + // TODO: This should not update if the schema already exists + @POST + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + @Path("/schemas") + @ApiOperation(value = "Add a new schema", notes = "Adds a new schema") + @ApiResponses(value = {@ApiResponse(code = 200, message = "Successfully created schema"), @ApiResponse(code = 404, message = "Schema not found"), @ApiResponse(code = 400, message = "Missing or invalid request body"), @ApiResponse(code = 500, message = "Internal error")}) + public SuccessResponse addSchema(Schema schema) { + return addOrUpdateSchema(null, schema); + } + @POST @Produces(MediaType.APPLICATION_JSON) @Path("/schemas/validate") @@ -145,6 +168,21 @@ public class PinotSchemaRestletResource { return schema.toPrettyJsonString(); } + @POST + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + @Path("/schemas/validate") + @ApiOperation(value = "Validate schema", notes = "This API returns the schema that matches the one you get " + + "from 'GET /schema/{schemaName}'. This allows us to validate schema before apply.") + @ApiResponses(value = {@ApiResponse(code = 200, message = "Successfully validated schema"), @ApiResponse(code = 400, message = "Missing or invalid request body"), @ApiResponse(code = 500, message = "Internal error")}) + public String validateSchema(Schema schema) { + if (!schema.validate(LOGGER)) { + throw new ControllerApplicationException(LOGGER, "Invalid schema. Check controller logs", + Response.Status.BAD_REQUEST); + } + return schema.toPrettyJsonString(); + } + /** * Internal method to add or update schema * @param schemaName null value indicates new schema (POST request) where schemaName is @@ -152,8 +190,17 @@ public class PinotSchemaRestletResource { * @return */ private SuccessResponse addOrUpdateSchema(@Nullable String schemaName, FormDataMultiPart multiPart) { + return addOrUpdateSchema(schemaName, getSchemaFromMultiPart(multiPart)); + } + + /** + * Internal method to add or update schema + * @param schemaName null value indicates new schema (POST request) where schemaName is + * not part of URI + * @return + */ + private SuccessResponse addOrUpdateSchema(@Nullable String schemaName, Schema schema) { final String schemaNameForLogging = (schemaName == null) ? "new schema" : schemaName + " schema"; - Schema schema = getSchemaFromMultiPart(multiPart); if (!schema.validate(LOGGER)) { LOGGER.info("Invalid schema during create/update of {}", schemaNameForLogging); throw new ControllerApplicationException(LOGGER, "Invalid schema", Response.Status.BAD_REQUEST); diff --git a/pinot-controller/src/test/java/org/apache/pinot/controller/api/PinotSchemaRestletResourceTest.java b/pinot-controller/src/test/java/org/apache/pinot/controller/api/PinotSchemaRestletResourceTest.java index 745ce81..7766a9c 100644 --- a/pinot-controller/src/test/java/org/apache/pinot/controller/api/PinotSchemaRestletResourceTest.java +++ b/pinot-controller/src/test/java/org/apache/pinot/controller/api/PinotSchemaRestletResourceTest.java @@ -19,6 +19,8 @@ package org.apache.pinot.controller.api; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.PutMethod; import org.apache.pinot.common.data.DimensionFieldSpec; @@ -54,6 +56,36 @@ public class PinotSchemaRestletResourceTest extends ControllerTest { } @Test + public void testPostJson() { + String schemaString = "{\n" + " \"schemaName\" : \"transcript\",\n" + " \"dimensionFieldSpecs\" : [ {\n" + + " \"name\" : \"studentID\",\n" + " \"dataType\" : \"STRING\"\n" + " }, {\n" + + " \"name\" : \"firstName\",\n" + " \"dataType\" : \"STRING\"\n" + " }, {\n" + + " \"name\" : \"lastName\",\n" + " \"dataType\" : \"STRING\"\n" + " }, {\n" + + " \"name\" : \"gender\",\n" + " \"dataType\" : \"STRING\"\n" + " }, {\n" + + " \"name\" : \"subject\",\n" + " \"dataType\" : \"STRING\"\n" + " } ],\n" + + " \"metricFieldSpecs\" : [ {\n" + " \"name\" : \"score\",\n" + " \"dataType\" : \"FLOAT\"\n" + + " } ]}"; + try { + Map<String, String> header = new HashMap<>(); + sendPostRequest(_controllerRequestURLBuilder.forSchemaCreate(), schemaString, header); + } catch (IOException e) { + e.printStackTrace(); + Assert.assertTrue(e.getMessage().startsWith("Server returned HTTP response code: 415"), e.getMessage()); + } + + try { + Map<String, String> header = new HashMap<>(); + header.put("Content-Type", "application/json"); + final String response = sendPostRequest(_controllerRequestURLBuilder.forSchemaCreate(), schemaString, header); + Assert.assertEquals(response, "{\"status\":\"transcript successfully added\"}"); + } catch (IOException e) { + e.printStackTrace(); + // should not reach here + Assert.fail("Shouldn't have caught an exception"); + } + } + + @Test public void testCreateUpdateSchema() throws IOException { String schemaName = "testSchema"; diff --git a/pinot-controller/src/test/java/org/apache/pinot/controller/helix/ControllerTest.java b/pinot-controller/src/test/java/org/apache/pinot/controller/helix/ControllerTest.java index 069c7bd..4ce7ce1 100644 --- a/pinot-controller/src/test/java/org/apache/pinot/controller/helix/ControllerTest.java +++ b/pinot-controller/src/test/java/org/apache/pinot/controller/helix/ControllerTest.java @@ -33,6 +33,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.PutMethod; @@ -466,8 +467,18 @@ public abstract class ControllerTest { public static String sendPostRequest(String urlString, String payload) throws IOException { + return sendPostRequest(urlString, payload, Collections.EMPTY_MAP); + } + + public static String sendPostRequest(String urlString, String payload, Map<String, String> headers) + throws IOException { HttpURLConnection httpConnection = (HttpURLConnection) new URL(urlString).openConnection(); httpConnection.setRequestMethod("POST"); + if (headers != null) { + for (String key : headers.keySet()) { + httpConnection.setRequestProperty(key, headers.get(key)); + } + } if (payload != null && !payload.isEmpty()) { httpConnection.setDoOutput(true); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
