Astra Schedule API

  Previous topic Next topic JavaScript is required for the print function Mail us feedback on this topic! Mail us feedback on this topic!  

Introduction

Starting in Release 7.4, Ad Astra will expose an API for customers and third-parties to interface with the Astra Schedule and Platinum Analytics products. The API uses open standards and can be accessed by any tool set or language (.NET, Java, Python/Ruby, etc.).

 

The API can query all entities and relationships in the Astra Database and perform complex searches. Further, there is a transaction API for updating data in the Astra Database.

 

The Astra API is best described as a RESTful web service1, using standard HTTP2 or HTTPS3. What this means in practice is that data contained in the Astra Database can be queried using simple web requests. For example, http://schedule.xyz.edu/~api/entities/event/byid/... would request data for an event given its unique ID. This concept extends to data relationships as well as searches. Further, searches can be filtered using arbitrary expressions against any number of fields, sorted by multiple fields and broken into conveniently sized pages.

 

For efficiency and convenience for Web 2.0 applications, the data returned by the Astra API is encoded using the JSON4 data format (described by RFC 46275). The http://json.org web site has links to dozens of open source and free libraries that can be used to easily decode JSON data in almost any language.

Entity Metadata

An “entity” in the Astra Database is basically a row in a table, though not all tables are entity tables. All entities have certain fields in common:

 

Id – The unique identifier of the entity (a GUID6).

 

CreateDate – The datetime stamp set when the entity (row) was created.

 

CreateBy – The Id of the User that created the entity.

 

ModifiedDate – The datetime stamp of the last modification of the entity.

 

ModifiedBy – The Id of the User that last modified the entity.

 

RowVersion – An internal number used for transaction management.

 

Beyond these fields, many entities have a Name, but the other fields vary by table. The most concise, programmatic description available to describe an entity in Astra is found in JavaScript format in the web application. These files are used by the Web UI to properly decode, validate, format and parse data for an entity. The location (relative to the virtual directory) for these files is:

 

/javascript/astra/entities

 

For example, the /javascript/astra/entities/Section.js file contains a description of the Section entity.

Fields

The most primitive information is the field description object. This information is equivalent to the table columns (more or less) found in the Astra Database. For example, the Section entity contains these fields:

 

fields:

{

    Id: { type:'string' },

    TermId: { type:'string' },

    CampusId: { type:'string' },

    CourseDeliveryMethodId: { type:'string' },

    SectionTitle: { type:'string' },

    SectionCode: { type:'string' },

    DoNotOptimize: { type:'boolean' },

    DoNotOptimizeInstructor: { type:'boolean' },

    DoNotOptimizeTime: { type:'boolean' },

    CourseTitleId: { type:'string' },

    IsCanceled: { type:'boolean' },

    SISEnrollment: { type:'int' },

    SISMaxEnrollment: { type:'int' },

    AdjustedMaxEnrollment: { type:'int' },

    CalculatedSeats: { type:'int' },

    EstimatedEnrollment: { type:'int' },

    CensusEnrollment: { type:'int' },

    CensusEnrollmentDate: { type:'date' },

    CensusEnrollment2: { type:'int' },

    CensusEnrollmentDate2: { type:'date' },

    IsPreReq: { type:'boolean' },

    IsGradeable: { type:'boolean' },

    EnrollmentWaiting: { type:'int' },

    WaitingAvailCount: { type:'int' },

    WaitingCapacity: { type:'int' },

    IsLinkParent: { type:'boolean' },

    IgnoreInAnalysis: { type:'boolean' },

    ContainsCrossList: { type:'boolean' },

    SISCrossEnrlError: { type:'boolean' },

    LinkedSectionId: { type:'string' },

    SisKey: { type:'string' },

    LastSisUpdateDate: { type:'date' },

    LastImportedDate: { type:'date' },

    LastExportedDate: { type:'date' },

    RequiresAttention: { type:'boolean' },

    RequiresAttentionReason: { type:'string' },

    IsActive: { type:'boolean' },

    CreatedDate: { type:'date' },

    CreatedBy: { type:'string' },

    ModifiedDate: { type:'date' },

    ModifiedBy: { type:'string' },

    RowVersion: { type:'int' }

},

Associations (joins)

Beyond simple fields, the Astra Database defines associations between entities and describes these associations in the same file. These are contained in a “join” portion of the metadata. For example, a Room has some of each kind of association:

 

join :

