Skip to content

HTTP REST API and PostgreSQL schemas for TermBase eXchange V3 data.

License

Notifications You must be signed in to change notification settings

BYU-TRG-Team/baseterm-api

Repository files navigation

BaseTerm API

HTTP REST API and PostgreSQL schemas built for TermBase eXchange (TBX) v3. The API currently supports the TBX-Basic dialect and Data Category as Attribute (DCA) style. The API and PostgreSQL schemas are part of the BaseTerm web application.

Installation

Contact the BYU TRG

Before installing any instance of the BaseTerm API, please reach out to the BYU TRG at byutrg@gmail.com to establish a dialogue with the team. Please include any necessary contact info so that we can reach out to you for important version updates.

Server Requirements

  • PostgreSQL 14.x
  • Node.js 16.x
  • Python 3.9.x

Setup PostgreSQL instance

A PostgreSQL (postgres) instance will be needed for the BaseTerm API application. A database will also need to be created in the postgres instance.

Install

Please reference the postgres downloads for installers for various platforms.

Setup database schemas

The postgres database will need to be setup with proper schemas using the node-pg-migrate postgres migration tool. The tool first needs to be installed using NPM. Once installed, the tool is run with a connection string for the postgres database.

npm ci
DATABASE_URL=<postgres database connection string> npm run migrate up

Please reference the node-pg-migrate docs for further use of this migration tool.

Build and deploy API

Third Party Requirements

  • Rollbar logging token (optional). Please contact the BYU TRG team to obtain this token. This is used to capture error logs.

Environment Variables

APP_ENV=<dev | prod>
PORT=<port number>
DATABASE_URL=<postgres database connection string>
AUTH_SECRET=<64-bit CSPRNG secret>
ROLLBAR_API_TOKEN=<Rollbar logging token> *Not required*
MAX_CONNECTION_POOL=<Max connections to pool for postgres database. Default is 20.> *Not required*
API_ROUTE_BASE=<API endpoint route base. Should not end with a forward slash (ex. baseterm/api). Default is an empty string.> *Not required*

Build and deploy with Docker

Install Docker

Install the Docker Engine on the host machine. Docker Engine is currently available on a variety of Linux distros, macOS, and Windows 10 through Docker Desktop, and as a static binary installation.

Create a Docker image

Example

docker build --tag baseterm-api .
Run the docker container

Example

docker run \
  -d \
  --expose 3000 \
  -p 3000:3000 \
  --env-file ".env" \
  --name "baseterm-api" \
  baseterm-api

Build and deploy directly from host machine

Currently works on Linux, macOS, and Windows.

Install Python

Install Python 3.9.x on the host machine. Please reference the Python documentation for setup.

Build
npm ci
npm run build
pip3 install -r requirements.txt
Launch
npm run start

This launches a background process using pm2 and opens up the pm2 monitor. This monitor need not be kept open. Please reference the pm2 docs for interacting with the process.

Schemas

TbxElement

{
  Tbx = "tbx",
  TbxHeader = "tbxHeader",
  EncodingDesc = "encodingDesc",
  P = "p",
  RevisionDesc = "revisionDec",
  Change = "change",
  FileDesc = "fileDesc",
  PublicationStmt = "publicationStmt",
  SourceDesc = "sourceDesc",
  TitleStmt = "titleStmt",
  Title = "title",
  Note = "note",
  Text = "text",
  Body = "body",
  ConceptEntry = "conceptEntry",
  LangSec = "langSec",
  TermSec = "termSec",
  Term = "term",
  TermNoteGrp = "termNoteGrp",
  TermNote = "termNote",
  Back = "back",
  RefObjectSec = "refObjectSec",
  RefObject = "refObject",
  ItemSet = "itemSet",
  ItemGrp = "itemGrp",
  Item = "item",
  Admin = "admin",
  AdminGrp = "adminGrp",
  AdminNote = "adminNote",
  Descrip = "descrip",
  DescripGrp = "descripGrp",
  DescripNote = "descripNote",
  Date = "date",
  Ref = "ref",
  Transac = "transac",
  TransacGrp = "transacGrp",
  TransacNote = "transacNote",
  Xref = "xref",
}

