This repo will contain code for the REST APIs to access the database containing 'cleaned' inscriptions from Epigraphia Carnatica (EC). See 'Cleaning' Epigraphia Carnatica for Knowledge Graphs for details on the (currently manual) process of obtaining cleaned information from EC.
The database is being built privately and step-by-step. Once the backend and frontend are in place, the database is planned to be hosted online. Building on this, the database is intended to feed into a project to build knowledge graphs from the inscriptions in EC. This is planned as a prototype.
Access the prototype at https://epigraphiacarnatica.pythonanywhere.com/ To use the APIs, use this as the base url to which to add the rest of the path.
The following ER schema has been developed:
EC is a series of volumes (here called source_text). Each volume has chapter-like geographical subdivisions (here called source_text_chapter). The real world 'object' is the inscription itself (called inscription), whose information is spread across the book under different headings, but using a single numbering for the geographical subdivision. Primarily, this is three-fold: the inscription text in Indic script, inscription text in 'Roman' (Latin) characters, and translation in English. At this stage, the project only involves itself with the latter two (called transliteration and translation respectively). Each inscription is associated with a location (represented by the location object).
The backend will be developed in Python using the Django framework.
Some thoughts:
-
Django is chosen as it enables rapid development. Python was a requirement keeping in mind extensibility to knowledge graphs, AI and NLP through Python support in such software.
-
Resources to learn Django:
-
Django documentation, especially about models, fields and querying.
-
Developing REST applications in plain Django or with Django REST Framework. Both tutorials are brilliant and lay out the costs of choosing either approach. In this project, plain Django is used.
-
The Django admin portal provides CRUD operations on database through a UI and obliviates a good deal of rationale for generating own data entry portal involving Auth. Further customization through this tutorial. Customizing forms to have multiple models in the same form - look at this.
-
Free small-scale hosting of Python based applications including web apps at Python Anywhere.
-
Solving a probelm with models and forms: my gist on the issue
Register APIs are meant to be create or update i.e., upsert.
Get APIs are read-only. (Here, the semantics of get is that of fetching, and not that of HTTP GET method. Thus, get is sometimes performed using POST as well)
- Register the text
Request:
POST /api/v1/source_text
{
"title": "",
"subtitle": "",
"series": "",
"volume": "",
"author": "",
"publisher": "",
"publication_place": "",
"publication_year": ""
}
Note: title
is the only mandatory field, other fields can be blank
Response:
{
"status": 200,
"message": "Source text registered successfully",
"data": {
"id": ,
"title": "",
"subtitle": "",
"series": "",
"volume": "",
"author": "",
"publisher": "",
"publication_place": "",
"publication_year": ""
}
}
Errors:
HTTP Status | Error Condition |
---|---|
400, Bad Request | If title is blank |
- Get source text by id
Request:
GET /api/v1/source_text/<id:int>
Response:
{
"status": 200,
"message": "Successfully found this record"
"data": {
"id": ,
"title": "",
"series": "",
"volume": "",
"author": "",
"publisher": "",
"publication_place": "",
"publication_year": ""
}
}
Errors:
HTTP Status | Error Condition |
---|---|
404, Not Found | If no text matches with request |
- Get all registered texts
Request:
GET /api/v1/source_text
Response:
{
"status": 200,
"message": "Successfully found these records",
"source_texts": [
{
"id": ,
"title": "",
"subtitle": "",
"series": "",
"volume": "",
},
...
]
}
- Register the chapter
Request:
POST /api/v1/source_text_chapter
{
"chapter_title": "",
"source_text": {
"id": ,
"title": "",
"subtitle": "",
"series": "",
"volume": ""
}
}
Note: chapter_title
is a mandatory field. To identify source_text
provide either the id
or a combination of the other attributes.
Response:
{
"status": 200,
"message": "Chapter registered successfully",
"data": {
"chapter_id": ,
"chapter_title": "",
"source_text": {
"id": ,
"title": "",
"subtitle": "",
"series": "",
"volume": "",
}
}
}
Errors:
HTTP Status | Error Condition |
---|---|
400, Bad Request | 1. If chapter title is blank or if no source text is provided |
2. If no source text matches or more than one source texts match with provided information |
- Get chapter by id
Request:
GET /api/v1/source_text_chapter/<id:int>
Response:
{
"status": 200,
"message": "Successfully found this record",
"data": {
"chapter_id": ,
"chapter_title": "",
"source_text": {
"id": ,
"title": "",
"subtitle": "",
"series": "",
"volume": "",
}
}
}
Error:
HTTP Status | Error Condition |
---|---|
404, Not Found | If no chapter matches the id |
- Get all registered chapters for a source text
Request:
POST /api/v1/source_text_chapter/search
{
"source_text": {
"id": ,
"title": "",
"subtitle": "",
"series": "",
"volume": ""
}
}
Note: To identify source_text
provide either the id
or a combination of the other attributes.
Response:
{
"status": 200,
"message": "Successfully found these records",
"data": [
{
"chapter_id": "",
"chapter_title": "",
"source_text": {
"id": ,
"title": "",
"subtitle": "",
"series": "",
"volume": ""
}
},
...
]
}
- Register the location
Request:
POST /api/v1/location
{
"location_name": "",
"coordinates": {
"latitude": ,
"longitude":
}
}
Note: location_name
and coordinates
are mandatory fields. latitude
and longitude
are mandatory floating-point fields inside coordinates
Response:
{
"status": 200,
"message": "Location registered successfully",
"data": {
"location_id": ,
"location_name": "",
"coordinates": {
"latitude": ,
"longitude"
}
}
}
Errors:
HTTP Status | Error Condition |
---|---|
400, Bad Request | If location_name or coordinates is blank |
2Get a location by id
Request:
GET /api/v1/location/<id:int>
Response:
{
"status": 200,
"message": "Successfully found this record",
"data": {
"location_id": ,
"location_name": "",
"coordinates": {
"latitude": ,
"longitude"
}
}
}
Error:
HTTP Status | Error Condition |
---|---|
404, Not Found | If no location matches the id |
3Get all locations
Request:
GET /api/v1/location
Response:
{
"status": 200,
"message": "Successfully found these records",
"data": []
}
- Register inscription text and/or transliteration and/or translation for an inscription
Request:
POST /api/v1/inscription
{
"chapter": {
"id": ,
"title": ""
},
"location_id": ,
"inscription_id": ,
"inscription_number": "",
"inscription_text_header": "",
"text": "",
"inscription_text_footnotes": "",
"translation_header": "",
"translation": "",
"translation_footnotes": "",
"transliteration_header": "",
"transliteration": "",
"transliteration_footnotes": ""
}
Note: Provide either id
or title
to identify chapter. inscription_number
cannot be null. inscription_id
is provided for programmatic upsert and is not mandatory. The backend will first check if record exists, and then update the translation and transliteration attributes. Else, it will insert into the database and create the foreign key relations.
Response:
{
"status": 200,
"message": "Successfully registered translation and/or transliteration",
"data": {
"source_text": {
"id": ,
"title": "",
"subtitle": "",
"series": "",
"volume": "",
"author": "",
"publisher": "",
"publication_place": "",
"publication_date": ""
},
"chapter": {
"id": ,
"title": "",
},
"location": {
"id": ,
"name": "",
"coordinates": {
"latitude": ,
"longitude"
}
},
"inscription_id": ,
"inscription_number": "",
"inscription_text_header": "",
"text": "",
"inscription_text_footnotes": "",
"translation_header": "",
"translation": "",
"translation_footer": "",
"transliteration_header": "",
"transliteration": "",
"transliteration_footer": ""
}
}
Error:
HTTP Status | Error Condition |
---|---|
400, Bad Request | 1. If inscription_id is absent and if chapter info. or inscription_number are missing |
2. If no chapter matches or more than one chapters match with provided info. | |
404, Not Found | If inscription_id is supplied but no inscription matches it |
- Get complete inscription object by id
Request:
GET /api/v1/inscription/<inscription_id:int>
Response:
{
"status": 200,
"message": "Successfully found this record",
"data": {
"source_text": {
"id": ,
"title": "",
"subtitle": "",
"series": "",
"volume": ""
"author": "",
"publisher": "",
"publication_place": "",
"publication_date": ""
},
"chapter": {
"id": ,
"title": "",
},
"location": {
"id": ,
"name": "",
"coordinates": {
"latitude": ,
"longitude"
}
},
"inscription_id": ,
"inscription_number": "",
"inscription_text_header": "",
"text": "",
"inscription_text_footnotes": "",
"translation_header": "",
"translation": "",
"translation_footer": "",
"transliteration_header": "",
"transliteration": "",
"transliteration_footer": ""
}
}
Error:
HTTP Status | Error Condition |
---|---|
404, Not Found | If no inscription matches the id |
- Get inscriptions by text, chapter, location or inscription number
Request:
POST /api/v1/inscription/search
{
"source_text": {
"id": ,
"title": "",
"subtitle": "",
"series": "",
"volume": ""
},
"chapter": {
"id": ,
"chapter_title": ""
},
"location": {
"id": ,
"location_name": ""
},
"inscription_number":
}
Note:
- To identify
source_text
provide either theid
or a combination of the other attributes. Some such information is necessary. To identifychapter
provide either itsid
orchapter_title
. To identifylocation
provide either itsid
orlocation_name
. None of the attributes are truly mandatory for the API, they act only as filters. - In the case of
source_text
,chapter
andlocation
, theid
if provided will be used before looking for the other attributes.
Response:
{
"status": 200,
"message": "Successfully found these records"
"data": [
{
"source_text": {
"id": ,
"title": "",
"subtitle": "",
"series": "",
"volume": ""
"author": "",
"publisher": "",
"publication_place": "",
"publication_date": ""
},
"chapter": {
"id": ,
"title": "",
},
"location": {
"id": ,
"name": "",
"coordinates": {
"latitude": ,
"longitude"
}
}
"inscription_id": ,
"inscription_number": "",
"inscription_text_header": "",
"text": "",
"inscription_text_footnotes": "",
"translation_header": "",
"translation": "",
"translation_footer": "",
"transliteration_header": "",
"transliteration": "",
"transliteration_footer": ""
},
...
]
}
Error:
HTTP Status | Error Condition |
---|---|
404, Not Found | If no inscription matches the filters |