Menu API
Welcome to Menu API!
Contributors:
- Sai Sriram
- Colin King
- Seung Hun Jang
- Timothy Goh
- Michael Sprintson
Useful Links:
Authentication API
Registration / Sign-up
POST to /auth/signup/
import requests
# User data includes all required fields of User model:
data = {"username": "example_username", "password": "example_password", "email": "example@example.com", "phone": "111-111-1111", "access": {"user": "true", "admin": "false"}, "restrictions": ["vegetarian", "vegan"], "preferences": {"Sushi": 10, "Asian": 10, "Latin American": 1}}
response = requests.post("https://www.menubackend.com/auth/signup/", json=data) # json=data automatically handles Content-Type header
print(response.text)
{ "result": { "id": "5efa368ac5fab88355ffa9c0" } }
Registering a user is performed by sending a POST request to the endpoint at /auth/signup/
. The body of the POST includes user information, including all required fields and any optional fields in the user model. The header must include Content-Type: application/json
. If the username or email is already taken, returns an error response. Upon success, the user's id is returned.
Login
POST to /auth/login/ -- Native login
# Native user's password and email:
data = {"password": "example_password", "username_or_email": "example@example.com" or "example"}
response = requests.post("https://www.menubackend.com/auth/login/", json=data)
print(response.text)
{ "result": { "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciO...", "logged_in_as": "example_username", "refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciO...", "user_id": "5f0fb5503cb6921b32c6b...", } }
The native login API takes a POST request containing the user's (username or email) and (password). If successful, returns a JSON response containing a newly created access token and refresh token. If the user has not already registered (i.e., is not on the database), tokens will not be issued and an error response is returned. Again requires the Content-Type: application/json
header.
POST to /auth/login/google/ -- Google login
# Google user's ID token obtained from Google's login API:
data = {"id_token": "insert_google_id_token_here"}
response = requests.post("https://www.menubackend.com/auth/login/google/", json=data)
print(response.text)
{ "result": { "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciO...", "logged_in_as": "example_username", "refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciO...", "user_id": "5f0fb5503cb6921b32c6b...", } }
Google login takes a POST request containing the user's id token obtained from Google's login API. If successful, returns a JSON response containing a newly created access token and refresh token. If the user has not already registered (i.e., is not on the database), tokens will not be issued and an error response is returned. Again requires the Content-Type: application/json
header.
A successful login attempt provides the user with a valid access token and refresh token. As its name suggests, the access token is used to access the backend's protected endpoints. However, the access token has a very limited lifespan of a few mins. Once the access token expires, the refresh token, which has a much longer lifespan of several hours, can be used to obtain a new access token using the refresh endpoint.
Logout
# First revoke the current access token:
data = {} # Empty POST body
headers = {'Authorization': 'Bearer insert_access_token_here'}
response = requests.post("https://www.menubackend.com/auth/logout/", headers=headers, json=data)
print(response.text)
{ "result": "Logout successful. Access token successfully revoked." }
# Next revoke the current refresh token:
data = {} # Empty POST body
headers = {'Authorization': 'Bearer insert_refresh_token_here'}
response = requests.post("https://www.menubackend.com/auth/logout2/", headers=headers, json=data)
print(response.text)
{ "result": "Logout successful. Refresh token successfully revoked." }
POST to /auth/logout/ and /auth/logout2/
After login, the frontend user possesses an access token and a refresh token. When logging out, the backend needs to revoke both of these tokens so they are no longer viable. To do this, the logout process provides two endpoints: /auth/logout/
and /auth/logout2/
, which revoke the active access token and refresh token, respectively. The POST body can be empty, but /auth/logout/
requires the access token header Authorization: Bearer insert_access_token_here
, and /auth/logout2/
requires the refresh token header Authorization: Bearer insert_refresh_token_here
. Upon success, a success message is returned in both cases.
Manage refresh token
POST to /auth/refresh/
# Obtain a new valid access token using a valid refresh token:
data = {} # Empty POST body
headers = {'Authorization': 'Bearer insert_refresh_token_here'}
response = requests.post("https://www.menubackend.com/auth/refresh/", headers=headers, json=data)
print(response.text)
{ "result": {"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciO..."} }
Sending a POST to this endpoint with a valid refresh token in the headers (Authorization: Bearer insert_refresh_token_here
) issues a new valid access token.
Forgot password
POST to /auth/forgot
data = {"email": "example@example.com"} # email in the post body
response = requests.post("https://www.menubackend.com/auth/forgot/", json=data)
print(response.text)
{'result': 'An email has been sent if this is a valid Menu email.'}
[This endpoint is under construction. We need to set up a menu email first] Sending a POST to this endpoint with a user's email in the body will send an email to that address with a token in the email body. This token will be included in the body of the post request to the reset endpoint.
Reset password
POST to /auth/reset/
data = {"reset_token": "insert_reset_token_from_email_here", "password": "new_password"} # reset token obtained from the email sent out by forgot endpoint
response = requests.post("https://www.menubackend.com/auth/forgot/", json=data)
print(response.text)
{'result': 'Successfully reset password.'}
[This endpoint works with /auth/forgot/, so is still under construction. Sending a POST to this endpoint with the reset token in the request body as well as the user's new password. The endpoint will update the user's password and send a confirmation email to them that the password has been changed.
Query API
data = { "name": "Avalon Diner", "addr": "12810 Southwest Fwy. Stafford, TX 77477"} # query the database for restaurant named Avalon diner at that address
response = requests.post("https://www.menubackend.com/query/restaurant/", json=data)
print(response.text)
{ "result": [ { "_id": ... "addr": "12810 Southwest Fwy. Stafford, TX 77477" ... etc ... } ] }
Resource for querying the mongoDB Restaurant collection from an HTTP request. Post request must contain header Content-Type: application/json and the body must be a JSON query. Response is a JSON with one key -- "result" whose corresponding value is a JSON List containing JSON dicts for every restuarant matching the query. If the JSON List is empty, nothing in the database matched the query.
Analagous post requests can be sent to the /query/item/
endpoint to query the database for menu items.
Category API
Get all categories
GET to /categories/
headers = {'Authorization': 'Bearer insert_access_token_here'}
response = requests.get("https://www.menubackend.com/category/", headers=headers)
print(response.text)
{'result': ['array of all categories']}
To obtain all the categories in the database, send a get request to this endpoint with an access token in the header.
Add a categories
POST to /categories/
headers = {'Authorization': 'Bearer insert_access_token_here'}
data = {"name": "category_name", "description": "category_description", "items":["array of references to item model"]}# Must be admin user token
response = requests.post("https://www.menubackend.com/category/", headers=headers, json=data)
print(response.text)
{'result': {'id': 'category id'}
To add a category to the database, send a post request to this endpoint with the access token from a user with admin priviledges (admin = true in the access field of the user model). If added successfully, returns the category id.
Get a specific category
GET to /category/<category_id>/
headers = {'Authorization': 'Bearer insert_access_token_here'}
response = requests.post("https://www.menubackend.com/category/", headers=headers)
print(response.text)
{'result': {"_id": {"$oid": "category_id"}, "description": "category_description", "items": [], "tags":[], "name":"category_name"}}
To obtain a specific category, send a get request to this endpoint with an access token in the header and category id in the URL.
Update a specific category
PATCH to /category/<category_id>/
headers = {'Authorization': 'Bearer insert_access_token_here'} # Must be admin user token
data = {"description": "category description update"}
response = requests.post("https://www.menubackend.com/category/category_id", headers=headers, json=data)
print(response.text)
{'result': {"_id": {"$oid": "category_id"}, "description": "category description update", "items": [], "tags":[], "name":"category_name"}}
To update a specific category, send a patch request to this endpoint with an admin access token in the header and category id in the URL, and the updated category fields in the body.
Delete a specific category
DELETE to /category/<category_id>/
headers = {'Authorization': 'Bearer insert_access_token_here'} # Must be admin user token
response = requests.delete("https://www.menubackend.com/category/category_id", headers=headers)
print(response.text)
{'result': {"_id": {"$oid": "category_id"}, "description": "category description update", "items": [], "tags":[], "name":"category_name"}}
To delete a specific category, send a delete request to this endpoint with an admin access token in the header and category id in the URL, and the updated category fields in the body.
Menu Item API
The Item API provides basic CRUD functionality which is very similar to the other CRUD APIs in our system.
To the \items\
endpoint, we support:
- GET request (with a valid access token in the header), which returns all items in the database.
- POST request (with an admin access token in the header), which allows creation of a new menu item on the database, where the POST body contains all the requireds fields of the menu item model.
To the \item\<item_id>\
endpoint, we support:
- GET request (with a valid access token in the header), which returns the specific item with
item_id
in the database. - PATCH request (with an admin access token in the header), which updates the item with
item_id
in the database with the request's body contents. - DELETE request (with an admin access token in the header), which deletes the item with
item_id
in the database.
Restaurant API
The Restaurant API provides basic CRUD functionality which is very similar to the other CRUD APIs in our system.
To the \restaurants\
endpoint, we support:
- GET request (with a valid access token in the header), which returns all restaurants in the database.
- POST request (with an admin access token in the header), which allows creation of a new restaurant on the database, where the POST body contains all the requireds fields of the restaurant model.
To the \restaurant\<restaurant_id>\
endpoint, we support:
- GET request (with a valid access token in the header), which returns the specific restaurant with
restaurant_id
in the database. - PATCH request (with an admin access token in the header), which updates the restaurant with
restaurant_id
in the database with the request's body contents. - DELETE request (with an admin access token in the header), which deletes the restaurant with
restaurant_id
in the database.
Review API
The Review API provides basic CRUD functionality which is very similar to the other CRUD APIs in our system.
To the \reviews\
endpoint, we support:
- GET request (with a valid access token in the header), which returns all reviews in the database.
- POST request (with an admin access token in the header), which allows creation of a new review on the database, where the POST body contains all the requireds fields of the review model.
To the \review\<review_id>\
endpoint, we support:
- GET request (with a valid access token in the header), which returns the specific review with
review_id
in the database. - PATCH request (with an admin access token in the header), which updates the review with
review_id
in the database with the request's body contents. - DELETE request (with an admin access token in the header), which deletes the review with
review_id
in the database.
To the \review\<restaurant_id>\
endpoint, we support:
- GET request (with a valid access token in the header), which returns all reviews associated with
restaurant_id
in the database
To the \review\<restaurant_id>\<max_number_of_reviews>\
endpoint, we support:
- GET request (with a valid access token in the header), which returns maximum of max_number_of_reviews number of reviews associated with the restaurant. You do not have to worry whether the number you request exceeds the actual number of reviews present. For instance, if you request 1000 reviews for a restaurant that currently has 600 reviews, this endpoint will return 600 reviews present.
User API
The User API provides basic CRUD functionality which is very similar to the other CRUD APIs in our system.
To the \users\
endpoint, we support:
- GET request (with an admin access token in the header), which returns all users in the database.
- POST request (with an admin access token in the header), which allows creation of a new user on the database, where the POST body contains all the requireds fields of the user model.
To the \user\<user_id>\
endpoint, we support:
- GET request (with an admin access token in the header, or with the jwt id of access token matching with
<user_id>
in the request param), which returns the specific user withuser_id
in the database. - PATCH request (with an admin access token in the header), which updates the user with
user_id
in the database with the request's body contents. Frontend can send uscluster_group_prefs
dictionary in the body json. For instance,{"Desserts" : 3, "Bar": 7"}
(case insensitive string keys). PATCH request will internally map "Desserts" and "Bar" to corresponding cluster label number and store{"2" : 3, "22": 3, "35": 3, "27": 7, "30": 7, "32": 7}
, since "Desserts" has three label numbers: 2, 22, 35, and "Bar" has three label numbers: 27, 30, 32. After this conversion, backend endpoint calls the DSCI usrprefgen/ POST request to update the user preferences. - DELETE request (with an admin access token in the header), which deletes the user with
user_id
in the database.
Search API
POST to /search/
The Search API provides one endpoint supporting a post request to handle search queries.
To the \search\
endpoint, send a POST request (with a logged in user's access token in the header), where POST body contains the following:
- (Required)
page
: An integer to represent which page the user has clicked on. The first page is page 0. This is required.- Example:
0
,1
,2
,3
...
- Example:
- (Optional)
user_coords
: a two-length list of latitude and longitude coordinatres from the user's location. This is optional, and if not provided theloc
andlocscore
fields will be empty.- Example:
[29.72154017, -95.39608383]
- Example:
- (Optional)
search_string
: Any string that the user inputs from the search bar. This is supposed to be either a cuisine, restaurant name, cluster name, or food name. This is optional, and if not provided the return will just be the highest rated items for the user.- Example:
chinese
,burgers
,chicken
,pizza
- Example:
- (Optional)
submenus
: a list of submenus that the user selects. Can be any combination of strings from the list of all possible submenus (see right). Should either be 'all' or a list of other strings. 'all' automatically includes all other submenus, so including other submenus with it is redundant. Adding delivery or takeout means only restaurants with delivery or takeout's menu items are considered.- Example:
['all']
,['delivery', 'dinner']
- All possible submenu filters:
[main, takeout, delivery, dessert, dinner, lunch, breakfast, pizza, sushi, appetizers, kids, brunch]
- Example:
Errors: In the case that page
parameter is not included in the POST request body, returns error id 15. If the processed_prefs
field of the user is an empty list on the database, meaning a PATCH request was never sent to the /user/
Response: The response is a list where each recommended restaurant is represented by a dictionary with 6 keys:
restaurant_object
: A dictionary containing all of the fields of the restaurant model with the exception ofmenudict
.items
: A dictionary where the keys are menu item's string names, and the values are dictionaries of the form {"score": 0.23158002514783957, "rev": 24}, where "score" is the item's recommendation score.item_sum_score
: The sum of item scores for that restaurant.rev_sum_score
: The sum of how the items were perceived in the reviews.loc
: Distance in miles of the restaurant from the user (0 ifuser_coords
is not provided above).locscore
: Miles of location converted to a score (0 ifuser_coords
is not provided above).
headers = {'Authorization': 'Bearer insert_access_token_here'}
data = {"page": 0, "search_string": "breakfast", "submenus":["breakfast"], "user_coords": [29.72154017, -95.39608383]}
response = requests.post("https://www.menubackend.com/search/", headers=headers, json=data)
print(response.text)
[ { "restaurant_object": { "_id": "ce64dcbe-5399-4be7-8f4b-88dc01b022b1", "name": "The Original Ninfa's - Uptown Houston", "link": "https://www.opentable.com/r/the-original-ninfas-uptown-houston?avt=eyJ2IjoxLCJtIjoxLCJwIjowfQ&corrid=f458c3a2-b079-46d0-a159-e58fae678ba4", "rating": "4.2", "attrs": { "piclink": "https://images.otstatic.com/prod/26414663/4/medium.jpg", "addr": "1700 Post Oak Blvd Houston, TX 77056", "diningstyle": "Casual Dining", "dresscode": "Casual Dress", "additional": "Beer, Cocktails, Delivery, Full Bar, Outdoor dining, Private Room, Takeout, Weekend Brunch, Wine", "website": "http://www.ninfas.com/" }, "dollarsigncount": 2, "cuisine": "Mexican", "revcount": 175, "loc": "Galleria / Uptown" }, "items": { "Bean, Egg, Cheese": { "score": 0.33183933558814865, "rev": 30 }, "Fajita, Egg, Cheese": { "score": 0.2749612585690266, "rev": 24 }, "Chorizo, Egg, Cheese": { "score": 0.23158002514783957, "rev": 24 }, "Potato, Egg, Cheese": { "score": 0.22243416722471326, "rev": 24 }, "Bacon, Egg, Cheese": { "score": 0.20954943656571773, "rev": 24 } }, "item_sum_score": 0.26302694106198093, "rev_sum_score": 0.6363636363636364, "loc": 4.408288309118191, "locscore": 0.04665314401622718 }, ... ]
Interested API
POST to /interested/
This endpoint is specifically for storing beta-user-request email info into mongodb collection, to later send out emails on updates to our product The Interested API supports only one request: POST. Use the POST request for /interested/ endpoint to store an email address and a default timestamp to 'interested' collection. The signup_time field will default to the request time.
data = {"email": <email address>}
response = requests.post("https://www.menubackend.com/interested/", json=data)
{'id': <"mongoDB document id">}
DSCI API
Note: Frontend should NOT call this directly; you should call backend's endpoint which then calls these.
Reviews
POST to /usefulreviewsgen/
# Get useful reviews
rhash = '0b7f3d99-13ce-4d45-955e-71902c4cb9a4'
response = requests.post(awsurl + 'usefulreviewsgen/', json = {'rhash':rhash})
newdict = ast.literal_eval(response.text.replace('Infinity', '-1').replace('false', 'False').replace('null','None'))
[ { 'name': 'RevrendDr', 'city': 'Kansas City', 'text': 'The mushroom risotto was delicious, as was the lobster bisque. Also had the lamb shank, which was nice and tender. The white sangria on special every Saturday night was also a big hit. Our waitress was sweet and attentive, if a little new. Will definitely go back for another visit.', 'overallrating': '5', 'subratings': { 'Overall': '5', 'food': '5', 'service': '4', 'ambience': '4' } }, ... # Other reviews left out for clarity ]
Getting useful reviews is performed by sending a POST request to the endpoint at /usefulreviewsgen/
. The body of the POST includes rhash
. The header must include Content-Type: application/json
. Upon success, a list of dictionaries representing reviews is returned.
Inputs
rhash
: the restaurant hash
Outputs
- List of dictionaries, each one containing:
name
:<name of the reviewer>
city
:<city the reviewer is from (i think)>
text
:<review text>
overallrating
:<rating of the review>
subratings
:<dict of subratings the user gave the restaurant>
User preference
POST to /usrprefgen/
# Generate user preferences
prefdict = {'Sushi': 10, 'Asian': 6, 'Latin Ameridfasdfcan': 10}
test_cluster_group_prefs = {'0': 1, '2': 2, '3': 3, '6':2}
response = requests.post(awsurl + 'usrprefgen/', json = {'prefscu':prefdict, 'prefscl': test_cluster_group_prefs})
utdl = ast.literal_eval(response.text.replace('Infinity', '-1').replace('false', 'False').replace('null','None'))
[ [['piece', 'succulent'], 0.0039, 1.0], [['mole', 'annie'], 0.0039, 1.0], [['crawfish', 'étouffée'], 0.0039, 1.0], [['pickle', 'lodge'], 0.0039, 1.0] ]
Takes a POST request optionally containing a cuisine preferences dictionary and/or a cluster preferences dictionary. Returns a list of lists representing the user's preferences.
Inputs
- (Should be Optional, but required for now)
prefcu
: a dictionary of cuisine names mapped to the score for that cuisine, which is a boundless integer, although this would work best with the score contained between -10 and 10. If any cuisine name is incorrect, that will be output inlog.txt
. All possible cuisines are listed on the right.- Example:
{'Sushi': 10, 'Asian': 6, 'Latin American': 10}
- Example:
- (Should be Optional, but required for now)
prefcl
: shows the user preference for each of the 54 clusters. The input dictionary is in the form of the string index of the cluster mapped to the integer score associated to that cluster. The keys can be any integer [0, 54] but 54 is kind of a useless cluster so it shouldn't be used as a key. The values can be any integer but should be constrained to [-10, 10] for best results. If an invalid key is provided, then it will be ignored and spit out inlog.txt
- Example:
{'0': 1, '2': 2, '3': 3, '6':2}
- Example:
# All possible cuisines (as of July 12, 2020)
from reccomender import make_from_cluster as mfc
mfc.cuisine_list()[1]
['American', 'Seafood', 'Steak', 'Italian', 'Steakhouse', 'Contemporary American', 'Southern', 'Mexican', 'Japanese', 'French', 'Wine Bar', 'Comfort Food', 'Contemporary Italian', 'Latin American', 'Tex-Mex', 'Cajun', 'Pizzeria', 'Mediterranean', 'Sushi', 'International', 'Lounge', 'Spanish', 'Asian', 'Global', 'Brazilian', 'Shellfish', 'Creole / Cajun / Southern', 'Bar / Lounge / Bottle Service', 'Tapas / Small Plates', 'Contemporary Southern', 'Bistro', 'Brazilian Steakhouse', 'European', 'Pub', 'Oyster Bar', 'Cocktail Bar', 'Chinese', 'Contemporary French', 'South American', 'Fusion / Eclectic', 'Farm-to-table', 'Gastro Pub', 'Sports Bar', 'Indian', 'Contemporary French / American', 'French American', 'Barbecue', 'Southwest', 'Continental', 'Vegetarian / Vegan', 'Southern African', 'Afternoon Tea', 'Contemporary Mexican', 'Latin / Spanish', 'Dessert', 'Grill', 'Lebanese', 'Korean', 'Sicilian', 'Peruvian', 'Chinese (Canton)', 'Fish', 'Burgers', 'Wild Game', 'Mexican / Southwestern', 'Contemporary Asian', 'Vietnamese', 'Traditional Mexican', 'Breakfast', 'Organic', 'Regional Japanese', 'Prime Rib', 'Dim Sum', 'Meat', 'Contemporary Indian', 'Winery', 'Halal', 'Pakistani', 'Argentinean', 'Greek', 'Creative Japanese', 'Teppanyaki', 'Ecuadorian', 'Cuban', 'Soul food', 'British', 'Beer Garden', 'Austrian', 'German', 'Rotisserie Chicken', 'Ramen', 'Regional Mexican', 'Café', 'Modern European', 'Northern Mexican', 'Thai', 'English', 'Fondue']
Outputs
- List of lists with three items - the first being a 2-length list of
main ingredient name
anddescriptor
, and the second being the floatitem score
of that ingredient and the third the integerconfidence index
, or how many times that ingredient has shown up in the input preferences.- See the code example on the right for an example.
Search results
POST to /search/
# Search for chinese restaurants with delivery
# utdl = result of previous call to /userprefgen/
response = requests.post(awsurl + 'search/', json = {
'search_string':'chinese', # breaks properly
'submenus':['delivery'], # non required works
'prefs':utdl, # breaks properly
'coords':[29.72154017, -95.39608383], # non required works
'restrictions':[], # non required works
'prefdict': {'locscore': 2, 'rev_sum_score': 0.03, 'item_sum_score': 0.6},
'page': 1
})
newdict = ast.literal_eval(response.text.replace('Infinity', '-1').replace('false', 'False').replace('null','None'))
{
"3841689": { // hash of restaurant
"items": { // dictionary of items in the top n belonging to that restaurant
"82051594": {"score": 0.3346763757962888, "rev": 0}, // item hash is mapped to the score
"21833507": {"score": 0.3191075257345033, "rev": 3},
...
},
"item_sum_score": 1.307567803061584, // sum of item scores for that restaurant
"rev_sum_score": 0.0, // the sum of how the items were perceived in the reviews
"loc": 21.016145659571272, // how far away the restaurant is in miles
"locscore": 0.005 // miles of location converted to a score
},
...
}
/* All possible submenu filters */
main, takeout, delivery, dessert, dinner, lunch, breakfast, pizza, sushi, appetizers, kids, brunch
Takes a POST request containing a search query and other parameters. Returns a list of dictionaries representing the recommended restaurants and their basic information.
Inputs
prefs
: the output of the user preference endpoint, which is explained in detail in the user-preferences endpoint in the "results" section. This is required.page
: An integer to represent which page the user has clicked on. The first page is page 0. This is required.- Example:
0
,1
,2
,3
...
- Example:
- (Optional)
coords
: a two-length list of latitude and longitude coordinatres from the user's location. This is optional, and if not provided theloc
andlocscore
fields will be empty.- Example:
[29.72154017, -95.39608383]
- Example:
- (Optional)
restrictions
: a list of restrictions the user selected. For now, only 'vegan' and 'vegetarian' are supported.- Example:
['vegan']
,[]
- Example:
- (Optional)
prefdict
: This is a three-length dictionary with keyslocscore
,rev_sum_score
, anditem_sum_score
. Each of these keys are mapped to a float which represents the importance of location, review score, and item score respectively for the user. - (Optional)
search_string
: Any string that the user inputs from the search bar. This is supposed to be either a cuisine, restaurant name, cluster name, or food name. This is optional, and if not provided the return will just be the highest rated items for the user.- Example:
chinese
,burgers
,chicken
,pizza
- Example:
- (Optional)
submenus
: a list of submenus that the user selects. Can be any combination of strings from the list of all possible submenus (see right). Should either be 'all' or a list of other strings. 'all' automatically includes all other submenus, so including other submenus with it is redundant. Adding delivery or takeout means only restaurants with delivery or takeout's menu items are considered.- Example:
['all']
,['delivery', 'dinner']
- Example:
Outputs
- List of dictionaries where the restaurant hash is mapped to a dictionary of top items belonging to that restaurant
- See the code example on the right for an example.
Restaurant menu
POST to /rstget/
# Get recommended menu items for a restaurant
rhash = '0b7f3d99-13ce-4d45-955e-71902c4cb9a4'
response = requests.post(awsurl + 'rstget/', json = {'rhash':rhash}), 'prefs':utdl})
newdict = ast.literal_eval(response.text.replace('Infinity', '-1').replace('false', 'False').replace('null','None'))
{
"42d9f32b-f4d8-4723-b905-240dcd3324f2": // hash of the item
{"itemscores":
[ // list of ingredients, each with a scores dict and the name and description. This structure is consistent for each ingredient, with the 'scores' key mapped to a dictionary of 'score' mapped to the item score, 'n' mapped to the confidence index, 'desc' mapped to the descriptor of that ingredient, and 'name' mapped to the name of that ingredient.
{"scores": {"score": 0.829, "n": 3}, "desc": "", "name": "tomato"},
{"scores": {"score": 0.738, "n": 3}, "desc": "", "name": "onion"},
...
],
"score": 0.171969300975924, // score of the item's ingredients (float)
"hash": 4e17ee65-c3ad-480d-8457-1878fc2c146f, // hash of the restaurant it belongs to (string)
"submenu": "Lunch Menu", // submenu the item was found in (string)
"submenufilter": ["lunch"], // submenu filter the item was found in (list of strings - constrained to items in all possible submenufilters
"price": "9.00", // price of the item (string of float)
"rev": 4, // accumulated score from the reviews (int))
}
...
}
/* All possible submenu filters */
main, takeout, delivery, dessert, dinner, lunch, breakfast, pizza, sushi, appetizers, kids, brunch
Takes a POST request containing a restaurant hash and (optionally) user preferences. Returns a list of dictionaries representing the recommended menu items and their basic information.
Inputs
rhash
: A UUID of a restraunt in the database. Must be a string with no leading spaces.- (Optional)
prefs
: the output of the user preference endpoint, which is explained in detail in the user-preferences in the "results" section. This is optional, and if it is not provided theitemscores
key in the results dictionary will map to an empty list.
Outputs
- See the code example on the right for an example and description.
Models
Category
Field Name | Code | Type | Description | Required |
---|---|---|---|---|
name | StringField(required=True) |
String | name of category | Required |
description | StringField(required=True) |
String | description of category | Required |
tags | ListField(StringField()) |
Array of String | tags associated with category. | |
items | ListField(ReferenceField(Item)) |
Array of ObjectID | array of references to Item model. |
Menu Item
Field Name | Code | Type | Description | Required |
---|---|---|---|---|
_id | StringField(primary_key=True, required=True) |
String of length 36 | MongoDB Primary Key hash, must be length 36 alphanumeric | Required |
location | StringField(required=True) |
String of length 36 | reference to Restaurant model. |
Required |
name | StringField(required=True) |
String | name of menu item. | Required |
desc | StringField() |
String | description of menu item. | |
price | FloatField(required=True) |
Float | price of menu item. | Required |
image_url | StringField() |
String | url that holds menu item image. | |
tags | ListField(StringField()) |
Array of String | tags associated with menu item. |
Restaurant
Restaurant model
Field Name | Code | Type | Description | Required |
---|---|---|---|---|
_id | _id = StringField(primary_key=True, required=True) |
String | MongoDB Primary Key hash, must be length 36 alphanumeric | Required |
name | StringField(required=True) |
String | name of restaurant | Required |
link | StringField() |
String | link to restaurant info | |
rating | StringField() |
String | rating of restaurant | |
attrs | EmbeddedDocumentField(Attributes) |
Attribute model | attributes of restaurant | |
dollarsigncount | IntField() |
Integer | dollar sign indicating price of restaurant | |
cuisine | StringField() |
String | type of cuisine | |
revcount | IntField() |
Integer | ||
loc | StringField() |
String | restaurant address | |
menudict | ListField(StringField()) |
Array of String (length 36) | object ids of menu item that the restaurant serves |
Attributes model
Field Name | Code | Type | Description | Required |
---|---|---|---|---|
piclink | StringField() |
String | url of restaurant picture | |
addr | StringField() |
String | restaurant address | |
cuisines | StringField() |
String | type of cuisine | |
diningstyle | StringField() |
String | dining style of cuisine | |
dresscode | StringField() |
String | restaurant dress code | |
additional | StringField() |
String | additional info of restaurant | |
website | StringField() |
String | restaurant website link |
Review
Review model
Field Name | Code | Type | Description | Required |
---|---|---|---|---|
location | StringField(required=True) |
String of length 36 | MongoDb object id of restaurant model | Required |
name | StringField(required=True) |
String | reviewer name | Required |
city | StringField(required=True) |
String | city location name | Required |
overallrating | IntField() |
Integer | overall rating for this review | |
subratings | EmbeddedDocumentField(Subrating) |
Subrating model | subrating information for this review | |
text | StringField() |
String | review text |
Subrating model
Field Name | Code | Type | Description | Required |
---|---|---|---|---|
overall | IntField() |
Integer | overall rating | |
food | IntField() |
Integer | food rating | |
service | IntField() |
Integer | service rating | |
ambience | IntField() |
Integer | ambience rating |
User
User model
- User info
Field Name | Code | Type | Description | Required |
---|---|---|---|---|
username | StringField(required=True) |
String | first and last name of user | Required |
password | BinaryField(required=True) |
Binary | encrypted account password | Required |
EmailField(required=True, unique=True) |
Email field | account email | Required | |
access | EmbeddedDocumentField(Access) |
Access model | refer to Access model |
|
phone | PhoneField() |
Phone field | account phone number |
- Restrictions
Field Name | Code | Type | Description | Required |
---|---|---|---|---|
restrictions | ListField() |
Array of String | list of restrictions |
- Pref levels
Field Name | Code | Type | Description | Required |
---|---|---|---|---|
preferences | DictField(default = {}) |
Dictionary (key = string, value = integer) | key-value pair of user preferences | |
cluster_group_prefs | DictField(default = {}) |
Dictionary (key = string, value = integer) | key-value pair of cluster_group_prefs (https://docs.google.com/spreadsheets/d/108FCNhgjhSnSmJ-OyNcjUzSwVw2f7l6cF6dU--GoR9M/edit#gid=0) | |
processed_prefs | DynamicField() |
Array of String | cached preferences after being processed by dsci |
- Other
Field Name | Code | Type | Description | Required |
---|---|---|---|---|
created_on | DateTimeField(default = datetime.now) |
DateTime field | indicates when this account was generated | |
fav_restaurant | StringField() |
String of length 36 | reference to restaurant model |
Access model
Field Name | Code | Type | Description | Required |
---|---|---|---|---|
user | BooleanField(default=False) |
Boolean | is this account "user" level? | |
admin | BooleanField(default=False) |
Boolean | is this account "admin" level? | |
googlelogin | BooleanField(default=False) |
Boolean | is this account "googlelogin" level? | |
facebooklogin | BooleanField(default=False) |
Boolean | is this account "facebooklogin" level? | |
guest | BooleanField(default=False) |
Boolean | is this account "guest" level? |
Errors
Menu Backend API uses the following error codes:
Error Code | Meaning |
---|---|
400 | Bad Request -- Your request is invalid. Could be: Request not json , Update failure , or Deletion failure . |
401 | Unauthorized -- Authorization has been refused for the given credentials |
403 | Forbidden -- The current user is not authorized to take this action. |
404 | Not Found -- This route is currently not supported. |
409 | Something is Invalid - Could be: This email is already taken or the email address is wrong , The user did not authorize the use of their email , This username is already taken , or Invalid token provided . |
500 | Internal Server Error -- We had a problem with our server. |
Error Ids
Look for specific error ids here!
Error Id | Name of Error | Error message | Status Code |
---|---|---|---|
1 | request_not_json |
Data type in request is not JSON | 400 |
2 | unauthorized |
Authorization has been revoked | 401 |
3 | forbidden |
Current user is not allowed to take this action | 403 |
4 | invalid_route |
This route is currently not supported | 404 |
5 | invalid_email |
This email is already taken or the email address is wrong | 409 |
6 | oauth_scopes_unauthorized |
The user did not authorize the use of their email | 409 |
7 | invalid_username |
This username is already taken | 409 |
8 | invalid_token |
Invalid token provided | 409 |
9 | update_failure |
Database document update failed | 400 |
10 | deletion_failure |
Database document deletion failed | 400 |
11 | validation_error |
Marshmallow validation has failed | 400 |
12 | mongodb_get_object_error |
MongoDB document get request has failed | 500 |
13 | all_other_error |
This error message corresponds to all other errors | 500 |
14 | wrong_login_route |
You cannot attempt login to /auth/login/ without user access field being True |
401 |
15 | unexpected_body_format |
Request body has format deviating from what is expected | 400 |
16 | no_user_prefs |
User doesn't have processed preferences before searching | 500 |