This is an automated email from the ASF dual-hosted git repository.
xiangfu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-pinot.git
The following commit(s) were added to refs/heads/master by this push:
new 4c4800b Support HTTP POST/PUT JSON schema (#4639)
4c4800b is described below
commit 4c4800bf65413105ecf0fde7c189f3378dfa0d3a
Author: Xiang Fu <[email protected]>
AuthorDate: Tue Sep 24 23:50:02 2019 -0700
Support HTTP POST/PUT JSON schema (#4639)
* Support HTTP POST JSON schema
* address comments
---
.../api/resources/PinotSchemaRestletResource.java | 51 +++++++++++++++++++++-
.../api/PinotSchemaRestletResourceTest.java | 30 +++++++++++++
.../pinot/controller/helix/ControllerTest.java | 11 +++++
3 files changed, 90 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..5f1979b 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,34 @@ 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) {
+ 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) {
+ // 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]