{

    // one-to-one association (set)

    Building : { field:"BuildingId", type:"Building" },

    HvacZone : { field:"HvacZoneId", type:"HvacZone" },

    RoomType : { field:"RoomTypeId", type:"RoomType" },

    WorkflowDefinition : { field:"WorkflowDefinitionId",

type:"WorkflowDefinition" },

 

    // one-to-many association (edit)

    OptimizerSctMtgSuitRms : { type: "OptimizerSctMtgSuitRm",

isOwner: false, fkField: "RoomId", fkNullable: false},

    PrefRuleRoomItems : { type: "PrefRuleRoomItem",

isOwner: true, fkField: "RoomId", fkNullable: false},

    RoomConfigurations : { type: "RoomConfiguration",

isOwner: true, fkField: "RoomId", fkNullable: false},

    RoomConflictsByConflictRoomId : { type: "RoomConflict",

isOwner: true, fkField: "ConflictRoomId", fkNullable: false},

    RoomConflicts : { type: "RoomConflict", isOwner: true,

fkField: "RoomId", fkNullable: false},

    RoomFeatureQuantities : { type: "RoomFeatureQuantity",

isOwner: true, fkField: "RoomId", fkNullable: false},

    NotesByRecordId : { type: "Note", isOwner: true,

fkField: "RecordId", fkNullable: false,

fkTypeField: "NoteTypeId",

fkTypeValue: "ad950a8d-046b-4d25-b079-5845a0f5530a"},

    RoomPartitionsByPartitionRoomId : { type: "RoomPartition",

isOwner: true, fkField: "PartitionRoomId",

fkNullable: false},

    RoomPartitions : { type: "RoomPartition", isOwner: true,

fkField: "RoomId", fkNullable: false},

    ProfileItemsByDataValueId : { type: "ProfileItem", isOwner: true,

fkField: "DataValueId", fkNullable: false,

fkTypeField: "ValueDataTypeId",

fkTypeValue: "759385fd-0d7c-4f3f-95d2-2f6757cb5606"},

    TimetableSctMtgSuitRms : { type: "TimetableSctMtgSuitRm",

isOwner: false, fkField: "RoomId", fkNullable: false},

 

    // many-to-many association (add/remove)

    Regions : { relation: "RoomRegion", role: "RoomId",

type:"Region" },

    AdHocRequestSettings : { relation: "AdHocRequestSttngRoom",

role: "AdHocRequestSettingId", type:"AdHocRequestSetting" }

}

One-to-One

The simplest form of association is an entity that contains the Id of another. The properties for this type of association are as follows:

 

field – The name of the field that contains the Id value.

type – The type of entity to which this Id refers.

One-to-Many

These entries describe other entities that contain an Id value related to this type.

 

type – The type of the entity that contains an Id relating to this type.

 

isOwner – True if this entity owns the entities that contain its Id. Such entities are deleted when the owning entity is deleted.

 

fkField – The field in the related entity that contains the Id.

 

fkNullable – True if the fkField in the related entity should be set to null when the related entity is deleted.

 

fkTypeField – If present this is the name of a field in the relating entity that contains a discriminating value that specifies the type to which it is related. For example, a Note can reference many different entity types. Which type a particular Note references is stored in its NoteTypeId field, so this property would contain “NoteTypeId” to describe this.

 

fkTypeValue – This goes along with fkTypeField and is the value used to specify this type of entity. For example, the GUID “ad950a8d-046b-4d25-b079-5845a0f5530a” is stored in the NoteTypeId field of a Note to indicate that a Note references a Room.

Many-to-Many

To describe entities that relate in a many-to-many arrangement, the descriptor contains the following properties:

 

type – The type of entity related to this type.

relation – The name of the many-to-many association.

role – The field name of this entity type in the association.

 

This type of association is often called a matrix association and the table containing the Id pairs is called a matrix table.

Using Entity Metadata

The data described above comes into play when accessing the Astra API via the Query and Entity API’s. In particular, field names and association names are often

The Query API

The Query API is a simple ad-hoc query mechanism that can retrieve entities in whole or in part and with values obtained from related entities. This API is read only and is accessed using GET requests.

URL

The Query API is accessed via an HTTP(S) GET to a URL off of the root of the virtual directory. The components of the URL are as follows:

 

~api/query/type?fields=Field1,Field2

&filter=foo

&sortOrder=foo

&search=foo

&searchField=foo

&start=0

&limit=25

 

