Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions core/server/SchemaAPIClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,13 +315,34 @@ bool SchemaAPIClient::validateMetadata(const std::string &a_schema_id,
a_warnings = result.value("warnings", "");
return true;
}

if (code == 422) {
a_errors = result.value("message", "metadata validation failed");
if (result.contains("details") && result["details"].contains("errors")) {
std::string raw = result["details"]["errors"].get<std::string>();
if (a_engine == "linkml") {
// Normalize semicolon-separated errors to newline-separated
// for consistency with json-schema validator output
std::string normalized;
size_t pos = 0, found;
while ((found = raw.find("; ", pos)) != std::string::npos) {
normalized += raw.substr(pos, found - pos) + "\n";
pos = found + 2;
}
normalized += raw.substr(pos);
a_errors = normalized;
} else {
a_errors = raw;
}
} else {
a_errors = result.value("message", "metadata validation failed");
}
return false;
}
if (code == 404)

if (code == 404) {
EXCEPT_PARAM(BAD_REQUEST,
"SchemaAPI: schema " << a_schema_id << " not found");
}
EXCEPT_PARAM(SERVICE_ERROR,
"SchemaAPI validateMetadata failed, HTTP " << code);
}
Expand Down
3 changes: 2 additions & 1 deletion core/server/client_handlers/SchemaHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ std::string SchemaHandler::validateMetadataContent(

std::string schema_type = "json-schema";
std::string schema_format = "json";
std::string metadata_format = "json";
std::string schema_def;

// Load schema record from DB
Expand Down Expand Up @@ -359,7 +360,7 @@ std::string SchemaHandler::validateMetadataContent(
}

auto result = validator.validateMetadata(
a_sch_id, schema_format, a_metadata, log_context);
a_sch_id, metadata_format, a_metadata, log_context);

if (!result.valid) {
return result.errors;
Expand Down
18 changes: 18 additions & 0 deletions core/server/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

// Standard includes
#include "Config.hpp"
#include "SchemaAPIConfig.hpp"
#include <climits>
#include <fstream>
#include <iostream>
Expand All @@ -34,6 +35,7 @@ int main(int a_argc, char **a_argv) {
LogContext log_context;
log_context.thread_name = "core_server";
log_context.thread_id = 0;
Core::SchemaAPIConfig linkml_schema_config;

try {

Expand Down Expand Up @@ -64,6 +66,12 @@ int main(int a_argc, char **a_argv) {
"Globus authorization API base URL")(
"glob-xfr-url", po::value<string>(&config.glob_xfr_url),
"Globus transfer API base URL")(
"linkml-schema-api-url",
po::value<string>(&linkml_schema_config.base_url),
"External LinkML schema API base URL (enables LinkML support)")(
"linkml-schema-api-token",
po::value<string>(&linkml_schema_config.bearer_token),
"Bearer token for LinkML schema API authentication")(
"client-id", po::value<string>(&config.client_id), "Client ID")(
"client-secret", po::value<string>(&config.client_secret),
"Client secret")("task-purge-age",
Expand Down Expand Up @@ -152,6 +160,16 @@ int main(int a_argc, char **a_argv) {

return 0;
}

if (linkml_schema_config.isConfigured()) {
config.schemas["linkml"] = linkml_schema_config;
DL_INFO(log_context, "LinkML schema engine enabled, API: "
<< linkml_schema_config.base_url);
} else {
DL_INFO(log_context,
"LinkML schema engine disabled (no linkml-schema-api-url configured)");
}

if (cfg_log_level != UINT_MAX) {
if (cfg_log_level >=
static_cast<unsigned int>(LogLevel::LAST_SENTINEL)) {
Expand Down
51 changes: 41 additions & 10 deletions python/datafed_pkg/datafed/CLI.py
Original file line number Diff line number Diff line change
Expand Up @@ -2046,29 +2046,44 @@ def _schemaView(schema_id, resolve):
@click.option(
"-s", "--system", is_flag=True, required=False, help="Create as a system schema."
)
@click.option(
"-t", "--type", "schema_type",
type=click.Choice(["json-schema", "linkml"]),
default="json-schema",
help="Schema engine type (default: json-schema).",
)
@click.option(
"--format", "schema_format",
type=click.Choice(["json", "yaml"]),
default="json",
help="Schema definition format (default: json).",
)
@_global_output_options
def _schemaCreate(schema_id, definition, definition_file, description, public, system):
def _schemaCreate(schema_id, definition, definition_file, description,
public, system, schema_type, schema_format):
"""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: CLI help text still describes JSON-only schemas despite new LinkML support.

The _schemaCreate docstring still states "A JSON schema definition is required" even though the command now supports multiple schema types via --type and --format (including LinkML/YAML). Please update the text to describe a generic schema definition and briefly reference how it relates to --type/--format to avoid misleading users about supported formats.

Create a new metadata schema. A JSON schema definition is required and
may be provided inline via --definition or read from a file via
--definition-file. Cannot specify both.
"""

if definition and definition_file:
raise Exception(
"Cannot specify both --definition and --definition-file options."
)

if not definition and not definition_file:
raise Exception("Must specify either --definition or --definition-file.")

reply = _capi.schemaCreate(
schema_id,
definition=definition,
definition_file=definition_file,
description=description,
public=public,
system=system,
schema_type=schema_type,
schema_format=schema_format,
)
_generic_reply_handler(reply, _print_ack_reply)

Expand Down Expand Up @@ -2106,26 +2121,34 @@ def _schemaCreate(schema_id, definition, definition_file, description, public, s
required=False,
help="Set as system schema.",
)
@click.option(
"-t", "--type", "schema_type",
type=click.Choice(["json-schema", "linkml"]),
default=None, required=False,
help="Schema engine type.",
)
@_global_output_options
def _schemaRevise(schema_id, definition, definition_file, description, public, system):
def _schemaRevise(schema_id, definition, definition_file, description,
public, system, schema_type):
"""
Create a new revision of an existing schema. Any fields not provided are
carried forward from the current revision. The definition may be provided
inline or read from a file.
"""

if definition and definition_file:
raise Exception(
"Cannot specify both --definition and --definition-file options."
)

reply = _capi.schemaRevise(
schema_id,
definition=definition,
definition_file=definition_file,
description=description,
public=public if public else None,
system=system if system else None,
schema_type=schema_type,
)
_generic_reply_handler(reply, _print_ack_reply)

Expand Down Expand Up @@ -2164,20 +2187,27 @@ def _schemaRevise(schema_id, definition, definition_file, description, public, s
required=False,
help="Set as system schema.",
)
@click.option(
"-t", "--type", "schema_type",
type=click.Choice(["json-schema", "linkml"]),
default=None, required=False,
help="Schema engine type.",
)
@_global_output_options
def _schemaUpdate(
schema_id, new_id, definition, definition_file, description, public, system
schema_id, new_id, definition, definition_file, description,
public, system, schema_type
):
"""
Update an existing schema in place without creating a new revision.
The definition may be provided inline or read from a file.
"""

if definition and definition_file:
raise Exception(
"Cannot specify both --definition and --definition-file options."
)

reply = _capi.schemaUpdate(
schema_id,
new_id=new_id,
Expand All @@ -2186,6 +2216,7 @@ def _schemaUpdate(
description=description,
public=public if public else None,
system=system if system else None,
schema_type=schema_type,
)
_generic_reply_handler(reply, _print_ack_reply)

Expand Down
Loading