TbxAuxElement

TbxElement.Admin |
TbxElement.AdminGrp |
TbxElement.Descrip |
TbxElement.DescripGrp |
TbxElement.Transac |
TbxElement.TransacGrp |
TbxElement.Note |
TbxElement.Ref |
TbxElement.Xref |
TbxElement.Date |
TbxElement.AdminNote |
TbxElement.DescripNote |
TbxElement.TransacNote

Termbase

{
  type: string;
  style: string;
  xmlns: string;
  name: string;
  termbaseUUID: UUID;
  xmlLang: string;
  enforceBasicDialect: boolean;
}

TermPreview

{
  uuid: UUID;
  termSecId: NullableString;
  id: NullableString;
  value: string;
  language: string;
  termbaseUUID: UUID;
  order: number;
}

TermPartialView

{
  synonyms: TermPreview[];
  translations: TermPreview[];
  conceptId: string;
  customers: string[];
  partOfSpeech: string;
  approvalStatus: string; 
  subjectField: string;
} & TermPreview

TermFullView

{
  conceptEntry: ConceptEntryPreview;
  languageSection: LanguageSectionPreview;
  auxElements: AuxElement[];
  termNotes: TermNote[];
}

ConceptEntryPreview

{
  uuid: UUID;
  id: string;
  termbaseUUID: string;
}

ConceptEntry

{
  languageSections: LanguageSectionPreview[];
  auxElements: AuxElement[];
} & ConceptEntryPreview

LanguageSectionPreview

{
  uuid: UUID;
  termbaseUUID: string;
  xmlLang: string;
  order: number;
}

LanguageSection

{
  conceptEntry: ConceptEntryPreview;
  auxElements: AuxElement[];
  terms: TermPreview[];
} & LanguageSectionPreview

AuxElement

{
  order: number;
  id?: NullableString;
  termbaseUUID?: UUID;
  target?: NullableString;
  xmlLang?: NullableString;
  datatype?: NullableString;
  type?: NullableString;
  auxElements?: AuxElement[];
  grpId?: NullableString;
  uuid: UUID;
  value: string;
  elementType: TbxAuxElement,
}

TermNotePreview

{
  uuid: UUID;
  xmlLang: NullableString;
  target: NullableString;
  termbaseUUID: UUID;
  type: string;
  value: string;
  order: number;
  elementType: TbxElement.TermNote | TbxElement.TermNoteGrp
}

TermNote

{
  id: NullableString;
  grpId: NullableString;
  datatype: NullableString;
  auxElements?: AuxElement[]
} & TermNotePreview

PersonRefObjectPreview

{
  uuid: UUID,
  id: string,
  source: "BaseTerm" | "External"
}

Endpoints

Parameters are required unless otherwise specified.


File Services


Validate

URL

/validate

HTTP METHOD

POST

Params

@tbxFile (FormData)

Responses

Status Code: 400 (Bad Request)

Body: {
  error: "Body Invalid"
}
Status Code: 400 (Bad Request)

Body: {
  error: "TBX File is invalid: 
  <error appended here>"
}
Status Code: 200 (Success)

Body: {
  tbx: TbxObject
}

Note

An example of a TbxObject can be found in the repository.


Import

URL

/import

HTTP METHOD

POST

Allowed Roles

Admin
Staff

Params

@tbxFile (FormData)
@name

Responses

Status Code: 400 (Bad Request)

Body: {
  error: "Body Invalid"
}
Status Code: 400 (Bad Request)

Body: {
  error: "TBX File is invalid: 
  <error appended here>"
}
Status Code: 202 (Accepted)

Body: {
  sessionId: UUID,
  termbaseUUID: UUID,
}

Note

The import endpoint launches a session. To subscribe to the session that is launched, the sessionId will need to be used with the session endpoint.


Export

URL

/export/:termbaseUUID

HTTP METHOD

GET

Allowed Roles

Admin
Staff

Responses

Status Code: 404 (Not Found)

Body: {
  error: "Resource not found"
}
Status Code: 202 (Accepted)

Body: {
  sessionId: UUID,
}

Note

