Skip to content

Instantly share code, notes, and snippets.

@cbruegg
Last active October 13, 2018 08:16
Show Gist options
  • Save cbruegg/ffc1d42ce74481bbd49dc9aa23b7018a to your computer and use it in GitHub Desktop.
Save cbruegg/ffc1d42ce74481bbd49dc9aa23b7018a to your computer and use it in GitHub Desktop.
PAULa API documentation

Calling the API

The main endpoint is https://paula-upb.de/Paul/ExportCourses?shortCatalogueTitle=X&token=Y where X specifies the semester of which courses should be exported. X is of the form "WS 2016/17" or "SS 2017". If the semester cannot be found in the database, an empty object is returned. Usually, the current and the next semester is stored in the database. To keep our database light, other semesters are deleted automatically. The parameter can also be omitted completely to fetch all courses. Y is the auth token we'll send you separately to avoid abuse.

In case the requested semester is found or you've requested all by omitting the parameter shortCatalogueTitle, the API returns the following structure:

{
  "SS 2017": [<course1>, ...],
  "WS 2016/17": ...
}

The returned JSON object is multiple MBs in size, so using a streaming JSON parser may be required to consume it.

A request from us: Exporting courses from the database is a computationally expensive task, so please call it a few times a day at maximum in production. Don't worry about it while debugging though.

Obtaining a list of all available semesters

https://paula-upb.de/Paul/ExportShortCatalogueTitles?token=Y yields a list of all available semesters in the database.

Modifications to the API

The class definitions seen in the other files are a layer on top of our actual database classes, so you may consider them stable. We reserve the right to add properties, but we won't remove any without warning first, at least not without very good reasons to do so.

Structure of courses

See the following two files. The private properties and property getters can be ignored, but the structure is exactly what the JSON looks like, with the minor difference that property names start with a lowercase letter, not with an uppercase letter as seen in the class definition.

Availability

Please note that these services are taken offline every night starting at 2:00 UTC to fetch the latest data from PAUL. This maintenance takes 30 minutes on average, so to be safe you should hold off from accessing the API between 2:00 to 3:00 UTC. During the maintenance phase, the API will return HTTP 503.

We guarantee neither correctness nor availability of the data, though during the lifetime of PAULa UPB we didn't run into any issues we weren't able to fix within a day or so. In almost all cases, issues simply caused our database to become out of date, but old data was still available.

using System.Collections.Generic;
using System.Linq;
namespace ProjectPaula.Model.Public
{
public class PublicCourse
{
private readonly Course _course;
private readonly List<Course> _allCourses;
/// <summary>
/// URL to PAUL. Needs to be prefixed with the PAUL base URL.
/// </summary>
public string Url => _course.Url;
/// <summary>
/// The PAUL ID, something like K.184.32843. NULL in case IsTutorial == true.
/// </summary>
public string PaulId => _course.InternalCourseID;
/// <summary>
/// The ID that will be referenced by TutorialIds and ConnectedCourseIds.
/// </summary>
public string Id => _course.Id;
/// <summary>
/// The name of the course, for example "Analysis", "K.184.32843", or anything really.
/// </summary>
public string Name => _course.Name;
/// <summary>
/// The short name of the course, for example "ANA", "Analysis", "K.184.32843", or anything at all again.
/// </summary>
public string ShortName => _course.ShortName;
/// <summary>
/// See doc for property ConnectedCourseIds. This property is true
/// if this is a course connected to some other course, but not if
/// this course owns connected courses.
/// </summary>
public bool IsConnectedCourse => _course.IsConnectedCourse;
/// <summary>
/// True in case this is a tutorial to another course.
/// </summary>
public bool IsTutorial => _course.IsTutorial;
/// <summary>
/// In case IsTutorial == true, this contains the ID of the parent course.
/// </summary>
public string ParentCourseId => _course.FindParent(_allCourses)?.InternalCourseID;
/// <summary>
/// A list of dates of this course.
/// </summary>
public List<PublicDate> Dates => _course.Dates.Select(date => new PublicDate(date)).ToList();
/// <summary>
/// Exam dates.
/// </summary>
public List<PublicDate> ExamDates => _course.ExamDates.Select(date => new PublicDate(date)).ToList();
/// <summary>
/// Docent.
/// </summary>
public string Docent => _course.Docent;
/// <summary>
/// In case this is a parent to one or more tutorials, this is a list of course IDs to courses
/// that are tutorials belonging to this. These IDs are not PAUL IDS!
/// </summary>
public List<string> TutorialIds => _course.Tutorials.Select(c => c.Id).ToList();
/// <summary>
/// Not all tutorials are modeled as Tutorial courses in PAUL. Courses can also be connected,
/// so docents use this to create two separate courses, one being for lectures and the other containing the tutorials
/// (meaning that TutorialsId is non-empty for the connected course). A connected course does not have
/// a reference to THIS course in its connectedCourseIds to avoid loops.
/// </summary>
public List<string> ConnectedCourseIds => _course.ConnectedCourses.Select(c => c.Id).ToList();
public PublicCourse(Course course, List<Course> allCourses)
{
_allCourses = allCourses;
_course = course;
}
}
}
using System;
namespace ProjectPaula.Model.Public
{
public class PublicDate
{
/// <summary>
/// When this date starts. Will be ISO 8601 formatted in the JSON.
/// </summary>
public DateTimeOffset From;
/// <summary>
/// When this date ends. Will be ISO 8601 formatted in the JSON.
/// </summary>
public DateTimeOffset To;
public string Room;
public string Instructor;
public PublicDate(Date date)
{
From = date.From;
To = date.To;
Room = date.Room;
Instructor = date.Instructor;
}
public PublicDate(ExamDate date)
{
From = date.From;
To = date.To;
Room = "";
Instructor = date.Instructor;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment