From 50b75e1e633f84de900386bc699bf95f1ee14f05 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 24 Feb 2019 12:24:55 +0000 Subject: [PATCH] API: Resolves #1148: Added support for search end-point and improved error handling --- CliClient/app/command-apidoc.js | 5 +++++ ReactNativeClient/lib/ClipperServer.js | 7 ++++++- ReactNativeClient/lib/services/SearchEngineUtils.js | 8 +++++--- ReactNativeClient/lib/services/rest/Api.js | 10 ++++++++++ 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/CliClient/app/command-apidoc.js b/CliClient/app/command-apidoc.js index 95d5b368b..2f4bfe1bb 100644 --- a/CliClient/app/command-apidoc.js +++ b/CliClient/app/command-apidoc.js @@ -113,6 +113,11 @@ class Command extends BaseCommand { lines.push('\tcurl http://localhost:41184/tags?fields=id'); lines.push(''); + lines.push('# Error handling'); + lines.push(''); + lines.push('In case of an error, an HTTP status code >= 400 will be returned along with a JSON object that provides more info about the error. The JSON object is in the format `{ "error": "description of error" }`.'); + lines.push(''); + lines.push('# About the property types'); lines.push(''); lines.push('* Text is UTF-8.'); diff --git a/ReactNativeClient/lib/ClipperServer.js b/ReactNativeClient/lib/ClipperServer.js index cc2a5d670..63ef1b9fa 100644 --- a/ReactNativeClient/lib/ClipperServer.js +++ b/ReactNativeClient/lib/ClipperServer.js @@ -148,7 +148,12 @@ class ClipperServer { writeResponse(200, response ? response : ''); } catch (error) { this.logger().error(error); - writeResponse(error.httpCode ? error.httpCode : 500, error.message); + const httpCode = error.httpCode ? error.httpCode : 500; + const msg = []; + if (httpCode >= 500) msg.push('Internal Server Error'); + if (error.message) msg.push(error.message); + + writeResponse(httpCode, { error: msg.join(': ') }); } } diff --git a/ReactNativeClient/lib/services/SearchEngineUtils.js b/ReactNativeClient/lib/services/SearchEngineUtils.js index 027e5f0d5..33149d2bb 100644 --- a/ReactNativeClient/lib/services/SearchEngineUtils.js +++ b/ReactNativeClient/lib/services/SearchEngineUtils.js @@ -3,15 +3,17 @@ const Note = require('lib/models/Note'); class SearchEngineUtils { - static async notesForQuery(query) { + static async notesForQuery(query, options = null) { + if (!options) options = {}; + const results = await SearchEngine.instance().search(query); const noteIds = results.map(n => n.id); - const previewOptions = { + const previewOptions = Object.assign({}, { order: [], fields: Note.previewFields(), conditions: ['id IN ("' + noteIds.join('","') + '")'], - } + }, options); const notes = await Note.previews(null, previewOptions); diff --git a/ReactNativeClient/lib/services/rest/Api.js b/ReactNativeClient/lib/services/rest/Api.js index 28dec68b3..e0cf8dc7f 100644 --- a/ReactNativeClient/lib/services/rest/Api.js +++ b/ReactNativeClient/lib/services/rest/Api.js @@ -13,6 +13,7 @@ const { shim } = require('lib/shim'); const HtmlToMd = require('lib/HtmlToMd'); const { fileExtension, safeFileExtension, safeFilename, filename } = require('lib/path-utils'); const ApiResponse = require('lib/services/rest/ApiResponse'); +const SearchEngineUtils = require('lib/services/SearchEngineUtils'); class ApiError extends Error { @@ -207,6 +208,15 @@ class Api { throw new ErrorMethodNotAllowed(); } + async action_search(request) { + if (request.method !== 'GET') throw new ErrorMethodNotAllowed(); + + const query = request.query.query; + if (!query) throw new ErrorBadRequest('Missing "query" parameter'); + + return await SearchEngineUtils.notesForQuery(query, this.notePreviewsOptions_(request)); + } + async action_folders(request, id = null, link = null) { if (request.method === 'GET' && !id) { return await Folder.allAsTree({ fields: this.fields_(request, ['id', 'parent_id', 'title']) });