The export endpoint launches a session. To subscribe to the session that is launched, the sessionId will need to be used with the session endpoint via HTTP SSE.


Session

URL

/session/:sessionId

HTTP METHOD

GET

Allowed Roles

Admin
Staff

Response Schema

{
  type?: "import" | "export",
  status?: "in progress" | "completed",
  conceptEntryNumber?: number;
  conceptEntryCount?: number;
  data?: string;
  error?: string;
  errorCode?: number;
}

Note

The session endpoint utilizes Server-Side Events (SSE), so the client will have to subscribe to the endpoint using EventSource.



Termbase


Get Termbase

URL

/termbase/:termbaseUUID

HTTP METHOD

GET

Allowed Roles

Admin
Staff
User

Responses

Status Code: 404 (Not Found)

Body: {
  error: "Resource not found"
}
Status Code: 200 (Success)

Body: {
  metadata: {
    languages: string[],
    partsOfSpeech: string[],
    customers: string[],
    conceptIds: string[],
    approvalStatuses: string[],
    subjectFields: string[],
    personRefs: PersonRefObjectPreview[],
  }
} & Termbase

Get All Termbases

URL

/termbases?page=:paginationPage

HTTP METHOD

GET

Allowed Roles

Admin
Staff
User

Responses

Status Code: 400 (Bad Request)

Body: {
  error: "Invalid query params supplied."
}
Status Code: 200 (Success)

Body: {
  termbases: Termbase[],
  pagination: {
    page: number;
    pageCount: number;
    perPage: number;
    totalCount: number;
  }
}

Create Termbase

URL

/termbase

HTTP METHOD

POST

Allowed Roles

Admin
Staff

Params

@name
@lang
@description (optional)

Responses

Status Code: 400 (Bad Request)

Body: {
  error: "Body Invalid"
}
Status Code: 409 (Conflict)

Body: {
  error: "A base already exists with the same name."
}
Status Code: 200 (Success)

Body: {
  uuid: UUID
}

Update Termbase

URL

/termbase/:termbaseUUID

HTTP METHOD

PATCH

Allowed Roles

Admin
Staff

Params

@type (optional)
@name (optional)
@enforceBasicDialect (optional)

Responses

Status Code: 400 (Bad Request)

Body: {
  error: "Body Invalid"
}
Status Code: 404 (Not Found)

Body: {
  error: "Resource not found"
}
Status Code: 409 (Conflict)

Body: {
  error: "A base already exists with the same name."
}
Status Code: 200 (Success)

Body: Termbase

Note

enforceBasicDialect is initially true when a termbase is either uploaded or created. Once set to false, the parameter can not be changed.

type can only be updated once enforceBasicDialect is set to false.


Delete Termbase

URL

/termbase/:termbaseUUID

HTTP METHOD

DELETE

Allowed Roles

Admin

Responses

Status Code: 204 (Success with no content)

Body: {}


Term


Get Term

URL

/termbase/:termbaseUUID/term/:termUUID

HTTP METHOD

GET

Allowed Roles

Admin
Staff
User

Responses

Status Code: 404 (Not Found)

Body: {
  error: "Resource not found"
}
Status Code: 200 (Success)

Body: TermFullView

Get All Terms

URL

/termbase/:termbaseUUID/terms?page=:paginationPage

HTTP METHOD

GET

Allowed Roles

Admin
Staff
User

Responses

Status Code: 404 (Not Found)

Body: {
  error: "Resource not found"
}
Status Code: 400 (Bad Request)

Body: {
  error: "Invalid query params supplied."
}
Status Code: 200 (Success)

Body: {
  terms: TermPartialView[],
  pagination: {
    page: number;
    pageCount: number;
    perPage: number;
    totalCount: number;
  }
}

Create Term

URL

/termbase/:termbaseUUID/term

HTTP METHOD

POST

Params

@langSecUUID
@value

Allowed Roles

Admin
Staff

Responses

Status Code: 400 (Bad Request)

Body: {
  error: "Body Invalid"
}
Status Code: 200 (Success)

Body: {
  uuid: UUID
}

Update Term

URL

/termbase/:termbaseUUID/term/:termUUID

