Skip to content

Commit

Permalink
v3 OpenAPI fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
david-leifker committed Apr 10, 2024
1 parent eeee76e commit 7ac1b22
Show file tree
Hide file tree
Showing 18 changed files with 347 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ private static DataPlatformInfo getDataPlatformInfo(Urn urn, EntityService<?> en
return null;
}

private static MetadataChangeProposal getProposalFromAspectForDefault(
public static MetadataChangeProposal getProposalFromAspectForDefault(
String aspectName,
RecordTemplate aspect,
RecordTemplate entityKeyAspect,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1106,9 +1106,7 @@ private Stream<IngestResult> ingestProposalSync(AspectsBatch aspectsBatch) {
if (!unsupported.isEmpty()) {
throw new UnsupportedOperationException(
"ChangeType not supported: "
+ unsupported.stream()
.map(item -> item.getMetadataChangeProposal().getChangeType())
.collect(Collectors.toSet()));
+ unsupported.stream().map(item -> item.getChangeType()).collect(Collectors.toSet()));
}

List<UpdateAspectResult> upsertResults = ingestAspects(nonTimeseries, true, true);
Expand Down
2 changes: 1 addition & 1 deletion metadata-service/openapi-analytics-servlet/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ task openApiGenerate(type: GenerateSwaggerCode) {
'java11' : "true",
'modelPropertyNaming': "original",
'modelPackage' : "io.datahubproject.openapi.generated",
'apiPackage' : "io.datahubproject.openapi.generated.controller",
'apiPackage' : "io.datahubproject.openapi.v2.generated.controller",
'delegatePattern' : "true"
]
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package io.datahubproject.openapi.config;

import io.datahubproject.openapi.delegates.DatahubUsageEventsImpl;
import io.datahubproject.openapi.generated.controller.DatahubUsageEventsApiDelegate;
import io.datahubproject.openapi.v2.generated.controller.DatahubUsageEventsApiDelegate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import com.datahub.authorization.AuthorizerChain;
import com.linkedin.metadata.search.elasticsearch.ElasticSearchService;
import io.datahubproject.openapi.exception.UnauthorizedException;
import io.datahubproject.openapi.generated.controller.DatahubUsageEventsApiDelegate;
import io.datahubproject.openapi.v2.generated.controller.DatahubUsageEventsApiDelegate;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ import java.util.concurrent.Callable;
{{/isJava8or11}}
{{>generatedAnnotation}}
@Controller
@RequestMapping("/v1/analytics")
@RequestMapping("/v2/analytics")
{{#operations}}
public class {{classname}}Controller implements {{classname}} {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ openapi: "3.0.0"
info:
title: Analytics API
description: This is a service for DataHub Analytics.
version: v1
version: v2

paths:
/datahub_usage_events/_search:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import io.datahubproject.metadata.context.RequestContext;
import io.datahubproject.openapi.dto.UpsertAspectRequest;
import io.datahubproject.openapi.dto.UrnResponseMap;
import io.datahubproject.openapi.entities.EntitiesController;
import io.datahubproject.openapi.exception.UnauthorizedException;
import io.datahubproject.openapi.generated.BrowsePathsV2AspectRequestV2;
import io.datahubproject.openapi.generated.BrowsePathsV2AspectResponseV2;
Expand Down Expand Up @@ -56,6 +55,7 @@
import io.datahubproject.openapi.generated.StatusAspectRequestV2;
import io.datahubproject.openapi.generated.StatusAspectResponseV2;
import io.datahubproject.openapi.util.OpenApiEntitiesUtil;
import io.datahubproject.openapi.v1.entities.EntitiesController;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import io.datahubproject.openapi.v2.delegates.EntityApiDelegateImpl;
import io.datahubproject.metadata.context.OperationContext;
import com.linkedin.metadata.entity.EntityService;
import com.linkedin.metadata.search.SearchService;
import io.datahubproject.openapi.entities.EntitiesController;
import io.datahubproject.openapi.v1.entities.EntitiesController;
import com.datahub.authorization.AuthorizerChain;

import org.springframework.web.bind.annotation.RequestMapping;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@
import com.linkedin.metadata.timeline.TimelineService;
import io.datahubproject.metadata.context.OperationContext;
import io.datahubproject.openapi.dto.UrnResponseMap;
import io.datahubproject.openapi.entities.EntitiesController;
import io.datahubproject.openapi.generated.EntityResponse;
import io.datahubproject.openapi.relationships.RelationshipsController;
import io.datahubproject.openapi.timeline.TimelineController;
import io.datahubproject.openapi.v1.entities.EntitiesController;
import io.datahubproject.openapi.v1.relationships.RelationshipsController;
import io.datahubproject.openapi.v2.controller.TimelineController;
import io.datahubproject.test.metadata.context.TestOperationContexts;
import java.util.Arrays;
import java.util.Map;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
public class SpringWebConfig implements WebMvcConfigurer {
private static final Set<String> OPERATIONS_PACKAGES =
Set.of("io.datahubproject.openapi.operations", "io.datahubproject.openapi.health");
private static final Set<String> V1_PACKAGES = Set.of("io.datahubproject.openapi.v1");
private static final Set<String> V2_PACKAGES = Set.of("io.datahubproject.openapi.v2");
private static final Set<String> V3_PACKAGES = Set.of("io.datahubproject.openapi.v3");
private static final Set<String> SCHEMA_REGISTRY_PACKAGES =
Expand All @@ -44,9 +45,10 @@ public class SpringWebConfig implements WebMvcConfigurer {
static {
NONDEFAULT_OPENAPI_PACKAGES = new HashSet<>();
NONDEFAULT_OPENAPI_PACKAGES.addAll(OPERATIONS_PACKAGES);
NONDEFAULT_OPENAPI_PACKAGES.addAll(V2_PACKAGES);
NONDEFAULT_OPENAPI_PACKAGES.addAll(SCHEMA_REGISTRY_PACKAGES);
NONDEFAULT_OPENAPI_PACKAGES.addAll(OPENLINEAGE_PACKAGES);
NONDEFAULT_OPENAPI_PACKAGES.addAll(V1_PACKAGES);
NONDEFAULT_OPENAPI_PACKAGES.addAll(V2_PACKAGES);
NONDEFAULT_OPENAPI_PACKAGES.addAll(V3_PACKAGES);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.datahubproject.openapi.entities;
package io.datahubproject.openapi.v1.entities;

import static com.datahub.authorization.AuthUtil.isAPIAuthorized;
import static com.linkedin.metadata.authorization.ApiGroup.ENTITY;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.datahubproject.openapi.relationships;
package io.datahubproject.openapi.v1.relationships;

import static com.linkedin.metadata.authorization.ApiGroup.RELATIONSHIP;
import static com.linkedin.metadata.authorization.ApiOperation.READ;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import com.datahub.authorization.AuthUtil;
import com.datahub.authorization.AuthorizerChain;
import com.datahub.util.RecordUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.linkedin.common.urn.Urn;
import com.linkedin.common.urn.UrnUtils;
Expand All @@ -23,6 +25,8 @@
import com.linkedin.metadata.aspect.patch.GenericJsonPatch;
import com.linkedin.metadata.aspect.patch.template.common.GenericPatchTemplate;
import com.linkedin.metadata.entity.EntityService;
import com.linkedin.metadata.entity.EntityUtils;
import com.linkedin.metadata.entity.IngestResult;
import com.linkedin.metadata.entity.UpdateAspectResult;
import com.linkedin.metadata.entity.ebean.batch.AspectsBatchImpl;
import com.linkedin.metadata.entity.ebean.batch.ChangeItemImpl;
Expand Down Expand Up @@ -55,6 +59,8 @@
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand Down Expand Up @@ -235,7 +241,9 @@ public ResponseEntity<Object> headEntity(
public ResponseEntity<Object> getAspect(
@PathVariable("entityName") String entityName,
@PathVariable("entityUrn") String entityUrn,
@PathVariable("aspectName") String aspectName)
@PathVariable("aspectName") String aspectName,
@RequestParam(value = "systemMetadata", required = false, defaultValue = "false")
Boolean withSystemMetadata)
throws URISyntaxException {

Urn urn = UrnUtils.getUrn(entityUrn);
Expand All @@ -247,9 +255,16 @@ public ResponseEntity<Object> getAspect(
}

return ResponseEntity.of(
toRecordTemplates(List.of(urn), Set.of(aspectName), true).stream()
toRecordTemplates(
List.of(urn), Set.of(aspectName), withSystemMetadata)
.stream()
.findFirst()
.flatMap(e -> e.getAspects().values().stream().findFirst()));
.flatMap(
e ->
e.getAspects().entrySet().stream()
.filter(entry -> entry.getKey().equals(aspectName))
.map(Map.Entry::getValue)
.findFirst()));
}

@Tag(name = "Generic Aspects")
Expand Down Expand Up @@ -293,6 +308,42 @@ public void deleteEntity(
entityService.deleteAspect(entityUrn, entitySpec.getKeyAspectName(), Map.of(), true);
}

@Tag(name = "Generic Entities")
@PostMapping(value = "/{entityName}", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Create a batch of entities.")
public ResponseEntity<List<GenericEntity>> createEntity(
@PathVariable("entityName") String entityName,
@RequestParam(value = "async", required = false, defaultValue = "true") Boolean async,
@RequestParam(value = "systemMetadata", required = false, defaultValue = "false")
Boolean withSystemMetadata,
@RequestBody @Nonnull String jsonEntityList)
throws URISyntaxException, JsonProcessingException {

EntitySpec entitySpec = entityRegistry.getEntitySpec(entityName);
Authentication authentication = AuthenticationContext.getAuthentication();

AspectsBatch batch = toBatch(jsonEntityList, authentication.getActor());

if (restApiAuthorizationEnabled) {
for (BatchItem item : batch.getItems()) {
checkAuthorized(
authorizationChain,
authentication.getActor(),
entitySpec,
item.getUrn().toString(),
ImmutableList.of(PoliciesConfig.EDIT_ENTITY_PRIVILEGE.getType()));
}
}

Set<IngestResult> results = entityService.ingestProposal(batch, async);

if (!async) {
return ResponseEntity.ok(toEntityListResponse(results, withSystemMetadata));
} else {
return ResponseEntity.accepted().body(toEntityListResponse(results, withSystemMetadata));
}
}

@Tag(name = "Generic Aspects")
@DeleteMapping(value = "/{entityName}/{entityUrn}/{aspectName}")
@Operation(summary = "Delete an entity aspect.")
Expand Down Expand Up @@ -550,4 +601,75 @@ private ChangeMCP toUpsertItem(
AuditStampUtils.createAuditStamp(actor.toUrnStr()),
entityService);
}

private AspectsBatch toBatch(String entityArrayList, Actor actor)
throws JsonProcessingException, URISyntaxException {
JsonNode entities = objectMapper.readTree(entityArrayList);

List<BatchItem> items = new LinkedList<>();
if (entities.isArray()) {
Iterator<JsonNode> entityItr = entities.iterator();
while (entityItr.hasNext()) {
JsonNode entity = entityItr.next();
Urn entityUrn = UrnUtils.getUrn(entity.get("urn").asText());

Iterator<Map.Entry<String, JsonNode>> aspectItr = entity.get("aspects").fields();
while (aspectItr.hasNext()) {
Map.Entry<String, JsonNode> aspect = aspectItr.next();

AspectSpec aspectSpec = lookupAspectSpec(entityUrn, aspect.getKey());

if (aspectSpec != null) {
MCPUpsertBatchItem.MCPUpsertBatchItemBuilder builder =
MCPUpsertBatchItem.builder()
.urn(entityUrn)
.aspectName(aspectSpec.getName())
.auditStamp(AuditStampUtils.createAuditStamp(actor.toUrnStr()))
.recordTemplate(
GenericRecordUtils.deserializeAspect(
ByteString.copyString(
objectMapper.writeValueAsString(aspect.getValue().get("value")),
StandardCharsets.UTF_8),
GenericRecordUtils.JSON,
aspectSpec));

if (aspect.getValue().has("systemMetadata")) {
builder.systemMetadata(
EntityUtils.parseSystemMetadata(
objectMapper.writeValueAsString(aspect.getValue().get("systemMetadata"))));
}

items.add(builder.build(entityService));
}
}
}
}

return AspectsBatchImpl.builder().items(items).build();
}

public List<GenericEntity> toEntityListResponse(
Set<IngestResult> ingestResults, boolean withSystemMetadata) {
List<GenericEntity> responseList = new LinkedList<>();

Map<Urn, List<IngestResult>> entityMap =
ingestResults.stream().collect(Collectors.groupingBy(IngestResult::getUrn));
for (Map.Entry<Urn, List<IngestResult>> urnAspects : entityMap.entrySet()) {
Map<String, Pair<RecordTemplate, SystemMetadata>> aspectsMap =
urnAspects.getValue().stream()
.map(
ingest ->
Map.entry(
ingest.getRequest().getAspectName(),
Pair.of(
ingest.getRequest().getRecordTemplate(),
withSystemMetadata ? ingest.getRequest().getSystemMetadata() : null)))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
responseList.add(
GenericEntity.builder()
.urn(urnAspects.getKey().toString())
.build(objectMapper, aspectsMap));
}
return responseList;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.datahubproject.openapi.platform.entities;
package io.datahubproject.openapi.v2.controller;

import static com.datahub.authorization.AuthUtil.isAPIAuthorized;
import static com.linkedin.metadata.authorization.ApiGroup.ENTITY;
Expand Down Expand Up @@ -36,7 +36,7 @@

@RestController
@RequiredArgsConstructor
@RequestMapping("/platform/entities/v1")
@RequestMapping("/v2/platform/entities/v1")
@Slf4j
@Tag(
name = "Platform Entities",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.datahubproject.openapi.timeline;
package io.datahubproject.openapi.v2.controller;

import com.datahub.authentication.Authentication;
import com.datahub.authentication.AuthenticationContext;
Expand Down Expand Up @@ -31,7 +31,7 @@

@RestController
@AllArgsConstructor
@RequestMapping("/timeline/v1")
@RequestMapping("/v2/timeline/v1")
@Tag(
name = "Timeline",
description =
Expand Down
Loading

0 comments on commit 7ac1b22

Please sign in to comment.