Last updated: 2/16/2021
input FilterInput {
keyword: String
genEdTypes: [GenEdType!]
dayOfWeeks: [DayOfWeek!]
limit: Int
offset: Int
}
input CourseGroupInput {
semester: String!
academicYear: String!
studyProgram: StudyProgram!
}
courses: [Course!]!
Returns all courses stored on backend, fetched from scraper.
course(courseNo: String!, courseGroup: CourseGroupInput!): Course!
Returns a single course with given courseNo and courseGroup (semester, academicYear, and studentProgram).
search(filter: FilterInput!, courseGroup: CourseGroupInput!): [Course!]!
Returns a list of courses matching the given filter.
Note: noConflict filter currently not implemented.
enum Interaction {
L
D
}
input CreateReviewInput {
rating: Int!
courseNo: String!
semester: String!
academicYear: String!
studyProgram: StudyProgram!
content: String
}
reviews(courseNo: String!, studyProgram: StudyProgram!): [Review!]!
Returns all reviews of the course that matches the input.
createReview(createReviewInput: CreateReviewInput!): Review!
Creates a review with the given input. The review will have a PENDING
status and must be approved by an admin.
removeReview(reviewId: String!): Review!
Removes the review with the given reviewId
. Only review owner can remove their own review.
setInteraction(reviewId: String!, interaction: Interaction!): Review!
Likes or dislikes the given review, depending on interaction
. To unlike or undislike, simple call the mutation again with the same interaction.
me: User
Returns the current user's info.
For full information about Google's OAuth 2.0 Authentication Flow, please see the official documentation.
The backend API uses Google has the OAuth provider of choice. To summarize:
Redirect to https://accounts.google.com/o/oauth2/v2/auth
with the following query parameters:
Parameters | Value |
---|---|
client_id | Must be set to 297489937770-g4p9q7jsmgaddbl074tbn9b6j2ba2kf4.apps.googleusercontent.com (staging). |
redirect_uri | Your frontend's callback URI which can handle the code in the query string and send to backend for verification. For Render PR Deployments, this value must be set to backend's callback URI which is https://cugetreg.com/api/auth/callback (production) or https://<STAGING_HOST>/api/auth/callback (staging). |
response_type | Must be set to code . |
scope | Must be set to openid+profile+email+https://www.googleapis.com/auth/drive.appdata . |
access_type | Must be set to offline . |
include_granted_scopes | Should be true . See Incremental Authorization |
state | Only set this parameter for PR Deployments. Use this parameter to set the returnURI so backend knows where to redirect after Google sends the authorization code to backend. For example: returnURI=https://cugetreg-pr-x.render.com/auth/callback |
For Render PR Deployments, normal authentication flow is impossible (as the domain will change every pr, and every redirect uri must be manually authorized in the Google Cloud Console).
To fix this, frontend must set the redirectURI to backend's callback endpoint (/api/auth/callback
) and set the returnURI
value in state
parameter to the deployment's callback path. For example: returnURI=https://cugetreg-pr-x.render.com/auth/callback
.
Nothing to do here. Just wait for user to confirm the permissions we're asking.
Google redirects to the URI stated above (redirect_uri) containing the authorization code. In normal environments (staging and production), the redirect URI should be a frontend path that extracts the authorization code from the query parameter and send to backend for verification.
To send the code to backend for verification, use the following mutation and GraphQL variables.
mutation verify($code: String!, $redirectURI: String!) {
verify(code: $code, redirectURI: $redirectURI) {
accessToken
_id
firstName
}
}
Variable | Description |
---|---|
code | The authorization code in the query parameter |
redirectURI | The same redirect URI used during OAuth initiation request. |
The verify mutation returns the following response
Field | Description |
---|---|
accessToken | The JWT access token used to access protected or current-user-specific resources. The payload contains _id and firstName . |
_id | The user's ObjectId |
firstName | The user's first name |
Store the accessToken somewhere safe and include this token in the header of every request.
To access Google Drive API for storing timetable data, you need the user's access token. Access token can be retrieved by calling me
GraphQL query in google.accessToken
field. The access token's expire date is stored in google.expiresIn
field. To refresh the token, simply call me
query again as backend already handles refreshing access tokens if token is already expired.
Note: Don't forget to put our own JWT access token in the header to call me
query.