HTTP METHOD

PATCH

Params

@id (optional)
@order (optional)
@value (optional)
@termSecId (optional)

Allowed Roles

Admin
Staff

Responses

Status Code: 400 (Bad Request)

Body: {
  error: "Body Invalid"
}
Status Code: 404 (Not Found)

Body: {
  error: "Resource not found"
}
Status Code: 200 (Success)

Body: TermPreview

Delete Term

URL

/termbase/:termbaseUUID/term/:termUUID

HTTP METHOD

DELETE

Allowed Roles

Admin
Staff

Responses

Status Code: 400 (Bad Request)

Body: {
  error: "Language Sections must have at least one term."
}
Status Code: 204 (Success with no content)

Body: {}


Term Note


Create Term Note

URL

/termbase/:termbaseUUID/termNote

HTTP METHOD

POST

Params

@isGrp
@type
@value
@termUUID

Allowed Roles

Admin
Staff

Responses

Status Code: 400 (Bad Request)

Body: {
  error: "Body Invalid"
}
Status Code: 200 (Success)

Body: {
  uuid: UUID
}

Update Term Note

URL

/termbase/:termbaseUUID/termNote/:termNoteUUID

HTTP METHOD

PATCH

Params

@id (optional)
@type (optional)
@value (optional)
@grpId (optional)
@target (optional)
@datatype (optional)
@langCode (optional)
@order (optional)

Allowed Roles

Admin
Staff

Responses

Status Code: 400 (Bad Request)

Body: {
  error: "Body Invalid"
}
Status Code: 400 (Bad Request)

Body: {
  error: "Target does not reference a known ID"
}
Status Code: 400 (Bad Request)

Body: {
  error: "ID is invalid. ID must follow convention for XML."
}
Status Code: 404 (Not Found)

Body: {
  error: "Resource not found"
}
Status Code: 409 (Conflict)

Body: {
  error: "A TBX element already exists with the same ID."
}
Status Code: 200 (Success)

Body: TermNotePreview

Delete Term Note

URL

/termbase/:termbaseUUID/termNote/:termNoteUUID

HTTP METHOD

DELETE

Allowed Roles

Admin
Staff

Responses

Status Code: 404 (Not Found)

Body: {
  error: "Resource not found"
}
Status Code: 204 (Success with no content)

Body: {}


Ref Object


Create Person Ref Object

URL

/termbase/:termbaseUUID/personRefObject

HTTP METHOD

POST

Allowed Roles

Admin
Staff
User

Params

@name
@email
@role
@id

Note

The resource will only be created if the requester's user id is the same as the request's id.

Responses

Status Code: 400 (Bad Request)

Body: {
  error: "Body Invalid"
}
Status Code: 400 (Bad Request)

Body: {
  error: "The supplied user id does not match the requester's user id."
}
Status Code: 400 (Bad Request)

Body: {
  error: "Person ID must be a UUID."
}
Status Code: 409 (Conflict)

Body: {
  error: "A TBX element already exists with the same ID."
}
Status Code: 200 (Success)

Body: {
  uuid: UUID
}


Language Section


Get Language Section

URL

/termbase/:termbaseUUID/langSec/:langSecUUID

HTTP METHOD

GET

Allowed Roles

Admin
Staff
User

Responses

Status Code: 404 (Not Found)

Body: {
  error: "Resource not found."
}
Status Code: 200 (Success)

Body: LanguageSection

Create Language Section

URL

/termbase/:termbaseUUID/langSec

HTTP METHOD

POST

Allowed Roles

Admin
Staff

Params

@entryUUID
@langCode
@initialTerm

Responses

Status Code: 400 (Bad Request)

Body: {
  error: "Body Invalid"
}
Status Code: 200 (Success)

Body: {
  uuid: UUID
}

Update Language Section

URL

/termbase/:termbaseUUID/langSec/:langSecUUID

HTTP METHOD

PATCH

Allowed Roles

Admin
Staff

Params

@langCode (optional)
@order (optional)

Responses

Status Code: 400 (Bad Request)

Body: {
  error: "Body Invalid"
}
Status Code: 404 (Not Found)

