Skip to content

Commit

Permalink
Merge pull request #35 from ternaustralia/edmond/ld-viewer
Browse files Browse the repository at this point in the history
Streamline API error responses, Improve performance and improve the fetching of labels of resources with deprecated code removed
  • Loading branch information
edmondchuc authored Sep 8, 2022
2 parents 3bf32f5 + 8a8442f commit cbea718
Show file tree
Hide file tree
Showing 27 changed files with 153 additions and 1,088 deletions.
65 changes: 44 additions & 21 deletions src/linkeddata_api/domain/label.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,30 @@ def get(
"""
Returns a label or None if no label found.
"""
query = f"""
template = Template(
"""
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX schema: <https://schema.org/>
PREFIX sdo: <http://schema.org/>
SELECT DISTINCT ?label
WHERE {{
VALUES (?labelProperty) {{
WHERE {
VALUES (?labelProperty) {
(skos:prefLabel)
}}
<{uri}> ?labelProperty ?label .
}}
(rdfs:label)
(dcterms:title)
(schema:name)
(sdo:name)
(dcterms:identifier)
}
<{{ uri }}> ?labelProperty ?label .
}
LIMIT 1
"""
)
query = template.render(uri=uri)

result = data.sparql.post(query, sparql_endpoint).json()

Expand All @@ -41,28 +55,37 @@ def _get_from_list_query(uris: list[str]) -> str:
template = Template(
"""
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
SELECT DISTINCT ?uri (SAMPLE(?_label) AS ?label)
PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX schema: <https://schema.org/>
PREFIX sdo: <http://schema.org/>
SELECT DISTINCT ?uri ?label
WHERE {
VALUES (?uri) {
{% for uri in uris %}
(<{{ uri }}>)
{% endfor %}
}
{% for uri in uris %}
{
?uri skos:prefLabel ?_label .
}
UNION {
# Also try and fetch label from TERN's controlled vocabularies.
SERVICE <https://graphdb.tern.org.au/repositories/tern_vocabs_core> {
?uri skos:prefLabel ?_label .
SELECT DISTINCT ?uri ?label
WHERE {
BIND(<{{ uri }}> as ?uri)
VALUES (?labelProperty) {
(skos:prefLabel)
(rdfs:label)
(dcterms:title)
(schema:name)
(sdo:name)
(dcterms:identifier)
}
?uri ?labelProperty ?label .
}
LIMIT 1
}
{% if not loop.last %}UNION{% endif %}
{% endfor %}
}
GROUP BY ?uri
"""
)
return template.render(uris=uris)
query = template.render(uris=uris)
return query


def get_from_list(
Expand Down
26 changes: 16 additions & 10 deletions src/linkeddata_api/domain/viewer/resource/json/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,16 +244,21 @@ def _get_types_and_properties(

for row in result["results"]["bindings"]:
if row["p"]["value"] == str(RDF.type):
type_label = uri_label_index.get(row["o"]["value"]) or domain.curie.get(
row["o"]["value"]
)
types.append(
domain.schema.URI(
label=type_label,
value=row["o"]["value"],
internal=uri_internal_index.get(row["o"]["value"], False),
if row["o"]["type"] != "bnode":
type_label = uri_label_index.get(row["o"]["value"]) or domain.curie.get(
row["o"]["value"]
)
)
types.append(
domain.schema.URI(
label=type_label,
value=row["o"]["value"],
internal=uri_internal_index.get(row["o"]["value"], False),
)
)
else:
# TODO: handle types that have bnode values
# E.g. /viewers/general?uri=http://linked.data.gov.au/dataset/ausplots/site-ntabrt0001&sparql_endpoint=https://graphdb.tern.org.au/repositories/knowledge_graph_core
continue
else:
predicate_label = domain.curie.get(row["p"]["value"])
predicate = domain.schema.URI(
Expand Down Expand Up @@ -317,7 +322,8 @@ def _get_types_and_properties(
for p in properties:
if p.predicate.value == predicate.value:
found = True
p.objects.append(item)
if item not in p.objects:
p.objects.append(item)

if not found:
properties.append(
Expand Down
1 change: 0 additions & 1 deletion src/linkeddata_api/views/api_v1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

# import all sub modules with views registered with blueprint
from . import ontology_viewer
from . import vocab_viewer
from . import version_info
from . import rdf_tools
from . import viewer
113 changes: 10 additions & 103 deletions src/linkeddata_api/views/api_v1/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,14 @@ components:
type: string
created:
title: The date when the resource was created
type: string
oneOf:
- type: string
nullable: true
modified:
title: The date when the resource was modified
type: string
oneOf:
- type: string
nullable: true
Resource:
title: Resource
type: object
Expand Down Expand Up @@ -174,6 +178,8 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/EntrypointItemList"
"404":
description: The supplied `viewer_id` value was not found
"502":
description: Gateway error
/viewer/resource:
Expand Down Expand Up @@ -246,24 +252,14 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/Resource"
"400":
description: Client error
"404":
description: Resource of URI not found.
content:
text/html:
schema:
type: string
"500":
description: Internal server error
content:
text/plain:
schema:
type: string
"502":
description: Error communicating with the database.
content:
text/html:
schema:
type: string

/ontology_viewer/classes/flat:
get:
Expand Down Expand Up @@ -302,95 +298,6 @@ paths:
type: string
"502":
description: Gateway error

/vocab_viewer/nrm/vocabs:
get:
tags:
- NRM vocabularies
summary: Get a list of NRM protocol vocabularies
description: Get a list of concept schemes and collections for the NRM protocol.
responses:
"200":
description: A list of concept schemes and collections.
content:
application/json:
schema:
type: array
items:
title: Vocabulary item
type: object
properties:
id:
title: IRI of item
type: string
label:
title: Label of item
type: string
description:
title: The description of the item
type: string
created:
title: The date when the resource was created
type: string
modified:
title: The date when the resource was modified
type: string
"502":
description: Gateway error

/vocab_viewer/nrm/resource:
get:
tags:
- NRM vocabularies
summary: Get a resource's description
description: A JSON payload used to render frontend user-interfaces.
parameters:
- in: query
name: uri
schema:
type: string
required: true
description: URI of the resource.
examples:
nrm:
summary: NRM index
value: https://linked.data.gov.au/def/nrm
- in: query
name: sparql_endpoint
schema:
type: string
required: true
description: SPARQL endpoint
examples:
nrm:
summary: NRM SPARQL endpoint
value: https://graphdb.tern.org.au/repositories/dawe_vocabs_core
responses:
"200":
description: A resource's description
content:
application/json:
schema:
type: object
properties:
uri:
type: string
label:
type: string
types:
type: array
items:
$ref: "#/components/schemas/URI"
properties:
type: array
items:
$ref: "#/components/schemas/PredicateObjects"
"404":
description: Resource with URI not found
content:
text/plain:
schema:
type: string

/rdf_tools/convert:
post:
Expand Down
9 changes: 4 additions & 5 deletions src/linkeddata_api/views/api_v1/viewer/entrypoint.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from flask import Response
from werkzeug.exceptions import HTTPException
from flask import abort
from flask_tern import openapi

from linkeddata_api.views.api_v1.blueprint import bp
Expand Down Expand Up @@ -31,10 +30,10 @@ def get_entrypoint(viewer_id: str):
sparql_endpoint = obj["sparql_endpoint"]
items = obj["func"](sparql_endpoint)
except ViewerIDNotFoundError as err:
raise HTTPException(str(err), Response(str(err), 404)) from err
abort(404, str(err))
except (RequestError, SPARQLResultJSONError) as err:
raise HTTPException(err.description, Response(err.description, 502)) from err
abort(502, err.description)
except Exception as err:
raise HTTPException(str(err), Response(str(err), 500)) from err
abort(500, err)

return jsonify(items, headers={"cache-control": "max-age=600, s-maxage=3600"})
23 changes: 9 additions & 14 deletions src/linkeddata_api/views/api_v1/viewer/resource.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import logging

from flask import request, Response
from werkzeug.exceptions import HTTPException
from flask import request, Response, abort
from flask_tern import openapi

from linkeddata_api.views.api_v1.blueprint import bp
Expand Down Expand Up @@ -29,9 +28,11 @@ def get_resource():
True if include_incoming_relationships == "true" else False
)

if uri is None or sparql_endpoint is None:
err_msg = "Required query parameters 'uri' or 'sparql_endpoint' was not provided."
raise HTTPException(err_msg, Response(err_msg, 404))
if not uri or not sparql_endpoint:
err_msg = (
"Required query parameters 'uri' or 'sparql_endpoint' was not provided."
)
abort(400, err_msg)

logger.info(
"""
Expand All @@ -57,17 +58,11 @@ def get_resource():
uri, sparql_endpoint, format_, include_incoming_relationships
)
except SPARQLNotFoundError as err:
raise HTTPException(err.description, Response(err.description, 404)) from err
abort(404, err.description)
except (RequestError, SPARQLResultJSONError) as err:
raise HTTPException(
description=err.description,
response=Response(err.description, status=502),
) from err
abort(502, err.description)
except Exception as err:
raise HTTPException(
description=str(err),
response=Response(str(err), mimetype="text/plain", status=500),
) from err
abort(500, err)

return Response(
result,
Expand Down
1 change: 0 additions & 1 deletion src/linkeddata_api/views/api_v1/vocab_viewer/__init__.py

This file was deleted.

2 changes: 0 additions & 2 deletions src/linkeddata_api/views/api_v1/vocab_viewer/nrm/__init__.py

This file was deleted.

27 changes: 0 additions & 27 deletions src/linkeddata_api/views/api_v1/vocab_viewer/nrm/resource.py

This file was deleted.

Loading

0 comments on commit cbea718

Please sign in to comment.