Skip to content

Commit

Permalink
feat(openapi): support structured properties & forms
Browse files Browse the repository at this point in the history
All changes refer to the DataHub OpenAPI v2 endpoints.

Strongly Typed Endpoints:
* Forms entity & aspects

Generic Endpoints:
* Structured Properties support
* Experimental generic PATCH support
* Relationships read support
* Timeseries aspects read support

Docs:
* Structured Properties OpenAPI v2 Guide
  • Loading branch information
david-leifker committed Jan 17, 2024
1 parent 24d045b commit 73e0ff8
Show file tree
Hide file tree
Showing 41 changed files with 2,294 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ private void generateSchema(final File file) {
final String fileBaseName;
try {
final JsonNode schema = JsonLoader.fromFile(file);

final JsonNode result = buildResult(schema.toString());
String prettySchema = JacksonUtils.prettyPrint(result);
Path absolutePath = file.getAbsoluteFile().toPath();
Expand All @@ -195,11 +196,21 @@ private void generateSchema(final File file) {
} else {
fileBaseName = getBaseName(file.getName());
}
Files.write(Paths.get(jsonDirectory + sep + fileBaseName + ".json"),

final String targetName;
if (schema.has("Aspect") && schema.get("Aspect").has("name") &&
!schema.get("Aspect").get("name").asText().equalsIgnoreCase(fileBaseName)) {
targetName = OpenApiEntities.toUpperFirst(schema.get("Aspect").get("name").asText());
prettySchema = prettySchema.replaceAll(fileBaseName, targetName);
} else {
targetName = fileBaseName;
}

Files.write(Paths.get(jsonDirectory + sep + targetName + ".json"),
prettySchema.getBytes(StandardCharsets.UTF_8), StandardOpenOption.WRITE, StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING);
if (schema.has("Aspect")) {
aspectType.add(NODE_FACTORY.objectNode().put("$ref", "#/definitions/" + getBaseName(file.getName())));
aspectType.add(NODE_FACTORY.objectNode().put("$ref", "#/definitions/" + targetName));
}
} catch (IOException | ProcessingException e) {
throw new RuntimeException(e);
Expand Down
22 changes: 16 additions & 6 deletions buildSrc/src/main/java/io/datahubproject/OpenApiEntities.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.linkedin.metadata.models.registry.config.Entities;
import com.linkedin.metadata.models.registry.config.Entity;
Expand Down Expand Up @@ -58,8 +59,12 @@ public class OpenApiEntities {
.add("notebookInfo").add("editableNotebookProperties")
.add("dataProductProperties")
.add("institutionalMemory")
.add("forms").add("formInfo").add("dynamicFormAssignment")
.build();

private final static ImmutableSet<String> ENTITY_EXCLUSIONS = ImmutableSet.<String>builder()
.add("structuredProperty")
.build();

public OpenApiEntities(JsonNodeFactory NODE_FACTORY) {
this.NODE_FACTORY = NODE_FACTORY;
Expand Down Expand Up @@ -117,14 +122,19 @@ public ObjectNode entityExtension(List<ObjectNode> nodesList, ObjectNode schemas
return componentsNode;
}

private static String toUpperFirst(String s) {
return s.substring(0, 1).toUpperCase() + s.substring(1);
public static String toUpperFirst(String s) {
if (s.length() > 2 && s.substring(2, 3).equals(s.substring(2, 3).toUpperCase())) {
return s.substring(0, 2).toUpperCase() + s.substring(2);
} else {
return s.substring(0, 1).toUpperCase() + s.substring(1);
}
}

private Set<String> withEntitySchema(ObjectNode schemasNode, Set<String> definitions) {
return entityMap.values().stream()
// Make sure the primary key is defined
.filter(entity -> definitions.contains(toUpperFirst(entity.getKeyAspect())))
.filter(entity -> !ENTITY_EXCLUSIONS.contains(entity.getName()))
.map(entity -> {
final String upperName = toUpperFirst(entity.getName());

Expand Down Expand Up @@ -547,7 +557,7 @@ private ObjectNode buildSingleEntityAspectPath(Entity entity, String aspect) {

ObjectNode getMethod = NODE_FACTORY.objectNode()
.put("summary", String.format("Get %s for %s.", aspect, entity.getName()))
.put("operationId", String.format("get%s", upperFirstAspect, upperFirstEntity));
.put("operationId", String.format("get%s", upperFirstAspect));
getMethod.set("tags", tagsNode);
ArrayNode singlePathParametersNode = NODE_FACTORY.arrayNode();
getMethod.set("parameters", singlePathParametersNode);
Expand Down Expand Up @@ -575,13 +585,13 @@ private ObjectNode buildSingleEntityAspectPath(Entity entity, String aspect) {
.set("application/json", NODE_FACTORY.objectNode())));
ObjectNode headMethod = NODE_FACTORY.objectNode()
.put("summary", String.format("%s on %s existence.", aspect, upperFirstEntity))
.put("operationId", String.format("head%s", upperFirstAspect, upperFirstEntity))
.put("operationId", String.format("head%s", upperFirstAspect))
.set("responses", headResponses);
headMethod.set("tags", tagsNode);

ObjectNode deleteMethod = NODE_FACTORY.objectNode()
.put("summary", String.format("Delete %s on entity %s", aspect, upperFirstEntity))
.put("operationId", String.format("delete%s", upperFirstAspect, upperFirstEntity))
.put("operationId", String.format("delete%s", upperFirstAspect))
.set("responses", NODE_FACTORY.objectNode()
.set("200", NODE_FACTORY.objectNode()
.put("description", String.format("Delete %s on %s entity.", aspect, upperFirstEntity))
Expand All @@ -591,7 +601,7 @@ private ObjectNode buildSingleEntityAspectPath(Entity entity, String aspect) {

ObjectNode postMethod = NODE_FACTORY.objectNode()
.put("summary", String.format("Create aspect %s on %s ", aspect, upperFirstEntity))
.put("operationId", String.format("create%s", upperFirstAspect, upperFirstEntity));
.put("operationId", String.format("create%s", upperFirstAspect));
postMethod.set("requestBody", NODE_FACTORY.objectNode()
.put("description", String.format("Create aspect %s on %s entity.", aspect, upperFirstEntity))
.put("required", true).set("content", NODE_FACTORY.objectNode()
Expand Down
2 changes: 2 additions & 0 deletions docker/profiles/docker-compose.gms.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ x-datahub-gms-service: &datahub-gms-service
timeout: 5s
volumes:
- ${HOME}/.datahub/plugins:/etc/datahub/plugins
labels:
io.datahubproject.datahub.component: "gms"

x-datahub-gms-service-dev: &datahub-gms-service-dev
<<: *datahub-gms-service
Expand Down
Loading

0 comments on commit 73e0ff8

Please sign in to comment.