Introduction
This section describes the new ShareVDE Subject API, introduced in December 2021. Subjects are a complicated matter from a functional and API perspective: for that reason, we decided to create a specific section to better focus on them.
The last part illustrates the REST endpoints and the GraphQL queries used for interacting with subjects. Note that the examples are often truncated because they are available in our PostMan API Collection.
Subjects are clusters
ShareVDE entities are clusters. That means a single entity could potentially receive multiple contributions from the institutions that form what we call a ShareVDE tenant.
Subjects follow that rule, but at the same time, their structure is a bit more articulated because they introduce some intermediate entities we will describe earlier.
Domain Model
The following picture illustrates the Subject Domain Model.
See also the following slide, which focuses on the different layers in the Subject domain:
Work
A Work is, at time of writing, the only ShareVDE entity that can have zero, one or multiple subjects. That means the association between works and subjects is defined in the domain model but the information about subjects, for example for searching purposes, can be made available also at opus and publication level.
Subject
A Subject is a ShareVDE entity which determines and describes the intellectual or artistic content and the genre/form characteristics of a given resource. A ShareVDE Subject doesn't have a specific type itself: it's the relationship between it and the owning Work that qualifies it in several ways (e.g. name, title, topical).
Subject Variants
A subject can have one or more variants: each variant is a Subject entity connected through the main form through the "variant" qualifier.
Heading Slice
A subject instance consists of one or multiple ordered heading slices.The ordered set of slices forms the so called "subject heading", which is the text usually displayed in OPACs.
For example the following except from a MARC record:
630 $aBible $lEnglish $xVersion
forms the subject heading as follows:
Bible -- English -- Version
In the example above each token between, starting with or ending with "--" is what we call HeadingSlice. Following that rule, the example produces three slices:
- Bible
- English
- Version
An HeadingSlice is not just a simple text: it is itself an Entity which associates the text (e.g. Bible) with a ShareVDE entity called Concept.
Concept
An abstract representation of a ShareVDE entity (i.e. cluster) which can be connected to a heading slice. Concretely, it corresponds to a subset of ShareVDE clusters (e.g. Opus, Agent, Date, Event, Topic).
This because the ShareVDE domain model includes entities that cannot be a concept (e.g. Work, Publication, Instances, Agent Type).
In case a given slice doesn't map to a known concept type, a GenericConcept cluster is created. It is a valid ShareVDE cluster, with few information like URI and heading (the owning slice text).
In the heading example above, we will have three heading slices:
- Bible => https://svde.org/opuses/82938 (an Opus)
- English => https://svde.org/languages/eng (a Language)
- Version => https://svde.org/concepts/83974384 (a Generic Concept)
REST API
Subjects can be retrieved in different ways. The usual scenario is when the requestor wants to retrieve the subjects connected to a given Work / Publication. In that case here's the request:
https://svde.org/work/{workId}/subjects
and the corresponding response, where you can see three subjects:
- A subject (https://svde.org/subjects/702) which consists of the following slices
- Library orientation for school children
- https://svde.org/concepts/1639399888501
- United States.
- https://svde.org/places/6252001
- Library orientation for school children
- A subject (https://svde.org/subjects/703) which consists of the following slices
- School libraries
- https://svde.org/concepts/1639399888505
- Activity programs
- https://svde.org/concepts/1639399888508
- United States.
- https://svde.org/places/6252001
- School libraries
- A subject (https://svde.org/subjects/704) which consists of the following slices
- Media programs (Education)
- https://svde.org/concepts/1639399888512
- Media programs (Education)
{
"_embedded": {
"resourceList": [
{
"heading": [
{
"text": "Library orientation for school children",
"_links": {
"concept": {
"href": "https://svde.org/concepts/1639399888501"
}
}
},
{
"text": "United States.",
"_links": {
"concept": {
"href": "https://svde.org/places/6252001"
}
}
}
],
"_links": {
"self": {
"href": "https://svde.org/subjects/702"
},
"provenances": {
"href": "https://svde.org/subjects/702/provenances"
},
"subjectType": {
"href": "https://svde.org/subjectTypes/top"
}
}
},
{
"heading": [
{
"text": "School libraries",
"_links": {
"concept": {
"href": "https://svde.org/concepts/1639399888505"
}
}
},
{
"text": "Activity programs",
"_links": {
"concept": {
"href": "https://svde.org/concepts/1639399888508"
}
}
},
{
"text": "United States.",
"_links": {
"concept": {
"href": "https://svde.org/places/6252001"
}
}
}
],
"_links": {
"self": {
"href": "https://svde.org/subjects/703"
},
"provenances": {
"href": "https://svde.org/subjects/703/provenances"
},
"subjectType": {
"href": "https://svde.org/subjectTypes/top"
}
}
},
{
"heading": [
{
"text": "Media programs (Education)",
"_links": {
"concept": {
"href": "https://svde.org/concepts/1639399888512"
}
}
}
],
"_links": {
"self": {
"href": "https://svde.org/subjects/704"
},
"provenances": {
"href": "https://svde.org/subjects/704/provenances"
},
"subjectType": {
"href": "https://svde.org/subjectTypes/top"
}
}
}
]
},
Note that being attached to a given Work, each subject provides also its qualification. In the example above the three subjects are all topical subjects (subjectType is https://svde.org/subjectTypes/top) The second endpoint allows to retrieve a specific subject, still belonging to a parent work:
https://svde.org/work/{workId}/subjects/702
The response contains one element of the response above, which is the subject we requested. It's possible to request a subject regardless its relationship with a work. In that case, the request is
https://svde.org/subjects/702
As you can imagine, the response is similar to the endpoint above with the difference that in this context we don't have any specific qualification (there's no Work ownership which qualifies the subject). As a consequence of that, the "subjectType" link reference is not in the response.
The last REST endpoint is used for typeahead search. The ShareVDE advanced search UI provides such features for allowing the end user to select a given subject that will be used as a publication search criteria.
The endpoint in this case:
https://svde.org/subjects?q=histo
It provides a parameter which consists of the search term entered by the user. The response is a bit different from the examples above because each subject contains the whole subject heading rebuilt from the matching slices, together with highlighting snippets for making evidence about the match (see the <b></b> html tags in the returned headings):
{
"_embedded": {
"resourceList": [
{
"uri": "https://svde.org/subjects/702",
"preferredHeading": "Library orientation for school children -- United <b>State</b>s"
},
{
"uri": "https://svde.org/subjects/703",
"preferredHeading": "School libraries -- Activity programs -- United <b>State</b>s"
},
...
GraphQL API
For each endpoint described in the previous section, there's a corresponding GraphQL query available. Specifically, we can retrieve the subjects of a given work:
query Subjects($uri: String!) {
work(uri: $uri) {
subjects {
resources {
uri
heading {
text
concept {
... on GenericConcept {
uri
}
... on Topic {
uri
}
... on Date {
uri
}
... on Event {
uri
}
... on Place {
uri
}
... on Genre {
uri
}
... on Form {
uri
}
... on Opus {
uri
}
... on Person {
uri
}
... on Organisation {
uri
}
... on Family {
uri
}
... on Meeting {
uri
}
}
}
}
}
}
}
Note the usage of the "... on" construct: this is because a Concept is an abstract class and it doesn't provide any specific attribute. We need to ask what needs to be done case by case. The second query retrieves the information about a given subject. Note the heading is split across several slices in the response:
query Subject($uri: String!) {
subject(uri: $uri) {
uri
heading {
text
concept {
...
...
{
"data": {
"subject": {
"uri": "https://svde.org/subjects/703",
"heading": [
{
"text": "School libraries",
"concept": {
"uri": "https://svde.org/concepts/1639399888505"
}
},
{
"text": "Activity programs",
"concept": {
"uri": "https://svde.org/concepts/1639399888508"
}
},
{
"text": "United States.",
"concept": {
"uri": "https://svde.org/places/6252001"
}
}
]
}
}
}
The last query provides a fulltext/typeahead search capability on top of subjects. Note that, due to the GraphQL data structures overhead, it is strongly recommended to use the REST version for serving typeahead services.
query Subjects($q: String!) {
subjects(tql:{q: $q}) {
resources {
uri
heading {
text
}
}
}
}
the response, differently from the REST endpoint, doesn't rebuild the subject heading. Instead it provides the highlighting snippets directly within the slices:
{
"data": {
"subjects": {
"resources": [
{
"uri": "https://svde.org/subjects/702",
"heading": [
{
"text": "Library orientation for school children"
},
{
"text": "United <b>State</b>s"
}
]
},
{
"uri": "https://svde.org/subjects/703",
"heading": [
{
"text": "School libraries"
},
{
"text": "Activity programs"
},
{
"text": "United <b>State</b>s"
}
]
},
{
"uri": "https://svde.org/subjects/707",
"heading": [
{
"text": "College students"
},
{
"text": "United <b>State</b>s"
},
{
"text": "Finance, Personal."
}
]
},
{
"uri": "https://svde.org/subjects/708",
"heading": [
{
"text": "Youth"
},
{
"text": "United <b>State</b>s"
},
{
"text": "Finance, Personal."
}
]
},
{
"uri": "https://svde.org/subjects/709",
"heading": [
{
"text": "Young adults"
},
{
"text": "United <b>State</b>s"
},
{
"text": "Finance, Personal."
}
]
},
{
"uri": "https://svde.org/subjects/723",
"heading": [
{
"text": "Dissertations, Academic"
},
{
"text": "United <b>State</b>s"
},
{
"text": "Bibliography"
}
]
},
{
"uri": "https://svde.org/subjects/724",
"heading": [
{
"text": "Dissertations, Academic"
},
{
"text": "United <b>State</b>s"
}
]
}
]
}
}
}
The following query is instead a subject which provides a variant.
query {
subject(uri: "https://svde.org/subjects/721"){
notes
heading {
concept {
__typename
... on Genre {
uri
label
}
... on GenericConcept {
uri
label
altLabels
}
}
}
variants {
resources {
uri
heading {
concept {
__typename
... on GenericConcept {
uri
label
altLabels
}
}
}
}
}
}
}
and here's the response:
{
"data": {
"subject": {
"notes": [],
"heading": [
{
"concept": {
"__typename": "Genre",
"uri": "https://svde.org/genres/gf2014026333",
"label": "Fantasy fiction"
}
},
{
"concept": {
"__typename": "GenericConcept",
"uri": "https://svde.org/concepts/1695141910611",
"label": "Congresses.",
"altLabels": []
}
}
],
"variants": {
"resources": [
{
"uri": "https://svde.org/subjects/701",
"heading": [
{
"concept": {
"__typename": "GenericConcept",
"uri": "https://svde.org/concepts/1695141910541",
"label": "Fantasy",
"altLabels": []
}
}
]
}
]
}
}
}
}