This document describes the REST APIs exposed by the Node.js/Express backend for the mobile application.
Base URL: http://localhost:<PORT> (default PORT is 3000)
Authentication: JSON Web Token (JWT) via Authorization: Bearer <token> header for protected routes.
Note: Environment variable names expected by the code:
MONGODB_URI: Mongo connection stringGMAIL_CLIENT_ID: Google OAuth 2.0 Client IDGMAIL_CLIENT_SECRET: Google OAuth 2.0 Client SecretGMAIL_REDIRECT_URI: OAuth redirect URI (e.g.,http://localhost:3000/auth/google/callback)JWT_SECRET: Secret used to sign JWTsPORT: Server port (default3000)
Routes defined in:
- Auth:
src/routes/auth.js - Applications:
src/routes/api.js
Create a new local account.
Request body (JSON):
{
"username": "john",
"email": "john@example.com",
"password": "StrongP@ssw0rd"
}
Responses:
- 201 Created
{
"token": "<jwt>",
"user": { "id": "...", "username": "john", "email": "john@example.com" }
}
- 400 Bad Request – missing fields
- 409 Conflict – user already exists
- 500 Internal Server Error
Login with local credentials.
Request body (JSON):
{ "email": "john@example.com", "password": "StrongP@ssw0rd" }
Responses:
- 200 OK
{
"token": "<jwt>",
"user": { "id": "...", "username": "john", "email": "john@example.com" }
}
- 400 Bad Request – missing fields
- 401 Unauthorized – invalid credentials
- 500 Internal Server Error
Stateless logout (client discards token). No body.
Responses:
- 200 OK
{ "message": "Logged out" }
Get current user profile. Protected.
Headers:
Authorization: Bearer <jwt>
Responses:
- 200 OK – user object (without password and tokens)
- 401 Unauthorized – missing/invalid token
- 404 Not Found – user not found
Update profile. Protected.
Headers:
Authorization: Bearer <jwt>
Request body (any of):
{ "username": "newname" }
{ "password": "NewStrongPass" }
Responses:
- 200 OK – updated user object
- 401 Unauthorized
- 500 Internal Server Error
Begin Google OAuth to allow Gmail read-only access.
Response:
- 200 OK
{ "url": "https://accounts.google.com/o/oauth2/v2/auth?..." }
The client should open this URL in the browser. User consents and Google redirects to the callback.
Google OAuth callback. The server exchanges code for tokens, stores them on the user, and returns a JWT to the client.
Responses:
- 200 OK
{
"token": "<jwt>",
"user": { "id": "...", "username": "john", "email": "john@example.com" }
}
- 400 Bad Request – missing
code - 500 Internal Server Error
Note: After linking, Gmail read-only access is available for syncing applications.
All application routes are protected. Include Authorization: Bearer <jwt>.
Application model fields (server-side):
user(ObjectId) – owner (inferred from JWT)applicantName(string, optional)university(string, optional)program(string, optional)applicationId(string, optional)applicationStatus(enum:Submitted|Under Review|Accepted|Rejected; defaultSubmitted)interviewDate(Date, optional)submissionDate(Date; default now)notes(string, optional)sourceEmailId(string, optional; set by Gmail sync)
List the current user’s applications.
Responses:
- 200 OK
[ { ...application }, ... ] - 401 Unauthorized
- 500 Internal Server Error
Create an application manually.
Request body (JSON): any subset of model fields except user and sourceEmailId.
Example:
{
"applicantName": "John Doe",
"university": "Stanford University",
"program": "PhD in CS",
"applicationStatus": "Under Review",
"interviewDate": "2025-09-15T10:00:00.000Z",
"submissionDate": "2025-08-01T00:00:00.000Z",
"notes": "Submitted via portal"
}
Responses:
- 201 Created
{ ...application } - 401 Unauthorized
- 500 Internal Server Error
Fetch one application by id (must belong to current user).
Responses:
- 200 OK
{ ...application } - 401 Unauthorized
- 404 Not Found
- 500 Internal Server Error
Update an application by id (must belong to current user).
Request body (JSON): any updatable fields.
Responses:
- 200 OK
{ ...updatedApplication } - 401 Unauthorized
- 404 Not Found
- 500 Internal Server Error
Delete an application by id (must belong to current user).
Responses:
- 200 OK
{ "success": true } - 401 Unauthorized
- 404 Not Found
- 500 Internal Server Error
Pull recent relevant emails from Gmail and upsert applications for the current user. Requires that the user linked Google via OAuth.
Behavior:
- Lists recent Gmail messages (query defaults to
subject:PhD). - Fetches each message body, parses to extract
applicationId,status,interviewDate(seesrc/utils/emailParser.js). - Upserts by
sourceEmailIdper user, updatingapplicationStatus,interviewDate,submissionDate, etc.
Responses:
- 200 OK
{ "synced": <numberOfUpsertedOrUpdatedItems> } - 400 Bad Request – Google account not connected
- 401 Unauthorized
- 500 Internal Server Error
- Send JWT in
Authorization: Bearer <token>header for protected routes. - Tokens are issued on
/auth/register,/auth/login, and/auth/google/callbackand are valid for 7 days. - Logout is client-side (discard the token).
Controllers typically return:
{ "message": "<human-readable message>", "error": "<optional more details>" }
Global error handler (src/middleware/errorHandler.js) returns 500s as:
{
"success": false,
"message": "An unexpected error occurred. Please try again later."
}
- Email parsing lives in
src/utils/emailParser.js. - Expected patterns in the email body:
Application ID: <alphanumeric>->applicationIdStatus: <word>->applicationStatusInterview Date: YYYY-MM-DD->interviewDate
- You can adjust the regex patterns and the Gmail search query (
src/services/gmailService.js) to improve recall.
- User signs in (or registers) to get a JWT.
- Frontend calls
GET /auth/google/initiate, opens the returned URL. - User completes consent; server handles
/auth/google/callbackand returns a JWT (also stores refresh token). - Frontend calls
POST /api/applications/syncwith the JWT to import applications from Gmail.
Current API version: v1 (unversioned paths). If breaking changes are introduced, consider namespacing under /v1.