API Docs - HackRU/HackRU-Backend GitHub Wiki
Welcome to the HackRU-Backend wiki! We'll be using Typescript, Node.js, and Serverless to set up our backend.
Endpoints:
/authorize:
METHOD: POST
BODY REQUEST TYPE: JSON
EXAMPLE BODY REQUEST:
"email": "[email protected]",
"password": "plain-text-password"
Return:
Situation | Return Value |
---|---|
Wrong password | {'statusCode': 403, message: 'Wrong password'} |
Email doesn't exist in DB | {'statusCode': 403, message: 'Invalid email'} |
Success Auth | {'statusCode': 200, message: 'Authentication Successful', token} |
Internal error | {'statusCode': 500, message: 'Internal server error'} |
/attend-event:
METHOD: POST
BODY REQUEST TYPE: JSON
EXAMPLE BODY REQUEST:
auth_email: "[email protected]", (this user must have role director/organizer)
auth_token: "authentication-token",
qr: "[email protected]",
event: "dinner",
limit: 1, (how many times user can attend this event)
points: 10, (optional - amount of points user earns for this event)
RETURN:
Situation | Return value |
---|---|
Auth token not valid | {'statusCode': 401, message: 'Unauthorized'} |
Hacker (qr) not found | {'statusCode': 404, message: 'User not found'} |
Auth user (auth_email) not found | {'statusCode': 404, message: 'Auth user not found'} |
Auth user does not have roles organizer/director | {'statusCode': 401, message: 'Only directors/organizers can call this endpoint.'} |
User tries to check into an event that they reached the limit for | {'statusCode': 409, message: 'User already checked into event.', attendance: number} |
Success check-in | {'statusCode': 200, message: 'user successfully checked into event', attendance: number} |
Internal error | {'statusCode': 500, message: 'Internal server error'} |
/create:
METHOD: POST
BODY REQUEST TYPE: JSON
EXAMPLE BODY REQUEST:
{
email: '[email protected]',
password: 'hackerPassword'
}
This is the minimum required JSON body for the /create endpoint which includes simply the Hacker email and password.
Return:
Situation | Return value |
---|---|
Registration Time Has Passed | {'statusCode': 400, message: 'Registration is closed!'} |
Creating a duplicate of existing user | {'statusCode': 400, message: 'Duplicate User'} |
Successfully create user | {'statusCode': 200, message: 'User created!'} |
/update:
METHOD: POST
BODY REQUEST TYPE: JSON
EXAMPLE BODY REQUEST:
{
user_email: '[email protected]',
auth_email: '[email protected]',
auth_token: 'user.JWT.token',
updates: {
$set: {
last_name: 'sampleLastName'
}
}
}
This sample JSON request body represents changing the last name of the hacker, given they provide a valid auth token.
THIS CALL WILL RETURN 400 STATUS IF:
- If you don't follow the FSM model with regard to registration status
-
If you attempt to update these fields:
'_id', 'password', 'discord', 'created_at', 'registered_at'
-
If your profile is not entirely filled out.
Return:
Situation | Return value |
---|---|
Invalid auth token | {'statusCode': 401, message: 'Unauthorized'} |
Auth user (auth_email) not found | {'statusCode': 404, message: 'Auth user not found'} |
Auth user does not have a valid role to update (organizer/director/hacker) | {'statusCode': 401, message: 'Unauthorized. Auth user is not an organizer/director/hacker.'} |
User to be updated not found | {'statusCode': 404, message: 'User to be updated not found.'} |
User provided invalid updates: update registration status in a way that doesn't follow registration order, update password or _id | {'statusCode': 400, message: 'Bad updates.'} |
Success update | {'statusCode': 200, message: 'User updated successfully'} |
Internal error | {'statusCode': 500, message: 'Internal server error'} |
/discord:
METHOD: POST
BODY REQUEST TYPE: JSON
EXAMPLE BODY REQUEST:
{
email: '[email protected]',
auth_token: 'user JWT',
code: 'discord code from OAuth2',
redirect_uri: 'discord redirect uri'
}
Return:
Situation | Return value |
---|---|
Invalid auth token | {'statusCode': 401, message: 'Unauthorized'} |
User (email) not found | {'statusCode': 404, message: 'User not found'} |
Success | {'statusCode': 200, message: 'Discord user verified', discordId: 'discord user id', discordUsername: 'discord username'} |
Internal error | {'statusCode': 500, message: 'Internal Server Error', error: error} |
If successful, user in database gets updated:
{
discord: {
user_id: 'discord user id',
username: 'discord username',
access_token: 'discord auth access token',
refresh_token: 'discord auth refresh token',
expires_at: 'timestamp (ms) when token expires'
}
}
/read:
METHOD: POST
BODY REQUEST TYPE: JSON
EXAMPLE BODY REQUEST:
{
"auth_email": "[email protected]",
"auth_token": "user.JWT.token",
"email": "[email protected]",
"all" (optional): false (default)
}
RETURN:
Situation | Return value |
---|---|
Invalid auth token | {'statusCode': 401, message: 'Unauthorized'} |
Auth user (auth_email) not found | {'statusCode': 404, message: 'Auth user not found.'} |
Auth user does not have a valid role (hacker/director/organizer) | {'statusCode': 401, message: 'Unauthorized. Auth user is not an organizer/director/hacker.'} |
Hacker tries to look up information for a different user | {'statusCode': 403, message: 'Hackers can only look up their own information.'} |
Look-up user (email) not found | {'statusCode': 404, message: 'Look-up user not found.'} |
Success | {'statusCode': 200, body: [User Object]} |
Internal error | {'statusCode': 500, message: 'Internal server error.', error: [Error details]} |
/resume:
METHOD: POST
BODY REQUEST TYPE: JSON
EXAMPLE BODY REQUEST:
{
"email": "[email protected]",
"auth_token": "user.JWT.token"
}
RETURN:
Situation | Return value |
---|---|
Invalid auth token | {'statusCode': 401, message: 'Unauthorized'} |
User has already submitted a resume before | {'statusCode': 400, message: 'You already submitted a resume'} |
Success | {'statusCode': 200, body: {url, message: 'Upload the resume through the generated URL.'}} |
Internal error | {'statusCode': 500, message: 'Internal server error.', error: [Error details]} |
If this endpoint returns the success case, there will be a URL in the return body. You can call that URL, with PUT http method, and attach your PDF file in the body as type 'Binary.' Do keep in mind that it ONLY accepts PDF files.
/waiver:
METHOD: POST
BODY REQUEST TYPE: JSON
EXAMPLE BODY REQUEST:
{
"email": "[email protected]",
"auth_token": "user.JWT.token"
}
RETURN:
Situation | Return value |
---|---|
Invalid auth token | {'statusCode': 401, message: 'Unauthorized'} |
User has already submitted a waiver before | {'statusCode': 400, message: 'You already submitted a waiver'} |
Success | {'statusCode': 200, body: {url, message: 'Upload the waiver through the generated URL.'}} |
Internal error | {'statusCode': 500, message: 'Internal server error.', error: [Error details]} |
If this endpoint returns the success case, there will be a URL in the return body. You can call that URL, with PUT http method, and attach your PDF file in the body as type 'Binary.' Do keep in mind that it ONLY accepts PDF files.
/reset-password:
METHOD: POST
BODY REQUEST TYPE: JSON
EXAMPLE BODY REQUEST:
{
"email": "[email protected]",
"reset_token": "tokenFromEmail",
"new_password": "iLoveHackRU"
}
RETURN:
Situation | Return value |
---|---|
User did not request a password change | {'statusCode': 403, message: 'You did not request a password change'} |
Invalid reset token | {'statusCode': 401, message: 'Reset token is invalid'} |
Reset token has expired | {'statusCode': 401, message: 'Reset token has expired'} |
Successful password update | {'statusCode': 200, message: 'Password reset successful'} |
Internal error | {'statusCode': 500, message: 'Internal server error.', error: [Error details]} |
/points:
METHOD: POST
BODY REQUEST TYPE: JSON
EXAMPLE BODY REQUEST:
{
"email": "[email protected]",
"auth_token": "user.JWT.token",
"buy_ins": [
// Array of buy_ins
]
}
RETURN:
Situation | Return Value |
---|---|
Invalid email format | {'statusCode': 400, message: 'Invalid email format'} |
Invalid auth token | {'statusCode': 401, message: 'Unauthorized'} |
User not found | {'statusCode': 404, message: 'User not found.'} |
Success | {'statusCode': 200, body: { balance: number, total_points: number, buy_ins: [{prize_id: number}, {prize_id: number}] }} |
Internal error | {'statusCode': 500, message: 'Internal server error.', error: [Error details]} |
Notes:
- This endpoint is specifically for the F24 Hackathon points system.
- The endpoint uses JWT for authentication.
- Returns empty array if user has no buy_ins
- All corner cases should be handled, including invalid email, invalid JWT token, non-existent email in Users collection, and non-existent hacker in Points collection.
/update-buy-ins:
METHOD: POST
BODY REQUEST TYPE: JSON
EXAMPLE BODY REQUEST:
"email": "[email protected]",
"auth_token": "token",
"buy_ins": [
{
"prize_id": "prize_A",
"buy_in": 20
},
{
"prize_id": "prize_B",
"buy_in": 10
}
]
Criterias for a successful call:
-
All the
prize_id
in thebuy_ins
array must match ALL theprize_id
in the attributebuy_ins
in the Points collection. For instance, if your request body has prizeA, prizeB, prizeC, then thebuy_ins
array in the Points collection must contain those prizes as well (ordering does not matter). Else, the request will not be fulfilled. -
The sum of
buy_in
in thebuy_ins
array MUST BE LESS THAN OR EQUAL to thetotal_points
attribute in thePoints
collection.
Return:
Situation | Return Value |
---|---|
Unauthorized | {'statusCode': 401, message: 'Unauthorized'} |
Object doesn't exist in DB | {'statusCode': 404, message: 'User point balance information not found'} |
Request body prizes do not match | {'statusCode': 400, message: 'Request body prizes do not match'} |
Points distributed exceed user point total | {'statusCode': 403, message: 'Points distributed exceed user point total'} |
Updated user point balance successfully | {'statusCode': 200, message: 'Updated user point balance successfully'} |
Internal error | {'statusCode': 500, message: 'Internal server error'} |
/get-buy-ins:
METHOD: POST
BODY REQUEST TYPE: JSON
EXAMPLE BODY REQUEST:
"email": "[email protected]",
"auth_token": "token",
What it does: Returns the sum of all buy-ins for each prize across the Points collection.
Return:
Situation | Return Value |
---|---|
Unauthorized | {'statusCode': 401, message: 'Unauthorized'} |
Success | {'statusCode': 200, buyIns: {prizeID: integer sum of prizeID across Points collection, ....} } |
Internal error | {'statusCode': 500, 'message': 'Internal server error'} |
/verify-email:
METHOD: POST
BODY REQUEST TYPE: JSON
To send the user a verification email, specify email
and auth_token
. To verify, specify only code
.
EXAMPLE BODY REQUEST:
{
email: '[email protected]',
auth_token: 'user JWT',
}
OR
{
code: 'email verification code'
}
Return:
Situation | Return value |
---|---|
Invalid auth token | {'statusCode': 401, message: 'Unauthorized'} |
User (email) not found | {'statusCode': 404, message: 'User not found'} |
Success | {'statusCode': 200, message: 'HackRU account ({email}) verified successfully.'} |
Invalid code | {'statusCode': 400, message: 'Invalid email verification code. It may be expired.'} |
Internal error | {'statusCode': 500, message: 'Internal Server Error', error: error} |
If successful, user in database gets updated:
{
email_verified: true
}
/delete:
METHOD: POST
BODY REQUEST TYPE: JSON
EXAMPLE BODY REQUEST:
auth_email: "[email protected]", (this user must have role director/organizer)
auth_token: "authentication-token",
email: "[email protected]"
RETURN:
Situation | Return value |
---|---|
Auth token not valid | {'statusCode': 401, message: 'Unauthorized'} |
User not found | {'statusCode': 404, message: 'User not found'} |
Auth user (auth_email) not found | {'statusCode': 404, message: 'Auth user not found'} |
Auth user does not have roles organizer/director | {'statusCode': 401, message: 'Only directors/organizers can call this endpoint.'} |
Success | {'statusCode': 200, message: 'Deleted {user_email} successfully'} |
Internal error | {'statusCode': 500, message: 'Internal server error'} |
/interest-form:
METHOD: POST
BODY REQUEST TYPE: JSON
EXAMPLE BODY REQUEST:
{
"firstName": "John",
"lastName": "Doe",
"age": 20,
"phoneNumber": "+1234567890",
"email": "[email protected]",
"school": "Rutgers University",
"levelOfStudy": "Undergraduate",
"countryOfResidence": "United States",
"linkedInUrl": "https://linkedin.com/in/johndoe",
"mlh_code_of_conduct": true,
"mlh_privacy_policy": true,
"mlh_terms_and_conditions": true
}
REQUIRED FIELDS:
firstName
(string)lastName
(string)age
(number)phoneNumber
(string)email
(string, must be valid email format)school
(string)levelOfStudy
(string)countryOfResidence
(string)mlh_code_of_conduct
(boolean)mlh_privacy_policy
(boolean)mlh_terms_and_conditions
(boolean)
OPTIONAL FIELDS:
linkedInUrl
(string, must be valid LinkedIn profile URL if provided) RETURN:
Situation | Return Value |
---|---|
Successful form submission | {'statusCode': 200, message: 'Successful Form Submission', submissionId: 'database-generated-id'} |
Invalid LinkedIn URL format | {'statusCode': 422, message: 'Please provide a valid LinkedIn profile URL (e.g., https://linkedin.com/in/yourname)'} |
Internal error | {'statusCode': 500, message: 'Internal Server Error', error: 'error-details'} |
NOTES:
- LinkedIn URL is optional but if provided, must follow the format:
https://linkedin.com/in/username
- All MLH fields are required and must be boolean values
- Email format is validated by the schema
- Age must be a positive number
- Form data is stored in the
interest-forms
collection