From d292bdcc119e1d8a939235ede15eab7331e21eb0 Mon Sep 17 00:00:00 2001 From: Debanjum Singh Solanky Date: Sat, 8 Oct 2022 13:16:08 +0300 Subject: [PATCH] Do not version API. Premature given current state of the codebase - Reason - All clients that currently consume the API are part of Khoj - Any breaking API changes will be fixed in clients immediately - So decoupling client from API is not required - This removes the burden of maintaining muliple versions of the API --- src/interface/emacs/khoj.el | 4 ++-- src/interface/web/assets/config.js | 6 +++--- src/interface/web/index.html | 8 ++++---- src/main.py | 4 ++-- src/routers/{api_v1_0.py => api.py} | 14 +++++++------- src/routers/api_beta.py | 2 +- tests/data/markdown/main_readme.md | 4 ++-- tests/data/org/main_readme.org | 4 ++-- tests/test_client.py | 22 +++++++++++----------- 9 files changed, 34 insertions(+), 34 deletions(-) rename src/routers/{api_v1_0.py => api.py} (94%) diff --git a/src/interface/emacs/khoj.el b/src/interface/emacs/khoj.el index e5b05605..d3d6c6f9 100644 --- a/src/interface/emacs/khoj.el +++ b/src/interface/emacs/khoj.el @@ -226,7 +226,7 @@ Use `which-key` if available, else display simple message in echo area" (defun khoj--get-enabled-content-types () "Get content types enabled for search from API." - (let ((config-url (format "%s/api/v1.0/config/data" khoj-server-url))) + (let ((config-url (format "%s/api/config/data" khoj-server-url))) (with-temp-buffer (erase-buffer) (url-insert-file-contents config-url) @@ -243,7 +243,7 @@ Use `which-key` if available, else display simple message in echo area" "Construct API Query from QUERY, SEARCH-TYPE and (optional) RERANK params." (let ((rerank (or rerank "false")) (encoded-query (url-hexify-string query))) - (format "%s/api/v1.0/search?q=%s&t=%s&r=%s&n=%s" khoj-server-url encoded-query search-type rerank khoj-results-count))) + (format "%s/api/search?q=%s&t=%s&r=%s&n=%s" khoj-server-url encoded-query search-type rerank khoj-results-count))) (defun khoj--query-api-and-render-results (query search-type query-url buffer-name) "Query Khoj API using QUERY, SEARCH-TYPE, QUERY-URL. diff --git a/src/interface/web/assets/config.js b/src/interface/web/assets/config.js index 90412e1c..965df9bc 100644 --- a/src/interface/web/assets/config.js +++ b/src/interface/web/assets/config.js @@ -10,7 +10,7 @@ var emptyValueDefault = "🖊️"; /** * Fetch the existing config file. */ -fetch("/api/v1.0/config/data") +fetch("/api/config/data") .then(response => response.json()) .then(data => { rawConfig = data; @@ -26,7 +26,7 @@ fetch("/api/v1.0/config/data") configForm.addEventListener("submit", (event) => { event.preventDefault(); console.log(rawConfig); - fetch("/api/v1.0/config/data", { + fetch("/api/config/data", { method: "POST", credentials: "same-origin", headers: { @@ -46,7 +46,7 @@ regenerateButton.addEventListener("click", (event) => { event.preventDefault(); regenerateButton.style.cursor = "progress"; regenerateButton.disabled = true; - fetch("/api/v1.0/update?force=true") + fetch("/api/update?force=true") .then(response => response.json()) .then(data => { regenerateButton.style.cursor = "pointer"; diff --git a/src/interface/web/index.html b/src/interface/web/index.html index 3d940ee3..c3360d8f 100644 --- a/src/interface/web/index.html +++ b/src/interface/web/index.html @@ -77,8 +77,8 @@ // Generate Backend API URL to execute Search url = type === "image" - ? `/api/v1.0/search?q=${encodeURIComponent(query)}&t=${type}&n=${results_count}` - : `/api/v1.0/search?q=${encodeURIComponent(query)}&t=${type}&n=${results_count}&r=${rerank}`; + ? `/api/search?q=${encodeURIComponent(query)}&t=${type}&n=${results_count}` + : `/api/search?q=${encodeURIComponent(query)}&t=${type}&n=${results_count}&r=${rerank}`; // Execute Search and Render Results fetch(url) @@ -94,7 +94,7 @@ function updateIndex() { type = document.getElementById("type").value; - fetch(`/api/v1.0/update?t=${type}`) + fetch(`/api/update?t=${type}`) .then(response => response.json()) .then(data => { console.log(data); @@ -118,7 +118,7 @@ function populate_type_dropdown() { // Populate type dropdown field with enabled search types only var possible_search_types = ["org", "markdown", "ledger", "music", "image"]; - fetch("/api/v1.0/config/data") + fetch("/api/config/data") .then(response => response.json()) .then(data => { document.getElementById("type").innerHTML = diff --git a/src/main.py b/src/main.py index 13d15674..33320285 100644 --- a/src/main.py +++ b/src/main.py @@ -19,7 +19,7 @@ from PyQt6.QtCore import QThread, QTimer # Internal Packages from src.configure import configure_server -from src.routers.api_v1_0 import api_v1_0 +from src.routers.api import api from src.routers.api_beta import api_beta from src.routers.frontend import frontend_router from src.utils import constants, state @@ -31,7 +31,7 @@ from src.interface.desktop.system_tray import create_system_tray # Initialize the Application Server app = FastAPI() app.mount("/static", StaticFiles(directory=constants.web_directory), name="static") -app.include_router(api_v1_0, prefix="/api/v1.0") +app.include_router(api, prefix="/api") app.include_router(api_beta, prefix="/api/beta") app.include_router(frontend_router) diff --git a/src/routers/api_v1_0.py b/src/routers/api.py similarity index 94% rename from src/routers/api_v1_0.py rename to src/routers/api.py index b6dea695..c8d4fa3a 100644 --- a/src/routers/api_v1_0.py +++ b/src/routers/api.py @@ -15,23 +15,23 @@ from src.utils.config import SearchType from src.utils import state, constants -api_v1_0 = APIRouter() +api = APIRouter() logger = logging.getLogger(__name__) -@api_v1_0.get('/config/data', response_model=FullConfig) -def config_data(): +@api.get('/config/data', response_model=FullConfig) +def get_config_data(): return state.config -@api_v1_0.post('/config/data') -async def config_data(updated_config: FullConfig): +@api.post('/config/data') +async def set_config_data(updated_config: FullConfig): state.config = updated_config with open(state.config_file, 'w') as outfile: yaml.dump(yaml.safe_load(state.config.json(by_alias=True)), outfile) outfile.close() return state.config -@api_v1_0.get('/search', response_model=list[SearchResponse]) +@api.get('/search', response_model=list[SearchResponse]) def search(q: str, n: Optional[int] = 5, t: Optional[SearchType] = None, r: Optional[bool] = False): results: list[SearchResponse] = [] if q is None or q == '': @@ -121,7 +121,7 @@ def search(q: str, n: Optional[int] = 5, t: Optional[SearchType] = None, r: Opti return results -@api_v1_0.get('/update') +@api.get('/update') def update(t: Optional[SearchType] = None, force: Optional[bool] = False): state.model = configure_search(state.model, state.config, regenerate=force, t=t) return {'status': 'ok', 'message': 'index updated'} diff --git a/src/routers/api_beta.py b/src/routers/api_beta.py index 389025b9..28d9cc2b 100644 --- a/src/routers/api_beta.py +++ b/src/routers/api_beta.py @@ -7,7 +7,7 @@ from typing import Optional from fastapi import APIRouter # Internal Packages -from src.routers.api_v1_0 import search +from src.routers.api import search from src.processor.conversation.gpt import converse, extract_search_type, message_to_log, message_to_prompt, understand, summarize from src.utils.config import SearchType from src.utils.helpers import get_absolute_path, get_from_dict diff --git a/tests/data/markdown/main_readme.md b/tests/data/markdown/main_readme.md index 7f626319..14d97a97 100644 --- a/tests/data/markdown/main_readme.md +++ b/tests/data/markdown/main_readme.md @@ -43,8 +43,8 @@ just generating embeddings* - **Khoj via API** - See [Khoj API Docs](http://localhost:8000/docs) - - [Query](http://localhost:8000/api/v1.0/search?q=%22what%20is%20the%20meaning%20of%20life%22) - - [Update Index](http://localhost:8000/api/v1.0/update?t=ledger) + - [Query](http://localhost:8000/api/search?q=%22what%20is%20the%20meaning%20of%20life%22) + - [Update Index](http://localhost:8000/api/update?t=ledger) - [Configure Application](https://localhost:8000/ui) - **Khoj via Emacs** - [Install](https://github.com/debanjum/khoj/tree/master/src/interface/emacs#installation) diff --git a/tests/data/org/main_readme.org b/tests/data/org/main_readme.org index 4f63801a..48c1bfd5 100644 --- a/tests/data/org/main_readme.org +++ b/tests/data/org/main_readme.org @@ -27,8 +27,8 @@ - Run ~M-x khoj ~ or Call ~C-c C-s~ - *Khoj via API* - - Query: ~GET~ [[http://localhost:8000/api/v1.0/search?q=%22what%20is%20the%20meaning%20of%20life%22][http://localhost:8000/api/v1.0/search?q="What is the meaning of life"]] - - Update Index: ~GET~ [[http://localhost:8000/api/v1.0/update][http://localhost:8000/api/v1.0/update]] + - Query: ~GET~ [[http://localhost:8000/api/search?q=%22what%20is%20the%20meaning%20of%20life%22][http://localhost:8000/api/search?q="What is the meaning of life"]] + - Update Index: ~GET~ [[http://localhost:8000/api/update][http://localhost:8000/api/update]] - [[http://localhost:8000/docs][Khoj API Docs]] - *Call Khoj via Python Script Directly* diff --git a/tests/test_client.py b/tests/test_client.py index c17e7edd..d3dde245 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -28,7 +28,7 @@ def test_search_with_invalid_content_type(): user_query = quote("How to call Khoj from Emacs?") # Act - response = client.get(f"/api/v1.0/search?q={user_query}&t=invalid_content_type") + response = client.get(f"/api/search?q={user_query}&t=invalid_content_type") # Assert assert response.status_code == 422 @@ -43,7 +43,7 @@ def test_search_with_valid_content_type(content_config: ContentConfig, search_co # config.content_type.image = search_config.image for content_type in ["org", "markdown", "ledger", "music"]: # Act - response = client.get(f"/api/v1.0/search?q=random&t={content_type}") + response = client.get(f"/api/search?q=random&t={content_type}") # Assert assert response.status_code == 200 @@ -51,7 +51,7 @@ def test_search_with_valid_content_type(content_config: ContentConfig, search_co # ---------------------------------------------------------------------------------------------------- def test_update_with_invalid_content_type(): # Act - response = client.get(f"/api/v1.0/update?t=invalid_content_type") + response = client.get(f"/api/update?t=invalid_content_type") # Assert assert response.status_code == 422 @@ -65,7 +65,7 @@ def test_update_with_valid_content_type(content_config: ContentConfig, search_co for content_type in ["org", "markdown", "ledger", "music"]: # Act - response = client.get(f"/api/v1.0/update?t={content_type}") + response = client.get(f"/api/update?t={content_type}") # Assert assert response.status_code == 200 @@ -73,7 +73,7 @@ def test_update_with_valid_content_type(content_config: ContentConfig, search_co # ---------------------------------------------------------------------------------------------------- def test_regenerate_with_invalid_content_type(): # Act - response = client.get(f"/api/v1.0/update?force=true&t=invalid_content_type") + response = client.get(f"/api/update?force=true&t=invalid_content_type") # Assert assert response.status_code == 422 @@ -87,7 +87,7 @@ def test_regenerate_with_valid_content_type(content_config: ContentConfig, searc for content_type in ["org", "markdown", "ledger", "music", "image"]: # Act - response = client.get(f"/api/v1.0/update?force=true&t={content_type}") + response = client.get(f"/api/update?force=true&t={content_type}") # Assert assert response.status_code == 200 @@ -104,7 +104,7 @@ def test_image_search(content_config: ContentConfig, search_config: SearchConfig for query, expected_image_name in query_expected_image_pairs: # Act - response = client.get(f"/api/v1.0/search?q={query}&n=1&t=image") + response = client.get(f"/api/search?q={query}&n=1&t=image") # Assert assert response.status_code == 200 @@ -122,7 +122,7 @@ def test_notes_search(content_config: ContentConfig, search_config: SearchConfig user_query = quote("How to git install application?") # Act - response = client.get(f"/api/v1.0/search?q={user_query}&n=1&t=org&r=true") + response = client.get(f"/api/search?q={user_query}&n=1&t=org&r=true") # Assert assert response.status_code == 200 @@ -139,7 +139,7 @@ def test_notes_search_with_only_filters(content_config: ContentConfig, search_co user_query = quote('+"Emacs" file:"*.org"') # Act - response = client.get(f"/api/v1.0/search?q={user_query}&n=1&t=org") + response = client.get(f"/api/search?q={user_query}&n=1&t=org") # Assert assert response.status_code == 200 @@ -156,7 +156,7 @@ def test_notes_search_with_include_filter(content_config: ContentConfig, search_ user_query = quote('How to git install application? +"Emacs"') # Act - response = client.get(f"/api/v1.0/search?q={user_query}&n=1&t=org") + response = client.get(f"/api/search?q={user_query}&n=1&t=org") # Assert assert response.status_code == 200 @@ -173,7 +173,7 @@ def test_notes_search_with_exclude_filter(content_config: ContentConfig, search_ user_query = quote('How to git install application? -"clone"') # Act - response = client.get(f"/api/v1.0/search?q={user_query}&n=1&t=org") + response = client.get(f"/api/search?q={user_query}&n=1&t=org") # Assert assert response.status_code == 200