The components that are replaced by real values are highlighted. The meaning of the various parameters are as follows:

 

type – The entity type to retrieve (e.g., “section”).

fields – The names of the fields to retrieve.

filter – A filter expression to limit the returned entities. See Filter Expressions below for details.

sortOrder – The names of the fields by which to sort the returned entities. This is a comma-separated list of field names prefixed by “+” or “-“ to sort ascending or descending, respectively. For example, “+Name,-ModifiedDate”.

searchField – The field on which to search (must match the primary sort field).

search – The value to find in the result set. The position where this value should occur (based on sortOrder) is returned along with the page that contained that value.

start – The zero-based index of the first result entity the return. This is used to perform pagination and does not combine with search/searchField. The default is to start with the first item (0).

limit – The number of items to return in the result set. This limits both start and search results. The default is to return all results.

 

The result is encoded based on the option view parameter whose default is “JSON”4. The object returned looks like this:

 

{

totalRecords: 427,

data: [

 [ “A”,2,”xyz” ], // requested fields of first entity

 ...

 // up to limit elements

]

}

 

The totalRecord property holds the total number of results, regardless of the “limit” parameter. The “data” property holds an array of arrays. Each array in the “data” array contains the field values based on the “fields” parameter.

Field Names

Normally the “fields” parameter contains simple field names such as “Name” or “Capacity”. The fields, however, can reference related entities by using the dot-syntax. For example, to get the Id of each Room along with the Name of its Building and Campus, you would do this:

 

~api/query/room?fields=Id,Building.Name,Building.Campus.Name

 

The “Building” component of the second field is the name found in the “join” object that describes a one-to-one association from Room to Building. This is similar for the third field except that “Campus” is an association from the Building entity. The dot-syntax can follow as many association references as necessary.

Filter Expressions

The ability to control the entities returned in a query comes from the filter parameter. The syntax of a filter is C-like with some SQL extensions. The following C relational operators are supported:

 

==        Equality

!=        Inequality

<        Less-than

<=        Less-than or equal

>        Greater-than

>=        Greater-than or equal

&&        Logical And

||        Logical Or

!        Logical Not

&        Bitwise AND

|        Bitwise OR

 

In addition, the following SQL-style operators are supported:

 

?=        Like  (e.g.  “Name ?= ‘Bob%th’”)

in        IN  (e.g.  “Capacity in (2,4,8)”)

 

Parentheses are also supported. If no filter expression is given, then all entities of the specified type are returned.

The Entity API

The Entity API is similar to the Query API but returns complete entities in JSON object format.

Retrieving Data

The URL is also somewhat different. Consider a GET of the following URL:

 

~api/entity/room/byid/95ad0ad8-0b46-254d-07b9-50f5a845a530

 

This would return the Room entity given its Id (a GUID). The returned object will look something like this:

 

{

    Id: “95ad0ad8-0b46-254d-07b9-50f5a845a530”,

    Name: “HOLT 122”,

    Description: null,

    RoomNumber: 122,

    KeyNumber: null,

    PhoneAreaCode: null,

    PhoneNumber: null,

    PhoneExtension: null,

    Width: 20.0,

    Length: 30.0,

    SquareFootage: 600.0,

    MaxOccupancy: 25,

    IsShareable: false,

    MaxSharedActivities: 1,

    PriorityId: null,

    RoomTypeId: null,

    BuildingId: “79D5F153-8695-4679-9819-303D584A01D8”,

    HvacZoneId: null,

    SisKey: “MAIN_HOLT_122”,

    NoSchedule: false,

    ArrangedSection: false,

    DoNotOptimize: false,

    LastSisUpdateDate: null,

    LastImportedDate: null,

    LastExportedDate: null,

    RequiresAttention: false,

    EffectiveStartDate: null,

    EffectiveEndDate: null,

    EffectiveParentId: null,

    IsActive: true,

    WorkflowDefinitionId: null,

    CreatedDate: “2007-03-13T13:11:30Z”,

    CreatedBy: “A394C903-7A6A-400d-936A-0C1142341DEB”,

    ModifiedDate: null,

    ModifiedBy: null,

    RowVersion: 1

}

 

In the URL, the special token “byid” is used to request an entity given its Id.

 

The same part of the URL that contained “byid” above is also used to retrieve entities related to a particular entity. For example, to get all rooms for a building:

 

~api/entity/building/rooms/79D5F153-8695-4679-9819-303D584A01D8

 

