mirror of
https://github.com/datahub-project/datahub.git
synced 2025-11-03 04:10:43 +00:00
fix(misc-openapi): fix openlineage, platform events & swagger (#12539)
This commit is contained in:
parent
d1e8a0a145
commit
a4f64fd49b
@ -28,7 +28,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|||||||
@EnableWebMvc
|
@EnableWebMvc
|
||||||
@OpenAPIDefinition(
|
@OpenAPIDefinition(
|
||||||
info = @Info(title = "DataHub OpenAPI", version = "2.0.0"),
|
info = @Info(title = "DataHub OpenAPI", version = "2.0.0"),
|
||||||
servers = {@Server(url = "/openapi/", description = "Default Server URL")})
|
servers = {@Server(url = "/", description = "Default Server URL")})
|
||||||
@Order(2)
|
@Order(2)
|
||||||
@Configuration
|
@Configuration
|
||||||
public class SpringWebConfig implements WebMvcConfigurer {
|
public class SpringWebConfig implements WebMvcConfigurer {
|
||||||
|
|||||||
@ -27,7 +27,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/openlineage/api/v1")
|
@RequestMapping("/openapi/openlineage/api/v1")
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class LineageApiImpl implements LineageApi {
|
public class LineageApiImpl implements LineageApi {
|
||||||
private static final ObjectMapper OBJECT_MAPPER = OpenLineageClientUtils.newObjectMapper();
|
private static final ObjectMapper OBJECT_MAPPER = OpenLineageClientUtils.newObjectMapper();
|
||||||
|
|||||||
@ -39,7 +39,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@RequestMapping("/openapiv2/platform/entities/v1")
|
@RequestMapping("/openapi/v2/platform/entities/v1")
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Tag(
|
@Tag(
|
||||||
name = "Platform Entities",
|
name = "Platform Entities",
|
||||||
|
|||||||
@ -35,6 +35,7 @@ import java.util.stream.Stream;
|
|||||||
|
|
||||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
public class OpenAPIV3Generator {
|
public class OpenAPIV3Generator {
|
||||||
|
private static final String PATH_PREFIX = "/openapi/v3";
|
||||||
private static final String MODEL_VERSION = "_v3";
|
private static final String MODEL_VERSION = "_v3";
|
||||||
private static final String TYPE_OBJECT = "object";
|
private static final String TYPE_OBJECT = "object";
|
||||||
private static final String TYPE_BOOLEAN = "boolean";
|
private static final String TYPE_BOOLEAN = "boolean";
|
||||||
@ -171,18 +172,19 @@ public class OpenAPIV3Generator {
|
|||||||
final Paths paths = new Paths();
|
final Paths paths = new Paths();
|
||||||
|
|
||||||
// --> Cross-entity Paths
|
// --> Cross-entity Paths
|
||||||
paths.addPathItem("/v3/entity/scroll", buildGenericListEntitiesPath());
|
paths.addPathItem(PATH_PREFIX + "/entity/scroll", buildGenericListEntitiesPath());
|
||||||
|
|
||||||
// --> Entity Paths
|
// --> Entity Paths
|
||||||
definedEntitySpecs.forEach(
|
definedEntitySpecs.forEach(
|
||||||
e -> {
|
e -> {
|
||||||
paths.addPathItem(
|
paths.addPathItem(
|
||||||
String.format("/v3/entity/%s", e.getName().toLowerCase()), buildListEntityPath(e));
|
String.format(PATH_PREFIX + "/entity/%s", e.getName().toLowerCase()),
|
||||||
|
buildListEntityPath(e));
|
||||||
paths.addPathItem(
|
paths.addPathItem(
|
||||||
String.format("/v3/entity/%s/batchGet", e.getName().toLowerCase()),
|
String.format(PATH_PREFIX + "/entity/%s/batchGet", e.getName().toLowerCase()),
|
||||||
buildBatchGetEntityPath(e));
|
buildBatchGetEntityPath(e));
|
||||||
paths.addPathItem(
|
paths.addPathItem(
|
||||||
String.format("/v3/entity/%s/{urn}", e.getName().toLowerCase()),
|
String.format(PATH_PREFIX + "/entity/%s/{urn}", e.getName().toLowerCase()),
|
||||||
buildSingleEntityPath(e));
|
buildSingleEntityPath(e));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -196,8 +198,9 @@ public class OpenAPIV3Generator {
|
|||||||
a ->
|
a ->
|
||||||
paths.addPathItem(
|
paths.addPathItem(
|
||||||
String.format(
|
String.format(
|
||||||
"/v3/entity/%s/{urn}/%s",
|
PATH_PREFIX + "/entity/%s/{urn}/%s",
|
||||||
e.getName().toLowerCase(), a.getName().toLowerCase()),
|
e.getName().toLowerCase(),
|
||||||
|
a.getName().toLowerCase()),
|
||||||
buildSingleEntityAspectPath(e, a))));
|
buildSingleEntityAspectPath(e, a))));
|
||||||
definedEntitySpecs.forEach(
|
definedEntitySpecs.forEach(
|
||||||
e ->
|
e ->
|
||||||
@ -208,8 +211,9 @@ public class OpenAPIV3Generator {
|
|||||||
a ->
|
a ->
|
||||||
paths.addPathItem(
|
paths.addPathItem(
|
||||||
String.format(
|
String.format(
|
||||||
"/v3/entity/%s/{urn}/%s",
|
PATH_PREFIX + "/entity/%s/{urn}/%s",
|
||||||
e.getName().toLowerCase(), a.getName().toLowerCase()),
|
e.getName().toLowerCase(),
|
||||||
|
a.getName().toLowerCase()),
|
||||||
buildSingleEntityAspectPath(e, a))));
|
buildSingleEntityAspectPath(e, a))));
|
||||||
|
|
||||||
// --> Link & Unlink APIs
|
// --> Link & Unlink APIs
|
||||||
@ -219,7 +223,8 @@ public class OpenAPIV3Generator {
|
|||||||
.forEach(
|
.forEach(
|
||||||
entitySpec -> {
|
entitySpec -> {
|
||||||
paths.addPathItem(
|
paths.addPathItem(
|
||||||
"/v3/entity/versioning/{versionSetUrn}/relationship/versionOf/{entityUrn}",
|
PATH_PREFIX
|
||||||
|
+ "/entity/versioning/{versionSetUrn}/relationship/versionOf/{entityUrn}",
|
||||||
buildVersioningRelationshipPath());
|
buildVersioningRelationshipPath());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,9 +4,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||||||
import com.linkedin.gms.factory.kafka.schemaregistry.InternalSchemaRegistryFactory;
|
import com.linkedin.gms.factory.kafka.schemaregistry.InternalSchemaRegistryFactory;
|
||||||
import com.linkedin.metadata.registry.SchemaRegistryService;
|
import com.linkedin.metadata.registry.SchemaRegistryService;
|
||||||
import io.datahubproject.openapi.schema.registry.SchemaRegistryController;
|
import io.datahubproject.openapi.schema.registry.SchemaRegistryController;
|
||||||
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
|
|
||||||
import io.swagger.v3.oas.annotations.info.Info;
|
|
||||||
import io.swagger.v3.oas.annotations.servers.Server;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
@ -19,9 +16,6 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
|||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@EnableWebMvc
|
@EnableWebMvc
|
||||||
@OpenAPIDefinition(
|
|
||||||
info = @Info(title = "DataHub OpenAPI", version = "1.0.0"),
|
|
||||||
servers = {@Server(url = "/schema-registry/", description = "Schema Registry Server URL")})
|
|
||||||
@Order(3)
|
@Order(3)
|
||||||
@ConditionalOnProperty(
|
@ConditionalOnProperty(
|
||||||
name = "kafka.schemaRegistry.type",
|
name = "kafka.schemaRegistry.type",
|
||||||
|
|||||||
0
smoke-test/tests/openapi/openlineage/__init__.py
Normal file
0
smoke-test/tests/openapi/openlineage/__init__.py
Normal file
34
smoke-test/tests/openapi/openlineage/openlineage.json
Normal file
34
smoke-test/tests/openapi/openlineage/openlineage.json
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"url": "/openapi/openlineage/api/v1/lineage",
|
||||||
|
"description": "Post openlineage",
|
||||||
|
"json": {
|
||||||
|
"eventType": "START",
|
||||||
|
"eventTime": "2020-12-28T19:52:00.001+10:00",
|
||||||
|
"run": {
|
||||||
|
"runId": "d46e465b-d358-4d32-83d4-df660ff614dd"
|
||||||
|
},
|
||||||
|
"job": {
|
||||||
|
"namespace": "workshop",
|
||||||
|
"name": "process_taxes"
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"namespace": "postgres://workshop-db:None",
|
||||||
|
"name": "workshop.public.taxes",
|
||||||
|
"facets": {
|
||||||
|
"dataSource": {
|
||||||
|
"_producer": "https://github.com/OpenLineage/OpenLineage/tree/0.10.0/integration/airflow",
|
||||||
|
"_schemaURL": "https://raw.githubusercontent.com/OpenLineage/OpenLineage/main/spec/OpenLineage.json#/definitions/DataSourceDatasetFacet",
|
||||||
|
"name": "postgres://workshop-db:None",
|
||||||
|
"uri": "workshop-db"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"producer": "https://github.com/OpenLineage/OpenLineage/blob/v1-0-0/client"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
31
smoke-test/tests/openapi/v2/platform_entities.json
Normal file
31
smoke-test/tests/openapi/v2/platform_entities.json
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"url": "/openapi/v2/platform/entities/v1/",
|
||||||
|
"description": "Create data product",
|
||||||
|
"params": {
|
||||||
|
"async": "false"
|
||||||
|
},
|
||||||
|
"json": [
|
||||||
|
{
|
||||||
|
"entityType": "dataProduct",
|
||||||
|
"entityUrn": "urn:li:dataProduct:4fd5aea7-a15f-4842-a2cc-e6562605ebf7",
|
||||||
|
"changeType": "UPSERT",
|
||||||
|
"aspectName": "status",
|
||||||
|
"aspect": {
|
||||||
|
"value": {
|
||||||
|
"__type": "Status",
|
||||||
|
"removed": false
|
||||||
|
},
|
||||||
|
"contentType": "application/json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"json": [
|
||||||
|
"urn:li:dataProduct:4fd5aea7-a15f-4842-a2cc-e6562605ebf7"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@ -57,13 +57,14 @@ def evaluate_test(auth_session, test_name, test_data):
|
|||||||
continue
|
continue
|
||||||
url = req_resp["request"]["url"]
|
url = req_resp["request"]["url"]
|
||||||
actual_resp = execute_request(auth_session, req_resp["request"])
|
actual_resp = execute_request(auth_session, req_resp["request"])
|
||||||
|
diff = None
|
||||||
try:
|
try:
|
||||||
if "response" in req_resp and "status_codes" in req_resp["response"]:
|
if "response" in req_resp and "status_codes" in req_resp["response"]:
|
||||||
assert (
|
assert (
|
||||||
actual_resp.status_code in req_resp["response"]["status_codes"]
|
actual_resp.status_code in req_resp["response"]["status_codes"]
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
assert actual_resp.status_code in [200, 202, 204]
|
assert actual_resp.status_code in [200, 201, 202, 204]
|
||||||
if "response" in req_resp:
|
if "response" in req_resp:
|
||||||
if "json" in req_resp["response"]:
|
if "json" in req_resp["response"]:
|
||||||
if "exclude_regex_paths" in req_resp["response"]:
|
if "exclude_regex_paths" in req_resp["response"]:
|
||||||
@ -87,7 +88,9 @@ def evaluate_test(auth_session, test_name, test_data):
|
|||||||
)
|
)
|
||||||
if description:
|
if description:
|
||||||
logger.error(f"Step {idx} Description: {description}")
|
logger.error(f"Step {idx} Description: {description}")
|
||||||
logger.error(f"Response content: {actual_resp.content}")
|
if diff:
|
||||||
|
logger.error(f"Unexpected diff: {diff}")
|
||||||
|
logger.debug(f"Response content: {actual_resp.content}")
|
||||||
raise e
|
raise e
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error executing test: {test_name}")
|
logger.error(f"Error executing test: {test_name}")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user