(defpackage oneliners.api (:use :cl) (:local-nicknames (#:lzb #:lazybones) (#:a #:alexandria) (#:db #:bknr.datastore)) (:import-from #:lazybones #:defendpoint* #:http-ok #:http-err)) (in-package :oneliners.api) ;;; SERVICE CONTROL (defvar *server* nil) (defun ensure-server (port address) (unless *server* (setf *server* (lzb:create-server :port port :address address)) (lzb:set-canned-response *server* 400 "Bad Request" "text/plain") (lzb:set-canned-response *server* 404 "Not Found" "text/plain") (lzb:set-canned-response *server* 500 "Server Error" "text/plain"))) (defun start (&optional (port 8888) (address "127.0.0.1")) (ensure-server port address) (lzb:install-app *server* (lzb:app)) (lzb:start-server *server*)) (defun stop () (when *server* (lzb:stop-server *server*))) ;;; API DEFINITION AND PROVISIONING (defparameter +oneliners-description+ "TBD") (lzb:provision-app () :title "Oneliners Wiki API" :version "0.0.1" :desc +oneliners-description+ :content-type "application/json" :auth 'api-token-authorization) (defun api-token-authorization () "TBD" t) ;;; ENDPOINT DEFINITIONS (defendpoint* :get "/search" () "A search endpoint returning a JSON encoded array of Command Entries. /search accepts the following query parameters: - command : The name of a command. E.g. `ls`, `grep`, `netcat`. - keywords : A comma-separated list of words that may appear in the title or description of a command entry, e.t. `'foo,bar,goo,zar,moo_blar' - limit : An integer, limiting the number of results returned. Defaults to 10. - recent : 0 for false 1 for true; sorts results by how recently they were added. Defaults to 0. - nextpage : 0 for false 1 for true; requests that the query be accompanied by a nextpage key - page : a nextpage token that will continue from a previous search. These expire after 10 minutes. **Note** that either `command` or `keyword` parameters are required. " (http-ok "[]")) (defendpoint* :put "/command/:command command-by-id:" (:auth t) "Updates a command entry in the wiki database." (cond (command (update-commmand command (lzb:request-body)) ; throws an error if fails, triggering a 500 (http-ok "true")) (t (http-err 404)))) ;no command with the given id. (defendpoint* :post "/command" (:auth t) "Adds a new command entry to the wiki database." (a:if-let (new-command (add-command-to-db (lzb:request-body))) (http-ok "{}") ; dummy implementation (http-err 400))) (defendpoint* :post "/auth" () "Requests an authorization token") ;;; HELPERS (defun command-by-id (id-string) "An integer id of a command." (list :a-dummy-command id-string)) (defun valid-command-update-data-p (jsonplist) "Checks the fields of jsonplist, return t if they are sufficient to update a command entry." jsonplist);; dummy implementation (defun update-commmand (command json-body) "Accepts a decoded json body, a plist, and " (assert (valid-command-update-data-p json-body)) (list command json-body)) ;; dummy implmenetation (defun valid-command-init-data-p (plist) "dchecks the fields in plist,returns t if they are sufficient to create a new command." plist);; dummy implementation (defun add-command-to-db (json-plist) "adds a new command to the database, returning it upon success " (assert (valid-command-init-data-p json-plist)) :dummy-ok)