The result of this API call is an array of Room entity objects like the one above. This can also retrieve a one-to-one associated entity in which case the result will be a single object and not an array.

Modifying Data

The Entity API also supports a POST method. This is a non-RESTful API in that all POST requests are sent to the “~api/entity” URL, but this is required to perform a proper database transaction. The general structure of the posted object is as follows:

 

{

    Inserts: 

    {

        EntityType1: 

        {

            “EntityId1”: 

            {

                Field1: value1,

                Field2: value2,

                Field3: value3,

                ...

            },

            ...

        },

        ...

    }, 

    

    Updates: // same as inserts

    { 

    }, 

    

    Deletes: 

    {

        EntityType2: {[ “EntityId1”, “EntityId2”, ...]}

    },

    Assoc:

    {

        JoinName:

        {

            role:

            {

                “EntityId”:

                {

                    Add: [ “idOfOtherEntity”, ... ],

                    Remove: [ “idofAnotherEntity”, ... ]

                }

            }

        }

    }

Inserts

The Inserts object in the POST contains one object per type of entity to be inserted. Those objects contain one object per inserted entity, the name of which is the Id of the new entity and the value of which is the object containing named field values. For example, to insert a Room, you might POST this:

 

Inserts:

{

Room:

{

“95ad0ad8-0b46-254d-07b9-50f5a845a530”:

{

    Id: “95ad0ad8-0b46-254d-07b9-50f5a845a530”,

    Name: “HOLT 122”,

    Description: null,

    RoomNumber: 122,

    KeyNumber: null,

    PhoneAreaCode: null,

    PhoneNumber: null,

    PhoneExtension: null,

    Width: 20.0,

    Length: 30.0,

    SquareFootage: 600.0,

    MaxOccupancy: 25,

    IsShareable: false,

    MaxSharedActivities: 1,

    PriorityId: null,

    RoomTypeId: null,

    BuildingId: “79D5F153-8695-4679-9819-303D584A01D8”,

    HvacZoneId: null,

    SisKey: “MAIN_HOLT_122”,

    NoSchedule: false,

    ArrangedSection: false,

    DoNotOptimize: false,

    LastSisUpdateDate: null,

    LastImportedDate: null,

    LastExportedDate: null,

    RequiresAttention: false,

    EffectiveStartDate: null,

    EffectiveEndDate: null,

    EffectiveParentId: null,

    IsActive: true,

    WorkflowDefinitionId: null,

    CreatedDate: “2007-03-13T13:11:30Z”,

    CreatedBy: “A394C903-7A6A-400d-936A-0C1142341DEB”,

    ModifiedDate: null,

    ModifiedBy: null,

    RowVersion: 1

}

}

}

 

Since the Astra Database uses GUID’s to identify objects, a properly generated GUID is safe to supply from the client on a new entity.

Updates

Update requests look just like insert requests, except that the supplied object is generally partial. This is because only the fields that need to be updated are given. All other fields remain unchanged.

Deletes

To delete an entity, you simply put its Id in an array under its type. For example, to delete the above room:

 

Deletes:

{

Room: [ “95ad0ad8-0b46-254d-07b9-50f5a845a530” ]

}

Associations

To update matrix (many-to-many) associations, the desired additions and removals are sent. These are collected under the pieces of the “join” in the entity metadata. For example, to add a room (whose Id is “95ad0ad8-0b46-254d-07b9-50f5a845a530”) to one region and remove it from another:

 

Assoc:

{

         RoomRegion:

{

         RoomId:

         {

“95ad0ad8-0b46-254d-07b9-50f5a845a530”:

{

Add: [ “42833acc-b9b0-4261-af77-25d3f6eb2f34” ],

Remove: [ “64e2fdde-edc3-4b52-aaf5-cd7534b7b15e” ]

}

}

         }

}

 

All modifications specified in the POST are performed as a single database transaction. If the request fails, no modifications will be made to the database. There are often side-effects to updates made via the Entity API, so the total set of modifications to the database may be (much) larger than given in the POST body.

References

1.http://en.wikipedia.org/wiki/Representational_State_Transfer

2.http://en.wikipedia.org/wiki/HTTP

3.http://en.wikipedia.org/wiki/HTTPS

4.http://json.org/

5.http://www.ietf.org/rfc/rfc4627.txt

6.http://en.wikipedia.org/wiki/Guid

Page url: ?astra_schedule_api.htm