-
Notifications
You must be signed in to change notification settings - Fork 0
3. APIs and Controller
This endpoint allows new users to register by creating a user account with a username, password, and optional personal preferences. The password is securely hashed before storage, and a JWT access token is generated upon successful registration.
Endpoint: POST /create_user
| Key | Container | Description |
|---|---|---|
| username | JSON | Unique username for the user (case-insensitive) |
| password | JSON | Plaintext password that will be hashed |
| fullname | JSON | User’s full name |
| likes | JSON | (Optional) User’s general travel likes/preferences |
| dislikes | JSON | (Optional) User’s general travel dislikes/preferences |
Response: Returns a JSON object containing a success message, JWT access token, and user details.
Response Format:
{
"message": "User created successfully",
"access_token": access_token,
"user": {
"id": new_user.user_id,
"username": new_user.username,
"firstname": new_user.firstname,
"lastname": new_user.lastname,
"likes": new_user.likes,
"dislikes": new_user.dislikes
}
}This endpoint authenticates a user by verifying their username and password. Upon successful authentication, it generates a new JWT token for authorization in future requests.
Endpoint: POST /login
| Key | Container | Description |
|---|---|---|
| username | JSON | Registered username of the user |
| password | JSON | Password associated with the username |
Response: Returns a JSON object with the login success message, JWT token, and basic user info.
Response Format:
{
"message": "Login successful",
"access_token": access_token,
"user": {
"id": user.user_id,
"username": user.username,
"firstname": user.firstname,
"lastname": user.lastname,
"likes": user.likes,
"dislikes": user.dislikes
}
}Allows authenticated users to update specific personal information fields such as first name, last name, likes, and dislikes.
Endpoint: POST /edit_user
Authorization: Requires valid JWT token in header
Authorization: Bearer <access_token>
| Key | Container | Description |
|---|---|---|
| firstname | JSON | User’s first name |
| lastname | JSON | User’s last name |
| likes | JSON | Updated user travel likes/preferences |
| dislikes | JSON | Updated user travel dislikes/preferences |
Response: Returns updated user information and confirmation message.
Response Format:
{
"message": "User updated successfully",
"user": {
"id": user.user_id,
"username": user.username,
"firstname": user.firstname,
"lastname": user.lastname,
"likes": user.likes,
"dislikes": user.dislikes
}
}/get_friends/<user_id> is called to retrieves a list of user IDs for all confirmed friends of the specified user. Friends are detected using the IsFriends relation between the queried user_id and all other users and checking that relationship is True. This builds the friends list as a list of user_ids which are serialized into a JSON array which allows the front end to generate the list of friends from each user_id.
Endpoint: GET /get_friends/<user_id>
Authorization: Requires JWT token
Response: JSON Array of user IDs
Example Response:
["user123", "user456", "user789"]/get_invites/<user_id> is called to fetch all incoming friend requests for the specified user. Incoming friends requests are determined by using the IsFriends relation and checking that relationship is False and the queried user is not initiating a friendship request. This builds a list of user_ids of people with incoming friendship requests to the queried user and serializes them into a JSON array which the front end can use to generate a list of users sending friend requests.
Endpoint: GET /get_invites/<user_id>
Response: JSON Array of user IDs
Example Response:
["user123", "user456", "user789"]/get_relationship/<user_id1>/<user_id2> is called to fetch the relationship status between the two queried users. Relationships are determined using the IsFriends relation, where absence of IsFriends indicates "none", existence with relationship being True indicates "friends", and existence with relationship being False indicating a "pending incoming/outgoing" relationship depending on the initiator_id. This endpoint returns this status as a JSON serialized string which the front end can use to determine how two users are related.
Endpoint: GET /get_relationship/<user_id1>/<user_id2>
Response: JSON of status dict between users
Example Response:
{"status": "friends"}/send_friend_request/<user_id> allows the authenticated user to send a friend request to another user. This endpoint validates that the queried user_id exists and doesn't match the current user via their JWT token, then validates that no current relationship exists, and then creates the request via a "pending outgoing" relation in the IsFriends relation. This endpoint returns a simple success message via JSON.
Endpoint: POST /send_friend_request/<user_id>
Authorization: Requires JWT token
| Key | Container | Description |
|---|---|---|
| user_id | JSON | The user ID of the person to send the friend request to. |
Response: Returns confirmation that friend request was sent.
/accept_friend_request/<int:user_id> allows the authenticated user to accept a friend request from the queried user. This endpoint validates that both users exist and that there is a "pending incoming" relation in the IsFriends relation to the current user via their JWT. It then updates the relationship to True. This endpoint returns a simple success message via JSON.
Accepts a pending friend request from another user.
Endpoint: POST /accept_friend_request/<int:user_id>
Authorization: Requires JWT token
| Key | Container | Description |
|---|---|---|
| user_id | JSON | The user ID of the person whose request is being accepted |
Response: Returns confirmation that the friend request was accepted and relationship updated.
/decline_friend_request/<int:user_id> allows the authenticated user to decline a friend request from the queried user. This endpoint validates that both users exist and that there is a "pending incoming" relation in the IsFriends relation to the current user via their JWT. It then deletes the IsFriends relation. This endpoint returns a simple success message via JSON.
Endpoint: POST /decline_friend_request/<int:user_id>
Authorization: Requires JWT token
| Key | Container | Description |
|---|---|---|
| user_id | JSON | The user ID of the person whose request is being declined |
Response: Returns confirmation message that the request was declined.
/revoke_friend_request/<user_id> allows the authenticated user to revoke a friend request sent to the queried user. This endpoint validates that both users exist and that there is a "pending outgoing" relation in the IsFriends relation from the current user via their JWT. It then deletes the IsFriends relation. This endpoint returns a simple success message via JSON.
Endpoint: POST /revoke_friend_request/<user_id>
Authorization: JWT Token Required
Response:
{"error": "No pending friend request found"}/remove_friend/<int:user_id> allows the authenticated user to remove the queried user as a friend. This endpoint validates that both users exist and that there is a "friend" relation in the IsFriends between the queried and current user. It then deletes the IsFriends relation. This endpoint returns a simple success message via JSON.
Endpoint: /remove_friend/<int:user_id>
Authorization: JWT Token Required
Response:
{"message": "Friend removed successfully"}/search_friends performs a live/debounced username search to find other users by username. It then sorts these friends and assigns their status based on relationship before sending them to the frontend as a JSON Array of user_ids. Used to enable user search.
Endpoint: GET /search_friends
Authorization: Requires JWT token
Response:
Returns a JSON array of user_ids which match the query.
Response Format:
[
{
"user_id": user.user_id,
"username": user.username,
"firstname": user.firstname,
"lastname": user.lastname,
"status": status
},
{
"user_id": user.user_id,
"username": user.username,
"firstname": user.firstname,
"lastname": user.lastname,
"status": status
},
...
]This endpoint allows the user to generate AI-powered trip itineraries using Gemini LLM based on destination, trip-specific preferences, and user-level preferences. The LLM returns structured JSON trip data containing stops and activities.
Endpoint: POST /trips/create
Authorization: Requires JWT token
| Key | Container | Description |
|---|---|---|
| destination | JSON | Primary destination for the trip |
| num_versions | JSON | Number of itinerary versions to generate (1-5) |
| likes | JSON | Trip-specific likes (override user-level preferences) (optional) |
| dislikes | JSON | Trip-specific dislikes (override user-level preferences) (optional) |
Response: Returns structured AI-generated trip itineraries following the strict JSON schema.
Response Format: Look into backend/sample_genai_trip.txt file for the response format returned from the LLM.
This endpoint returns information stored within the DB record for the specified trip.
Endpoint: GET /trip/{trip_id}/info
Authorization: Requires JWT token
| Key | Type | Description |
|---|---|---|
| trip_id | URL | The unique identifier of the trip |
This is a URL Parameter. The full URL will hence be https://api_url/trip/3/info for trip_id == 3.
Response Example:
{
"trip_id": 17,
"owner_id": 5,
"status": "archived",
"driving_polyline": "{wr~FhiyuOeBriJ",
"driving_polyline_timestamp": 1762019914,
}This endpoint allows the user to obtain context based on an image they take with their camera on the app intended for helping travelers identify and learn more about attractions and landmarks they encounter.
Endpoint: POST /landmark_context
| Key | Container | Description |
|---|---|---|
| image | multipart/form | An image file taken by the user of a landmark they want context for. |
Response: Returns a JSON object containing LLM response test describing the image's context.
Response Format:
{
"context": "Generated context ..."
}Expected 201 Status Code on success.
This endpoint allows the trip owner to invite a confirmed friend to join their trip. Ownership is verified through the JWT token — the user making the request must be the trip’s owner. Only confirmed friends can be invited.
Endpoint: POST /party/invite
Authorization: Requires JWT token
| Key | Container | Description |
|---|---|---|
| friend_id | JSON | The ID of the friend to invite |
| trip_id | JSON | The trip ID for which the invitation is being sent |
Response Example:
{
"message": "User 42 invited to trip 17"
}This endpoint allows the trip owner to remove an existing member from their trip. Ownership is verified automatically via the JWT token.
Endpoint: POST /party/remove
Authorization: Requires JWT token
| Key | Container | Description |
|---|---|---|
| friend_id | JSON | The ID of the member to remove |
| trip_id | JSON | The trip ID from which to remove the member |
Response Example:
{
"message": "User 42 removed from trip 17",
"removed_by": 5
}This endpoint allows any trip participant — owner or member — to view all participants in a specific trip. Access is restricted: users who are not part of the trip will receive a 403 error.
Endpoint: GET /party/{trip_id}
Authorization: Requires JWT token
| Key | Type | Description |
|---|---|---|
| trip_id | URL | The unique identifier of the trip |
This is a URL Parameter. The full URL will hence be https://api_url/party/3 for trip_id == 3.
Response Example:
{
"trip_id": 17,
"owner_id": 5,
"members": [
{
"user_id": 5,
"username": "Frank",
"firstname": "Frank",
"lastname": "asdf"
},
{
"user_id": 42,
"username": "charlie",
"firstname": "Charlie",
"lastname": "asdf"
}
]
}https://ai.google.dev/gemini-api/docs/image-understanding This endpoint allows for using the Gemini LLM to perform image recognition to facilitate landmark context from uploaded user images.
Endpoint: POST /v1beta/models/gemini-2.5-flash:generateContent
Request Parameters: | Key| Container | Description | |-----|-----|-----|-----| | model | JSON | The model to use for image recognition | | contents | JSONArray | the inputs to feed towards the Gemini model, including the image and queries |
This endpoint allows user to obtain routing information with a number of parameters to manage their trip. https://project-osrm.org/docs/v5.5.1/api/#nearest-service Endpoint: GET /route/v1/
Request Parameters:
| Key | Container | Description |
|---|---|---|
| alternatives | URL | Boolean for searching for alternative routes is allowed |
| steps | URL | Boolean for returning steps for each route leg |
| annotations | URL | Boolean for returning metadata for each coordinate along route geometry |
| geometries | URL | Determine format of returned route, either polyline, polyline6, or geojson |
| overview | URL | Determines level of detail of overview geometry |
| continue_straight | URL | Option for making routes as direct as possible even if slower |
https://project-osrm.org/docs/v5.5.1/api/#route-service This endpoint allows us to receive a driving polyline between stops on a route. Polylines come in Google encoded format and are then decoded into LatLng pairs in the frontend.
Endpoint: GET https://routing.openstreetmap.de/routed-car/route/v1/driving/{coordinatesSubStr}?geometries=polyline6 where {coordinatesSubStr} is a semicolon-seperated list of longitude and latitude tuples. For example: {coordinatesSubStr} = -83.7269,42.2986;-83.7753,42.2825
Example request: https://routing.openstreetmap.de/routed-car/route/v1/driving/-83.7269,42.2986;-83.7753,42.2825?geometries=polyline6
Example response:
{
"code": "Ok",
"routes": [{
"legs": [{
"steps": [],
"weight": 489.1,
"summary": "",
"duration": 489.1,
"distance": 5072.5
}],
"weight_name": "routability",
"geometry": "squtoAjhhu~CltIbbOr{CpbDpiAjo@tiCphGbtCtrI`xEpJya@xl`@unBrlO`[bL|l@taA",
"weight": 489.1,
"duration": 489.1,
"distance": 5072.5
}],
"waypoints": [{
"hint": "Yw_DhEJfpIYUAAAABAAAAHYAAAAIAQAAyY_MQbJpekAFiRRDnKSlQxQAAAAEAAAAdgAAAAgBAADJdQAAam0C-ypthQLMbQL76GyFAhYA7w0AAAAA",
"location": [-83.726998, 42.298666],
"name": "Plymouth Road",
"distance": 10.91341369
}, {
"hint": "6YdkgC7YZIA7AAAAFwAAABEBAAAIAAAAVRYlQmNBfEG2wD1DHo-7QDsAAAAXAAAAEQEAAAgAAADJdQAAuLAB-1ouhQK8sAH7BC6FAgoAfwUAAAAA",
"location": [-83.775304, 42.282586],
"name": "Longman Lane",
"distance": 9.558459137
}]
}
From this response, we take routes[0]["geometry"] and store in trip database object to later be sent to the frontend whenever changes are made to the stops on that trip.
https://developers.google.com/maps/documentation/places/web-service/nearby-search This endpoint allows us to receive information about a stop such as ratings, hours, price range, address, and a link to that stops Google Maps entry. The endpoint takes a latitude and longitude and searches in a circle of radius 50 meters and returns information about the top result within that circle. This endpoint is called whenever a stop is newly created, either in trip creation or later on.
Endpoint: GET https://places.googleapis.com/v1/places:searchNearby
Headers:
{
"X-Goog-Api-Key": [MAPS_API_KEY as set in .env],
"X-Goog-FieldMask": "places.rating,places.priceRange,places.currentOpeningHours,places.shortFormattedAddress,places.googleMapsUri",
"Content-Type": "application/json; charset=UTF-8"
}
Request Data:
{
"maxResultCount": 1,
"locationRestriction": {
"circle": {
"center": {
"latitude": [Stop latitude from DB],
"longitude": [Stop longitude from DB],
},
"radius": 50.0
}
}
}
Example response:
"places": [
{
"currentOpeningHours": {
"nextOpenTime": "2025-11-24T14:00:00Z",
"openNow": false,
"periods": [
{}, // Not displayed for brevity
...
],
"weekdayDescriptions": [
"Monday: 9:00\u202fAM\u2009\u2013\u20094:00\u202fPM",
...
]
},
"priceRange": {
"endPrice": {
"currencyCode": "USD",
"units": "20"
},
"startPrice": {
"currencyCode": "USD",
"units": "10"
}
},
"googleMapsUri": "https://maps.google.com/?cid=15450195039452542620&g_mp=Cilnb29nbGUubWFwcy5wbGFjZXMudjEuUGxhY2VzLlNlYXJjaE5lYXJieRACGAQgAA",
"rating": 4.4,
"shortFormattedAddress": "2781 Packard St, Ann Arbor"
}
]
}
From this response, we take the following data and adapt it/store in the following attributes on the stop database object:
| JSON Response Key | Attribute in DB |
|---|---|
["places"][0]["rating"] |
rating |
["places"][0]["priceRange"]["startPrice"]["units"] |
priceRange |
["places"][0]["priceRange"]["endPrice"]["units"] |
priceRange |
["places"][0]["shortFormattedAddress"] |
address |
All items of ["places"][0]["currentOpeningHours"]["weekdayDescriptions"]
|
hours |
["places"][0]["googleMapsUri"] |
googleMapsUri |