import Widget from require "lapis.html"
import domain from require("lapis.config").get!
if domain == "localhost"
domain = "http://localhost"
else
domain = "https://#{domain}"
example_key = "JDJiJDEyJFRPaG0wOW16VXhoUTd3dElB"
class Docs_1 extends Widget
content: =>
task_list = ->
ul style: "font-family: monospace;", ->
li ->
a href: "#task-operations", "/new/:content"
text " { content: string }"
li ->
a href: "#task-operations", "/get/:selector"
text " { id: integer, content: string }"
li ->
a href: "#task-operations", "/do/:selector"
text " { id: integer, content: string }"
li ->
a href: "#task-operations", "/undo/:selector"
text " { id: integer, content: string }"
li ->
a href: "#task-operations", "/edit/:selector"
text " { id: integer, content: string, new_content: string }"
li ->
a href: "#task-operations", "/delete/:selector"
text " { id: integer, content: string }"
li ->
a href: "#list", "/list"
text " { count: integer, done: boolean, page: integer, order: 'asc'/'desc' }"
li ->
a href: "#random", "/random"
text " { count: integer, done: boolean }"
style -> raw "
h3 { font-family: monospace; }
.top { font-size: 1.33rem; }
blockquote > code { white-space: normal; }
"
a name: "top"
ol style: "font-family: monospace;", ->
li ->
a href: "#endpoints", "Endpoints"
li ->
a href: "#auth", "Authorization"
li ->
a href: "#tasks", "Tasks"
task_list!
li ->
a href: "#keys", "API Keys"
ul ->
li ->
a href: "#new-key", "/key/new"
li ->
a href: "#delete-key", "/key/delete/:key"
text " { key: string }"
li ->
a href: "#errors", "Errors"
li ->
a href: "#rate-limit", "Rate Limiting"
li ->
a href: "#changes", "Changes"
li ->
a href: "#next", "Coming Next"
li ->
a href: "#notes", "Notes"
a name: "endpoints"
h2 "Endpoints"
p ->
text "All endpoints are under "
code "#{domain}/v1"
text ", and accept parameters in the URL hierarchy, from POSTed JSON, in URI query string params, and for API keys, in an Authorization header. Most parameters are optional, with the only required parameters specified as part of the URL hierarchy."
p ->
text "All endpoints return HTTP status 200 when successful, as well as a JSON object ("
code '{ "success": true }'
text ") with a success boolean and extra data depending on the endpoint. When errors are encountered, a non-200 HTTP status code is sent, along with a JSON object ("
code '{ "success": false, "errors": [ /*list of strings omitted*/ ] }'
text ") with an array of errors (usually containing a single error)."
button class: "collapsible", "Examples"
div class: "content", ->
blockquote ->
code "#{domain}/v1/get/12?api_key=#{example_key}"
p ->
text "Assuming a task with ID "
code 12
text " belongs to you, and the "
code "api_key"
text " is valid, returns:"
code "{\"success\":true,\"task\":{\"created_at\":\"2018-04-24 14:15:04\",\"id\":12,\"content\":\"Make index return a logged_out view instead of redirecting to login\",\"done\":true,\"user_id\":1,\"updated_at\":\"2018-04-25 04:28:36\"}}"
p "(Note: This example is a real task that I added while developing this API. :P)"
a class: ".top", href: "#top", "back to top"
a name: "auth"
h2 "Authorization"
p "Authorization is done by sending an API key along with other parameters. It can be sent as an Authorization header, in a URI query string (not recommended), or as part of a POSTed JSON object."
p ->
text "Grab an API key from "
a href: @url_for("index"), "the web interface"
text " to get started. You can also delete existing API keys there."
button class: "collapsible", "Examples"
div class: "content", ->
blockquote ->
p "As a header:"
code "Authorization: #{example_key}"
p ->
text "As part of a JSON object:"
br!
text "(POSTing to "
code "#{domain}/v1/get"
text " in this example)"
code "{ \"id\": 12, \"api_key\": \"#{example_key}\" }"
a class: ".top", href: "#top", "back to top"
a name: "tasks"
h2 "Tasks"
p ->
text "In the endpoints listed below, "
code ":content"
text " represents an optional URI-encoded string (for "
code "/new/:content"
text " only), and "
code ":selector"
text " represents an integer for selecting via ID, or a URI-encoded string for selecting via content (generally not recommended). All endpoints except "
code "/list"
text " and "
code "/random"
text " accept these in the URL, as query parameters, or in a POSTed JSON object, and operate on a single task."
p ->
code "/list"
text " and "
code "/random"
text " are a little more complex, and are explained further below."
task_list!
a class: ".top", href: "#top", "back to top"
a name: "task-operations"
h3 "/new, /get, /do, /undo, /edit, /delete"
p "As stated above, all of these operations accept the same data from the same formats, and return data in the same format, except:"
ul ->
li ->
code "/new"
text " only accepts "
code "content"
text " for input (you can't specify an ID for something that doesn't exist..)"
li ->
code "/edit"
text " additionally accepts a "
code "done"
text " boolean, and/or "
code "new_content"
text " specifying how to modify a task."
li ->
code "/delete"
text " only returns a success boolean (and errors array if there are errors)."
p ->
text "All tasks are returned like so:"
br!
code '{ "success": true, "task": { "id": 4, "user_id": 2, "content": "Get a new API key.", "done": false, "created_at": "2018-04-25 04:27:47", "updated_at": "2018-04-25 04:27:47" } }'
button class: "collapsible", "Examples"
div class: "content", ->
p "To be written."
-- TODO example using just query stuff, one w header and URL hierarchy params only
-- state every one returns the same thing except delete just returns success or errors
a class: ".top", href: "#top", "back to top"
a name: "list"
h3 "/list"
p "Note: The API was recently updated (as evidenced by all the changes here), however, for the moment, this is where I have stopped updating documentation."
p "Below here, the important things to note are that API keys no longer have IDs (that seemed to be broken anyhow), and that random is still not implemented."
p ->
text "Returns an array of task objects (see "
a href: "#new", "/new"
text " for an example task object). All arguments are optional:"
element "table", ->
thead ->
tr ->
th "Argument"
th "Type"
th "Default"
tbody ->
tr ->
td -> code "count"
td "integer"
td 50
tr ->
td -> code "done"
td "boolean"
td "returns ALL tasks if not set"
tr ->
td -> code "page"
td "integer"
td 1
tr ->
td -> code "order"
td "'asc'/'desc'"
td "'asc' (oldest first)"
p ->
text "If you request a page beyond the number of pages available, the last page will be returned. "
code "page"
text " is specified in the response, so you will know if you have received a different page than requested. Additionally, "
code "pages"
text " is defined in all requests to "
code "/list"
text ". Example response (with tasks trimmed out):"
blockquote ->
code '{ "success": true, page: 5, pages: 10, tasks: [ /* task list omitted */ ] }'
a class: ".top", href: "#top", "back to top"
a name: "random"
h3 "/random"
p "This is the only endpoint not currently implemented. This documentation will be updated once it is finished."
-- TODO /random { count: #, done: bool } (both args optional, defaults count 1, done false)
a class: ".top", href: "#top", "back to top"
a name: "keys"
h2 "API Keys"
p "The API can be used to request new API keys and delete API keys, but cannot be used to look up API keys, or perform any other actions with API keys."
a class: ".top", href: "#top", "back to top"
a name: "new-key"
h3 "/key/new"
p "Send an empty request. Receive the following:"
blockquote ->
code '{ "success": true, "api_key": { "id": 4, "user_id": 1, "key": "", "created_at": "2018-04-25 06:05:53", "updated_at": "2018-04-25 06:05:53" } }'
p "NOTE: For some reason, API key IDs are not being returned with API keys currently."
a class: ".top", href: "#top", "back to top"
a name: "delete-key"
h3 "/key/delete"
p ->
text "Send a POST request with "
code "id"
text " or "
code "key"
text " defined to delete an API key. Note: You can delete the API key you are currently using with this endpoint, so be careful!"
p ->
text "Returns just the "
code '{ "success": true }'
text " JSON if successful."
a class: ".top", href: "#top", "back to top"
a name: "errors"
h2 "Errors"
p "In addition to an array of errors (usually only consisting of one error message), the HTTP status returned will indicate errors:"
ul ->
li "400: Bad Request. This means something on the client-side did not call the API correctly."
li "404: Not Found. This means the requested item doesn't exist."
li "500: Internal Server Error. Something went wrong with the server while processing your request."
li ->
text "501: Not Implemented. This error should only exist for the next few hours/days as I finish implementing "
code "/random"
text ", the only part of the API not already implemented."
p "Right now, please report any 500 errors you encounter. In the future, these will be logged automatically."
a class: ".top", href: "#top", "back to top"
a name: "rate-limit"
h2 "Rate Limiting"
p "At this time there is no rate limiting. This will be developed when needed, and the API documentation updated to reflect that, with at least 2 months' warning."
a class: ".top", href: "#top", "back to top"
a name: "changes"
h2 "Changes"
-- NOTE id stuff removed because never worked
-- NOTE fixed large bug with several actions -> get, do, undo
p "I intend to keep support for v1 of the API indefinitely. If new features require backwards-incompatible API changes, those will be released under a new version of the API, and v1 will remain accessible for at least 6 months before switching."
p "All new features that do not require modifications to existing API calls will be added to v1 as they are introduced. The next version of the API will only exist if backwards-incompatible changes are introduced."
a class: ".top", href: "#top", "back to top"
a name: "next"
h2 "Coming Next"
p "Until I implement an a tracking system for features/bugs, here is a brief list of features to be added 'soon', and a few known bugs:"
ul ->
li ->
text "Implementing "
code "/random"
text " endpoint."
li ->
code "/edit"
text " endpoint for modifying the "
code "content"
text " of a task. The web interface will also be updated to utilize this."
li ->
code "/search"
text " endpoint. The web interface will also be updated to utilize this."
li "Lists (including the ability to have lists of lists). The API and web interface will receive several updates for this."
li ->
code "/duplicate"
text " endpoint for duplicating a task or list (with optional inclusion of any sub-tasks/sub-lists). The web interface will be updated to utilize this."
li "CLI program for interacting with the API."
li ->
span class: "error", "BUG"
text ": IDs are not returned with requests to "
code "/key/new"
text " endpoint."
li "Twitter integration."
li "Data export. (Note: Initially will be a large JSON dump, but you can contact me if you have special needs for data export and I will develop these upon request.)"
p "And this is a list of ideas that may or may not be coming a bit later on, still being thought about:"
ul ->
li "Email integration."
li "Reminders."
li "Recurring tasks."
li "Shared tasks."
li "Customization of web interface. (e.g. select between current interface and a kanban-style board)"
li "Reordering tasks/lists. (This one requires some research on my part of how to implement this efficiently.)"
li "Tagging system (for tasks/lists)."
li "Due dates/times."
li "Webhooks."
li "OAuth2 support."
li "Import from other todo/task management software."
p "Finally, this is a list of a few site-related things I need to get set up:"
ul ->
li "A homepage for non-users showing features / enticing sign-up. Of course. :P"
li "A dynamically updated page showing project status, both in terms of budget (income/expenses) and features/bugs. (This will also allow users to vote for features/bugs to be prioritized.)"
li "A page for accepting payments. At this stage, this is optional and I will be relying purely on people wanting to see this system succeed. In the future, more advanced API features may be behind a subscription model (intended to be $1.50/year)."
a class: ".top", href: "#top", "back to top"
a name: "notes"
h2 "Notes"
p "All routes are technically available by any HTTP verb. However, depending on the HTTP spec for the verb you use, this may cause required data to not be parsed correctly."
p "I would recommend sticking to POST requests, but GET works for sure, and /new might work with anything if the content is specified in the URL." -- TODO clean up format here
p "Do not write your code expecting ONLY the data specified here, as more features are added, more data will be in the task objects returned."
a class: ".top", href: "#top", "back to top"