openapi: 3.0.2
info:
title: Penn Courses API Documentation [Accounts] User [Accounts] User [PCx] Course API
version: ''
description: '
# Introduction
Penn Courses ([GitHub](https://github.com/pennlabs/penn-courses)) is the umbrella
categorization for [Penn Labs](https://pennlabs.org/)
products designed to help students navigate the course registration process. It currently
includes three products, each with their own API documented on this page:
Penn Course Alert, Penn Course Plan, and Penn Course Review.
See `Penn Labs Notion > Penn Courses` for more details on each of our (currently) three apps.
For instructions on how to maintain this documentation while writing code,
see the comments in `backend/PennCourses/docs_settings.py` (it is easy, and will be helpful
for maintaining Labs knowledge in spite of our high member turnover rate).
See our [GitHub](https://github.com/pennlabs/penn-courses) repo for instructions on
installation, running in development, and loading in course data for development. Visit
the `/admin/doc/` route ([link](/admin/doc/)) for the backend documentation generated by Django
(admin account required, which can be made by running
`python manage.py createsuperuser` in terminal/CLI).
# Unified Penn Courses
By virtue of the fact that all Penn Courses products deal with, well, courses,
it would make sense for all three products to share the same backend.
We realized the necessity of a unified backend when attempting to design a new Django backend
for Penn Course Plan. We like to live by the philosophy of keeping it
[DRY](https://en.wikipedia.org/wiki/Don''t_repeat_yourself), and
PCA and PCP''s data models both need to reference course and
section information. We could have simply copied over code (a bad idea)
or created a shared reusable Django app (a better idea) for course data,
but each app would still need to download copies of the same data.
Additionally, this will help us build integrations between our Courses products.
# Authentication
PCx user authentication is handled by platform''s Penn Labs Accounts Engine.
See [Penn Labs Notion > Platform > The Accounts Engine](https://www.notion.so/pennlabs/The-Accounts-Engine-726ccf8875e244f4b8dbf8a8f2c97a87?pvs=4)
for extensive documentation and links to repositories for this system. When tags or routes
are described as requiring user authentication, they are referring to this system.
I highly recommend the [official video course on OAuth2](https://oauth.net/2/) (by Aaron Parecki),
then the Platform Notion docs on the "Accounts Engine" for anyone who wants to understand
Labs authentication better. Platform is our OAuth2 "Authorization Server",
and Django Labs Accounts is an OAuth2 client run by our Django backends (Clubs, Penn Courses, etc),
exposing client-facing authentication routes like `penncourseplan.com/accounts/login`.
There''s also this Wikipedia page explaining [Shibboleth](https://en.wikipedia.org/wiki/Shibboleth_(software))
(which is used by Penn for authentication, and by the Platform authorization server).
See the Django docs for more on Django''s features for
[User Authentication](https://docs.djangoproject.com/en/3.0/topics/auth/),
which are used by PCX apps, as part of Platform''s accounts system.
'
x-logo:
url: https://i.imgur.com/tVsRNxJ.png
altText: Labs Logo
contact:
email: contact@pennlabs.org
servers:
- url: https://penncoursereview.com
description: Penn Course Review
- url: https://penncourseplan.com
description: Penn Course Plan
tags:
- name: '[PCx] Course'
description: ''
paths:
/api/base/{semester}/courses/:
get:
operationId: List Courses
description: '(GET `/api/base/{semester}/courses/`)
Retrieve a list of (all) courses for the provided semester.'
parameters:
- name: semester
in: path
required: true
description: 'The semester of the course (of the form YYYYx where x is A [for spring], B [summer], or C [fall]), e.g. ''2019C'' for fall 2019. Alternatively, you can just pass ''current'' for the current semester. Finally, you can pass ''all'' to always return the most recent course for each full_code, no matter which semester it is from. The ''all'' option can be significantly more expensive, so use only where needed. '
schema:
type: string
responses:
'200':
content:
application/json:
schema:
type: array
items:
type: object
properties:
id:
type: string
readOnly: true
description: '
The full code of the course, in the form ''{dept code}-{course code}''
dash-joined department and code of the course, e.g. `CIS-120` for CIS-120.'
title:
type: string
readOnly: true
description: '
The title of the course, e.g. ''Programming Languages and Techniques I'' for CIS-120.
'
description:
type: string
readOnly: true
description: '
The description of the course, e.g. ''A fast-paced introduction to the fundamental concepts
of programming... [etc.]'' for CIS-120.
'
semester:
type: string
readOnly: true
description: '
The semester of the course (of the form YYYYx where x is A [for spring],
B [summer], or C [fall]), e.g. `2019C` for fall 2019.
'
num_sections:
type: integer
readOnly: true
description: The number of sections for this course.
course_quality:
type: number
multipleOf: 0.001
maximum: 10
minimum: -10
readOnly: true
description: The average course quality rating for this section, on a scale of 0-4.
instructor_quality:
type: number
multipleOf: 0.001
maximum: 10
minimum: -10
readOnly: true
description: The average instructor quality for this section, on a scale of 0-4.
difficulty:
type: number
multipleOf: 0.001
maximum: 10
minimum: -10
readOnly: true
description: The average difficult rating for this section, on a scale of 0-4.
work_required:
type: number
multipleOf: 0.001
maximum: 10
minimum: -10
readOnly: true
description: The average work required for this section, on a scale of 0-4.
recommendation_score:
type: number
multipleOf: 0.001
maximum: 10
minimum: -10
readOnly: true
description: '
The recommendation score for this course if the user is logged in, or null if the
the user is not logged in.'
credits:
type: number
multipleOf: 0.01
maximum: 100
minimum: -100
readOnly: true
nullable: true
description: The number of credits this course takes. This is precomputed for efficiency.
description: Courses listed successfully.
tags:
- '[PCx] Course'
/api/base/{semester}/search/courses/:
get:
operationId: Course Search
description: '(GET `/api/base/{semester}/search/courses/`)
This route allows you to list courses by certain search terms and/or filters.
Without any GET parameters, this route simply returns all courses
for a given semester. There are a few filter query parameters which constitute ranges of
floating-point numbers. The values for these are <min>-<max> , with minimum excluded.
For example, looking for classes in the range of 0-2.5 in difficulty, you would add the
parameter difficulty=0-2.5. If you are a backend developer, you can find these filters in
backend/plan/filters.py/CourseSearchFilterBackend. If you are reading the frontend docs,
these filters are listed below in the query parameters list (with description starting with
"Filter").'
parameters:
- name: semester
in: path
required: true
description: 'The semester of the course (of the form YYYYx where x is A [for spring], B [summer], or C [fall]), e.g. ''2019C'' for fall 2019. Alternatively, you can just pass ''current'' for the current semester. Finally, you can pass ''all'' to always return the most recent course for each full_code, no matter which semester it is from. The ''all'' option can be significantly more expensive, so use only where needed. '
schema:
type: string
- name: page
required: false
in: query
description: A page number within the paginated result set.
schema:
type: integer
- name: page_size
required: false
in: query
description: Number of results to return per page.
schema:
type: integer
- name: search
schema:
type: string
required: false
in: query
description: Search query. Can be either a fragment of a course code, or any keyword/professor name.
- name: degree_rules
required: false
in: query
description: Filter to courses that satisfy certain degree Rules. Accepts a string of comma-separated Rule ids. If multiple Rule ids are passed then filtered courses satisfy all the rules.
schema:
type: string
- name: type
required: false
in: query
description: Can specify what kind of query to run. Course queries are faster, keyword queries look against professor name and course title.
schema:
type: string
default: auto
enum:
- auto
- course
- keyword
- name: pre_ngss_requirements
required: false
in: query
description: Deprecated since 2022B. Filter courses by comma-separated pre ngss requirements, ANDed together. Use the [List Requirements](/api/documentation/#operation/List%20Pre-Ngss%20Requirements) endpoint to get requirement IDs.
schema:
type: string
example: SS@SEAS,H@SEAS
- name: attributes
required: false
in: query
description: 'This query parameter accepts a logical expression of attribute codes separated by `*` (AND) or `|` (OR) connectives, optionally grouped into clauses by parentheses and arbitrarily nested (we avoid using `&` for the AND connective so the query string doesn''t have to be escaped). You can negate an individual attribute code or a clause with the `~` operator (this will filter for courses that do NOT have that attribute or do not satisfy that clause). Binary operators are left-associative, and operator precedence is as follows: `~ > * > |`. Whitespace is ignored. A syntax error will cause a 400 response to be returned. Example: `(EUHS|EUSS)*(QP|QS)` would filter for courses that satisfy the EAS humanities or social science requirements and also have a standard grade type or a pass/fail grade type. Use the [List Attributes](/api/documentation/#operation/List%20Attributes) endpoint to get a list of valid attribute codes and descriptions.'
schema:
type: string
example: WUOM|WUGA
- name: cu
required: false
in: query
description: Filter course units to be within the given range.
schema:
type: string
example: 0-0.5
- name: difficulty
required: false
in: query
description: Filter course difficulty (average across all reviews) to be within the given range.
schema:
type: string
example: 1-2.5
- name: course_quality
required: false
in: query
description: Filter course quality (average across all reviews) to be within the given range.
schema:
type: string
example: 2.5-4
- name: instructor_quality
required: false
in: query
description: Filter instructor quality (average across all reviews) to be within the given range.
schema:
type: string
example: 2.5-4
- name: days
required: false
in: query
description: 'Filter meetings to be within the specified set of days. The set of days should be specified as a string containing some combination of the characters [M, T, W, R, F, S, U]. This filters courses by the following condition: include a course only if the specified day filter does not limit the set of section activities we can participate in for the course. Passing an empty string will return only asynchronous classes or classes with meeting days TBD.'
schema:
type: string
example: TWR
- name: time
required: false
in: query
description: 'Filter meeting times to be within the specified range. The start and end time of the filter should be dash-separated. Times should be specified as decimal numbers of the form `h+mm/100` where h is the hour `[0..23]` and mm is the minute `[0,60)`, in ET. You can omit either the start or end time to leave that side unbounded, e.g. ''11.30-''. This filters courses by the following condition: include a course only if the specified time filter does not limit the set of section activities we can participate in for the course.'
schema:
type: string
example: 11.30-18
- name: schedule-fit
required: false
in: query
description: 'Filter meeting times to fit into the schedule with the specified integer id. You must be authenticated with the account owning the specified schedule, or this filter will be ignored. This filters courses by the following condition: include a course only if the specified schedule-fit filter does not limit the set of section activities we can participate in for the course.'
schema:
type: integer
example: '242'
- name: is_open
required: false
in: query
description: 'Filter courses to only those that are open. A boolean of true should be included if you want to apply the filter. By default (ie when the `is_open` is not supplied, the filter is not applied. This filters courses by the following condition: include a course only if the specification that a section is open does not limit the set of section activities we can participate in for the course.In other words, filter to courses for which all activities have open sections.'
schema:
type: boolean
example: 'true'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
count:
type: integer
example: 123
next:
type: string
nullable: true
format: uri
example: http://api.example.org/accounts/?page=4
previous:
type: string
nullable: true
format: uri
example: http://api.example.org/accounts/?page=2
results:
type: array
items:
type: object
properties:
id:
type: string
readOnly: true
description: '
The full code of the course, in the form ''{dept code}-{course code}''
dash-joined department and code of the course, e.g. `CIS-120` for CIS-120.'
title:
type: string
readOnly: true
description: '
The title of the course, e.g. ''Programming Languages and Techniques I'' for CIS-120.
'
description:
type: string
readOnly: true
description: '
The description of the course, e.g. ''A fast-paced introduction to the fundamental concepts
of programming... [etc.]'' for CIS-120.
'
semester:
type: string
readOnly: true
description: '
The semester of the course (of the form YYYYx where x is A [for spring],
B [summer], or C [fall]), e.g. `2019C` for fall 2019.
'
num_sections:
type: integer
readOnly: true
description: The number of sections for this course.
course_quality:
type: number
multipleOf: 0.001
maximum: 10
minimum: -10
readOnly: true
description: The average course quality rating for this section, on a scale of 0-4.
instructor_quality:
type: number
multipleOf: 0.001
maximum: 10
minimum: -10
readOnly: true
description: The average instructor quality for this section, on a scale of 0-4.
difficulty:
type: number
multipleOf: 0.001
maximum: 10
minimum: -10
readOnly: true
description: The average difficult rating for this section, on a scale of 0-4.
work_required:
type: number
multipleOf: 0.001
maximum: 10
minimum: -10
readOnly: true
description: The average work required for this section, on a scale of 0-4.
recommendation_score:
type: number
multipleOf: 0.001
maximum: 10
minimum: -10
readOnly: true
description: '
The recommendation score for this course if the user is logged in, or null if the
the user is not logged in.'
credits:
type: number
multipleOf: 0.01
maximum: 100
minimum: -100
readOnly: true
nullable: true
description: The number of credits this course takes. This is precomputed for efficiency.
description: Courses listed successfully.
'400':
description: Bad request (invalid query).
tags:
- '[PCx] Course'
/api/base/{semester}/courses/{full_code}/:
get:
operationId: Retrieve Course
description: '(GET `/api/base/{semester}/courses/{full_code}/`)
Retrieve a detailed look at a specific course. Includes all details necessary to display course
info, including requirements this class fulfills, and all sections.'
parameters:
- name: semester
in: path
required: true
description: 'The semester of the course (of the form YYYYx where x is A [for spring], B [summer], or C [fall]), e.g. ''2019C'' for fall 2019. Alternatively, you can just pass ''current'' for the current semester. Finally, you can pass ''all'' to always return the most recent course for each full_code, no matter which semester it is from. The ''all'' option can be significantly more expensive, so use only where needed. '
schema:
type: string
- name: full_code
in: path
required: true
description: The dash-joined department and code of the course, e.g. `CIS-120` for CIS-120.
schema:
type: string
- name: check_offered_in
in: query
description: '
Check that the desired course was offered under the specified
code in the specified semester.
Format is `course_code@semester`, e.g. `CIS-1210@2022A`.
404 will be returned if the course
does not exist, or was not offered in that semester.
'
schema:
type: string
required: false
responses:
'200':
content:
application/json:
schema:
type: object
properties:
id:
type: string
readOnly: true
description: '
The full code of the course, in the form ''{dept code}-{course code}''
dash-joined department and code of the course, e.g. `CIS-120` for CIS-120.'
title:
type: string
readOnly: true
description: '
The title of the course, e.g. ''Programming Languages and Techniques I'' for CIS-120.
'
description:
type: string
readOnly: true
description: '
The description of the course, e.g. ''A fast-paced introduction to the fundamental concepts
of programming... [etc.]'' for CIS-120.
'
syllabus_url:
type: string
readOnly: true
nullable: true
description: '
A URL for the syllabus of the course, if available.
Not available for courses offered in or before spring 2022.
'
semester:
type: string
readOnly: true
description: '
The semester of the course (of the form YYYYx where x is A [for spring],
B [summer], or C [fall]), e.g. `2019C` for fall 2019.
'
prerequisites:
type: string
readOnly: true
description: Text describing the prereqs for a course, e.g. 'CIS 120, 160' for CIS-121.
course_quality:
type: number
multipleOf: 0.001
maximum: 10
minimum: -10
readOnly: true
description: The average course quality rating for this section, on a scale of 0-4.
instructor_quality:
type: number
multipleOf: 0.001
maximum: 10
minimum: -10
readOnly: true
description: The average instructor quality for this section, on a scale of 0-4.
difficulty:
type: number
multipleOf: 0.001
maximum: 10
minimum: -10
readOnly: true
description: The average difficult rating for this section, on a scale of 0-4.
work_required:
type: number
multipleOf: 0.001
maximum: 10
minimum: -10
readOnly: true
description: The average work required for this section, on a scale of 0-4.
credits:
type: number
multipleOf: 0.01
maximum: 100
minimum: -100
readOnly: true
nullable: true
description: The number of credits this course takes. This is precomputed for efficiency.
crosslistings:
type: array
items:
type: string
readOnly: true
description: '
A list of the full codes (DEPT-###) of all crosslistings for this course
(not including this course).
'
pre_ngss_requirements:
type: array
items: []
readOnly: true
description: '
A list of the pre-NGSS (deprecated since 2022B) academic requirements
this course fulfills.
'
attributes:
type: array
items: []
readOnly: true
description: '
A list of attributes this course has. Attributes are typically
used to mark courses which students in a program/major should
take.
'
restrictions:
type: array
items: []
readOnly: true
description: '
A list of NGSSRestrictions this course has. Restrictions provide information about
who can take a course.
'
sections:
type: array
items: []
readOnly: true
description: A list of the sections of this course.
description: Courses detail retrieved successfully.
tags:
- '[PCx] Course'
x-tagGroups:
- name: Penn Course Plan
tags:
- '[PCP] Course Recommendations'
- '[PCP] Schedule'
- '[PCP] Primary Schedule'
- '[PCP] Calendar'
- '[PCP] Break'
- name: Penn Course Alert
tags:
- '[PCA] Registration History'
- '[PCA] Registration'
- name: Penn Course Review
tags:
- '[PCR] Course Reviews'
- '[PCR] Autocomplete Dump'
- '[PCR] Department Reviews'
- '[PCR] Section-Specific Reviews'
- '[PCR] Plots'
- '[PCR] Instructor Reviews'
- name: Penn Courses (Base)
tags:
- '[PCx] NGSS Restrictions'
- '[PCx] Attributes'
- '[PCx] Status Updates'
- '[PCx] Healths'
- '[PCx] Friendship'
- '[PCx] Course'
- '[PCx] Section'
- '[PCx] Pre-NGSS Requirements'
- name: Penn Labs Accounts
tags:
- '[Accounts] User'
- name: Other
tags:
- '[PDP] Docked Course'
- '[PDP] Degree'
- '[PDP] Onboard From Transcript'
- '[PDP] Fulfillment'
- '[PDP] Degree Plan Lists'
- '[PDP] Satisfied Rule Lists'
- '[PDP] Degree Plan Detail'