Body: {
  error: "Resource not found"
}
Status Code: 200 (Success)

Body: LanguageSectionPreview

Delete Language Section

URL

/termbase/:termbaseUUID/langSec/:langSecUUID

HTTP METHOD

DELETE

Allowed Roles

Admin
Staff

Responses

Status Code: 400 (Bad Request)

Body: {
  error: "Concept entries must have at least one language section."
}
Status Code: 204 (Success with no content)

Body: {}


Concept Entry


Get Concept Entry

URL

/termbase/:termbaseUUID/entry/:entryUUID

HTTP METHOD

GET

Allowed Roles

Admin
Staff
User

Responses

Status Code: 404 (Not Found)

Body: {
  error: "Resource not found"
}
Status Code: 200 (Success)

Body: ConceptEntry

Create Concept Entry

URL

/termbase/:termbaseUUID/entry

HTTP METHOD

POST

Allowed Roles

Admin
Staff

Params

@entryId
@initialLanguageSection
@initialTerm

Responses

Status Code: 409 (Conflict)

Body: {
  error: "A TBX element already exists with the same ID."
}
Status Code: 400 (Bad Request)

Body: {
  error: "ID is invalid. ID must follow convention for XML."
}
Status Code: 200 (Success)

Body: {
  uuid: UUID
}

Update Concept Entry

URL

/termbase/:termbaseUUID/entry/:entryUUID

HTTP METHOD

PATCH

Allowed Roles

Admin
Staff

Params

@id (optional)

Responses

Status Code: 400 (Bad Request)

Body: {
  error: "Body Invalid"
}
Status Code: 409 (Conflict)

Body: {
  error: "A TBX element already exists with the same ID."
}
Status Code: 400 (Bad Request)

Body: {
  error: "ID is invalid. ID must follow convention for XML."
}
Status Code: 404 (Not Found)

Body: {
  error: "Resource not found"
}
Status Code: 200 (Success)

Body: ConceptEntryPreview

Delete Concept Entry

URL

/termbase/:termbaseUUID/entry/:entryUUID

HTTP METHOD

DELETE

Allowed Roles

Admin
Staff

Responses

Status Code: 204 (Success with no content)

Body: {}


Aux Element


Create Aux Element

URL

/termbase/:termbaseUUID/auxElement

HTTP METHOD

POST

Allowed Roles

Admin
Staff

Params

@parentElementType (TbxElement)
@parentUUID
@value
@elementType
@type (optional)
@target (optional)

Responses

Status Code: 400 (Bad Request)

Body: {
  error: "Body Invalid"
}
Status Code: 404 (Not Found)

Body: {
  error: "Resource not found"
}
Status Code: 200 (Success)

Body: {
  uuid: UUID
}

Note

Although type is listed as an optional request parameter, the inclusion of this parameter depends on whether or not the auxiliary element being created requires a type attribute.


Update Aux Element

URL

/termbase/:termbaseUUID/auxElement/:auxElementUUID

HTTP METHOD

PATCH

Allowed Roles

Admin
Staff

Params

@elementType (TbxElement)
@id (optional)
@grpId (optional)
@order (optional)
@target (optional)
@langCode (optional)
@datatype (optional)
@type (optional)
@value (optional)

Responses

Status Code: 400 (Bad Request)

Body: {
  error: "Body Invalid"
}
Status Code: 400 (Bad Request)

Body: {
  error: "Target does not reference a known ID"
}
Status Code: 400 (Bad Request)

Body: {
  error: "ID is invalid. ID must follow convention for XML."
}
Status Code: 404 (Not Found)

Body: {
  error: "Resource not found"
}
Status Code: 409 (Conflict)

Body: {
  error: "A TBX element already exists with the same ID."
}
Status Code: 200 (Success)

Body: AuxElement

Delete Aux Element

URL

/termbase/:termbaseUUID/auxElement/:auxElementUUID

HTTP METHOD

DELETE

Allowed Roles

Admin
Staff

Params

@elementType (TbxElement)

Responses

Status Code: 400 (Bad Request)

Body: {
  error: "Body Invalid"
}
Status Code: 204 (Success with no content)

Body: {}