Categories as first class objects

Lev Eliezer Israel edited this page Aug 20, 2017 · 8 revisions

In August 2017, we started treating Categories as first class objects. Previously, the category tree was implied by categories on Index records.

The Category object is defined in sefaria/model/Category.py, along with the OO table of contents tree.

From now on, when an Index record is posted, the category that it is in must exist. If the category does not exist, then the Index save will fail with a InputError Exception, and an Index post will return a JSON object with an error as its only key.

Structure of the object

Category objects require path:

  • path: a list of primary titles of categories that form the path of ancestors to this one. The current category's title is included in the path.

And either titles or sharedTitle:

  • titles: a titles block, identical to other title blocks - for Index records or Terms
  • sharedTitle: a string key for an existing Term object.

Derived Attributes:

  • lastPath is derived from the path attribute, and doesn't need to be specified on object creation.
  • depth is derived from the path attribute, and doesn't need to be specified on object creation.

Optionally, they can have:

  • enDesc: An English language description
  • heDesc: A Hebrew language description

The Category API

A new API exists as api/category. It accepts POST requests to create new categories, and GET requests to look up categories.

POST

POST requests needs a full valid category object in the json attribute of the POST body. Note that the parent of the category must already exist. When creating more than one category, the ancestors must be created in order. See "Creating a new Category", below.

GET

GET requests take a full category path in the request, e.g. /api/category/Tanakh/Torah/Genesis, and return the full category object found. The above request would return:

{
  "path": [
    "Tanakh",
    "Torah"
  ],
    "titles": [
    {
      "lang": "en",
      "text": "Torah",
      "primary": true
    },
    {
      "lang": "he",
      "text": "תורה",
      "primary": true
    }
  ],
  "lastPath": "Torah"
}

If the category is not found, the returned object will have an error attribute. If any element of the path is found, the API will return the closest parent in an attribute called closest_parent. This is useful for proactively looking up a category before posting an Index to it.

E.g. a GET request to /api/category/Tanakh/Torah/Genesis/Bob/Dob returns:

{
  "closest_parent": {
    "path": [
      "Tanakh",
      "Torah"
    ],
    "titles": [
      {
        "lang": "en",
        "text": "Torah",
        "primary": true
      },
      {
        "lang": "he",
        "text": "תורה",
        "primary": true
      }
    ],
    "lastPath": "Torah"
  },
  "error": "Category not found"
}

Creating a new Category

On the cli:

    c = Category()
    c.add_primary_titles("New Category", u"חדשנית")
    c.path = ["Root", "Parent", "New Category"]
    c.save()

With the API:

Send a POST request to /api/category with a complete serialized category record in the json attribute of the POST body. e.g.:

  {'path': ['Root', 'Parent', 'New Category'],
  'titles': [{'lang': 'en', 'primary': True, 'text': 'New Category'},
  {'lang': 'he', 'primary': True, 'text': 'חדשנית'}]}
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.