From 57a5b6a1886c07c45995cc9c3e656baf8657b85e Mon Sep 17 00:00:00 2001 From: Hannah Wolfe Date: Tue, 3 Jun 2014 14:05:25 +0100 Subject: [PATCH] Full pass at inline API Docs closes #2622, ref #2125 --- core/server/api/db.js | 32 ++++++++++++++++++++++- core/server/api/index.js | 24 ++++++++++++++++- core/server/api/mail.js | 44 ++++++++++++++++++++++---------- core/server/api/notifications.js | 29 ++++++++++++++++++--- core/server/api/posts.js | 25 ++++++++++++++++-- core/server/api/settings.js | 7 ++++- core/server/api/slugs.js | 22 ++++++++++------ core/server/api/tags.js | 13 +++++++++- core/server/api/themes.js | 22 ++++++++++++++-- core/server/api/users.js | 28 +++++++++++++++++++- core/server/api/utils.js | 10 ++++++++ 11 files changed, 223 insertions(+), 33 deletions(-) diff --git a/core/server/api/db.js b/core/server/api/db.js index a31440e2217b..55ee7a7d2f73 100644 --- a/core/server/api/db.js +++ b/core/server/api/db.js @@ -1,3 +1,5 @@ +// # DB API +// API for DB operations var dataExport = require('../data/export'), dataImport = require('../data/import'), dataProvider = require('../models'), @@ -11,10 +13,22 @@ var dataExport = require('../data/export'), api = {}, db; -api.notifications = require('./notifications'); api.settings = require('./settings'); +/** + * ## DB API Methods + * + * **See:** [API Methods](index.js.html#api%20methods) + */ db = { + /** + * ### Export Content + * Generate the JSON to export + * + * @public + * @param {{context}} options + * @returns {Promise} Ghost Export JSON format + */ 'exportContent': function (options) { options = options || {}; @@ -29,6 +43,14 @@ db = { return when.reject(new errors.NoPermissionError('You do not have permission to export data. (no rights)')); }); }, + /** + * ### Import Content + * Import posts, tags etc from a JSON blob + * + * @public + * @param {{context}} options + * @returns {Promise} Success + */ 'importContent': function (options) { options = options || {}; var databaseVersion; @@ -108,6 +130,14 @@ db = { return when.reject(new errors.NoPermissionError('You do not have permission to export data. (no rights)')); }); }, + /** + * ### Delete All Content + * Remove all posts and tags + * + * @public + * @param {{context}} options + * @returns {Promise} Success + */ 'deleteAllContent': function (options) { options = options || {}; diff --git a/core/server/api/index.js b/core/server/api/index.js index 8299eafcb4e7..e16736631e7f 100644 --- a/core/server/api/index.js +++ b/core/server/api/index.js @@ -1,5 +1,8 @@ // # Ghost Data API -// Provides access to the data model +// Provides access from anywhere to the Ghost data layer. +// +// Ghost's JSON API is integral to the workings of Ghost, regardless of whether you want to access data internally, +// from a theme, an app, or from an external app, you'll use the Ghost JSON API to do so. var _ = require('lodash'), when = require('when'), @@ -251,3 +254,22 @@ module.exports = { users: users, slugs: slugs }; + +/** + * ## API Methods + * + * Most API methods follow the BREAD pattern, although not all BREAD methods are available for all resources. + * Most API methods have a similar signature, they either take just `options`, or both `object` and `options`. + * For RESTful resources `object` is always a model object of the correct type in the form `name: [{object}]` + * `options` is an object with several named properties, the possibilities are listed for each method. + * + * Read / Edit / Destroy routes expect some sort of identifier (id / slug / key) for which object they are handling + * + * All API methods take a context object as one of the options: + * + * @typedef context + * Context provides information for determining permissions. Usually a user, but sometimes an app, or the internal flag + * @param {Number} user (optional) + * @param {String} app (optional) + * @param {Boolean} internal (optional) + */ diff --git a/core/server/api/mail.js b/core/server/api/mail.js index 3ff6cc706ece..aedc87bb557a 100644 --- a/core/server/api/mail.js +++ b/core/server/api/mail.js @@ -1,33 +1,51 @@ +// # Mail API +// API for sending Mail var when = require("when"), config = require('../config'), errors = require('../errors'), mail; -// ## Mail +/** + * ## Mail API Methods + * + * **See:** [API Methods](index.js.html#api%20methods) + * @typedef Mail + * @param mail + */ mail = { - - // #### Send - // **takes:** a json object representing an email. - send: function (postData) { + /** + * ### Send + * Send an email + * + * @public + * @param {Mail} object details of the email to send + * @returns {Promise} + */ + send: function (object) { var mailer = require('../mail'); - // **returns:** a promise from the mailer with the number of successfully sent emails - return mailer.send(postData.mail[0].message) + // TODO: permissions + return mailer.send(object.mail[0].message) .then(function (data) { - delete postData.mail[0].options; + delete object.mail[0].options; // Sendmail returns extra details we don't need and that don't convert to JSON - delete postData.mail[0].message.transport; - postData.mail[0].status = { + delete object.mail[0].message.transport; + object.mail[0].status = { message: data.message }; - return postData; + return object; }) .otherwise(function (error) { return when.reject(new errors.EmailError(error.message)); }); }, - // #### SendTest - // **takes:** nothing + /** + * ### SendTest + * Send a test email + * + * @public + * @returns {Promise} + */ sendTest: function () { var html = '

Hello there!

' + '

Excellent!' + diff --git a/core/server/api/notifications.js b/core/server/api/notifications.js index 63478103c384..e276741df852 100644 --- a/core/server/api/notifications.js +++ b/core/server/api/notifications.js @@ -1,3 +1,5 @@ +// # Notifications API +// RESTful API for creating notifications var when = require('when'), _ = require('lodash'), errors = require('../errors'), @@ -8,13 +10,29 @@ var when = require('when'), notificationCounter = 0, notifications; -// ## Notifications +/** + * ## Notification API Methods + * + * **See:** [API Methods](index.js.html#api%20methods) + */ notifications = { + /** + * ### Browse + * Fetch all notifications + * @returns {Promise(Notifications)} + */ browse: function browse() { return when({ 'notifications': notificationsStore }); }, + /** + * ### Destroy + * Remove a specific notification + * + * @param {{id (required), context}} options + * @returns {Promise(Notifications)} + */ destroy: function destroy(options) { var notification = _.find(notificationsStore, function (element) { return element.id === parseInt(options.id, 10); @@ -33,10 +51,16 @@ notifications = { notificationsStore = _.reject(notificationsStore, function (element) { return element.id === parseInt(options.id, 10); }); - // **returns:** a promise for the deleted object return when({notifications: [notification]}); }, + /** + * ### DestroyAll + * Clear all notifications, used for tests + * + * @private Not exposed over HTTP + * @returns {Promise} + */ destroyAll: function destroyAll() { notificationsStore = []; notificationCounter = 0; @@ -73,7 +97,6 @@ notifications = { }); notificationsStore.push(notification); - // **returns:** a promise of the new notification object return when({ notifications: [notification]}); } }; diff --git a/core/server/api/posts.js b/core/server/api/posts.js index 0029f886b167..3f31dd13d0c7 100644 --- a/core/server/api/posts.js +++ b/core/server/api/posts.js @@ -1,4 +1,5 @@ // # Posts API +// RESTful API for the Post resource var when = require('when'), _ = require('lodash'), dataProvider = require('../models'), @@ -24,19 +25,31 @@ function prepareInclude(include) { return include; } -// ## API Methods +/** + * ## Posts API Methods + * + * **See:** [API Methods](index.js.html#api%20methods) + */ posts = { /** * ### Browse * Find a paginated set of posts + * + * Will only return published posts unless we have an authenticated user and an alternative status + * parameter. + * + * Will return without static pages unless told otherwise + * + * Can return posts for a particular tag by passing a tag slug in + * + * @public * @param {{context, page, limit, status, staticPages, tag}} options (optional) * @returns {Promise(Posts)} Posts Collection with Meta */ browse: function browse(options) { options = options || {}; - // only published posts if no user is present if (!(options.context && options.context.user)) { options.status = 'published'; } @@ -51,6 +64,8 @@ posts = { /** * ### Read * Find a post, by ID or Slug + * + * @public * @param {{id_or_slug (required), context, status, include, ...}} options * @return {Promise(Post)} Post */ @@ -81,6 +96,8 @@ posts = { /** * ### Edit * Update properties of a post + * + * @public * @param {Post} object Post or specific properties to update * @param {{id (required), context, include,...}} options * @return {Promise(Post)} Edited Post @@ -114,6 +131,8 @@ posts = { /** * ### Add * Create a new post along with any tags + * + * @public * @param {Post} object * @param {{context, include,...}} options * @return {Promise(Post)} Created Post @@ -146,6 +165,8 @@ posts = { /** * ### Destroy * Delete a post, cleans up tag relations, but not unused tags + * + * @public * @param {{id (required), context,...}} options * @return {Promise(Post)} Deleted Post */ diff --git a/core/server/api/settings.js b/core/server/api/settings.js index 1af7ce852609..4ceaf6951c95 100644 --- a/core/server/api/settings.js +++ b/core/server/api/settings.js @@ -1,4 +1,5 @@ // # Settings API +// RESTful API for the Setting resource var _ = require('lodash'), dataProvider = require('../models'), when = require('when'), @@ -209,7 +210,11 @@ canEditAllSettings = function (settingsInfo, options) { return when.all(checks); }; -// ## API Methods +/** + * ## Settings API Methods + * + * **See:** [API Methods](index.js.html#api%20methods) + */ settings = { /** diff --git a/core/server/api/slugs.js b/core/server/api/slugs.js index 7c5b40e7938f..092a6e07c329 100644 --- a/core/server/api/slugs.js +++ b/core/server/api/slugs.js @@ -1,26 +1,32 @@ +// # Slug API +// RESTful API for the Slug resource var canThis = require('../permissions').canThis, dataProvider = require('../models'), errors = require('../errors'), when = require('when'), slugs, - // `allowedTypes` is used to define allowed slug types and map them against it's model class counterpart + // `allowedTypes` is used to define allowed slug types and map them against its model class counterpart allowedTypes = { post: dataProvider.Post, tag: dataProvider.Tag }; /** - * ## Generate Slug - * Create a unique slug for a given post title - * @param {{type (required), context}} options - * @param {{title (required), transacting}} options - * @returns {Promise(String)} Unique string + * ## Slugs API Methods + * + * **See:** [API Methods](index.js.html#api%20methods) */ slugs = { - // #### Generate slug - // **takes:** a string to generate the slug from + /** + * ## Generate Slug + * Create a unique slug for a given post title + * TODO: make it generic for all objects: post, tag, user + * + * @param {{type (required), title (required), context, transacting}} options + * @returns {Promise(String)} Unique string + */ generate: function (options) { options = options || {}; diff --git a/core/server/api/tags.js b/core/server/api/tags.js index f56b205a5107..184c701c6f62 100644 --- a/core/server/api/tags.js +++ b/core/server/api/tags.js @@ -1,8 +1,19 @@ +// # Tag API +// RESTful API for the Tag resource var dataProvider = require('../models'), tags; - +/** + * ## Tags API Methods + * + * **See:** [API Methods](index.js.html#api%20methods) + */ tags = { + /** + * ### Browse + * @param {{context}} options + * @returns {Promise(Tags)} + */ browse: function browse(options) { return dataProvider.Tag.findAll(options).then(function (result) { return { tags: result.toJSON() }; diff --git a/core/server/api/themes.js b/core/server/api/themes.js index 6df7c629f498..5f7b472f8a91 100644 --- a/core/server/api/themes.js +++ b/core/server/api/themes.js @@ -1,3 +1,5 @@ +// # Themes API +// RESTful API for Themes var when = require('when'), _ = require('lodash'), canThis = require('../permissions').canThis, @@ -7,9 +9,18 @@ var when = require('when'), when = require('when'), themes; -// ## Themes +/** + * ## Themes API Methods + * + * **See:** [API Methods](index.js.html#api%20methods) + */ themes = { - + /** + * ### Browse + * Get a list of all the available themes + * @param {{context}} options + * @returns {Promise(Themes)} + */ browse: function browse(options) { options = options || {}; @@ -50,6 +61,13 @@ themes = { }); }, + /** + * ### Edit + * Change the active theme + * @param {Theme} object + * @param {{context}} options + * @returns {Promise(Theme)} + */ edit: function edit(object, options) { var themeName; diff --git a/core/server/api/users.js b/core/server/api/users.js index 79dcfd622fa5..64c884445df5 100644 --- a/core/server/api/users.js +++ b/core/server/api/users.js @@ -1,3 +1,5 @@ +// # Users API +// RESTful API for the User resource var when = require('when'), _ = require('lodash'), dataProvider = require('../models'), @@ -10,12 +12,18 @@ var when = require('when'), ONE_DAY = 86400000, users; + +/** + * ## Posts API Methods + * + * **See:** [API Methods](index.js.html#api%20methods) + */ users = { /** * ## Browse * Fetch all users - * @param {object} options (optional) + * @param {{context}} options (optional) * @returns {Promise(Users)} Users Collection */ browse: function browse(options) { @@ -29,6 +37,11 @@ users = { }); }, + /** + * ### Read + * @param {{id, context}} options + * @returns {Promise(User)} User + */ read: function read(options) { var attrs = ['id'], data = _.pick(options, attrs); @@ -48,6 +61,12 @@ users = { }); }, + /** + * ### Edit + * @param {User} object the user details to edit + * @param {{id, context}} options + * @returns {Promise(User)} + */ edit: function edit(object, options) { if (options.id === 'me' && options.context && options.context.user) { options.id = options.context.user; @@ -68,6 +87,12 @@ users = { }); }, + /** + * ### Add + * @param {User} object the user to create + * @param {{context}} options + * @returns {Promise(User}} Newly created user + */ add: function add(object, options) { options = options || {}; @@ -89,6 +114,7 @@ users = { }); }, + // TODO complete documentation as part of #2822 register: function register(object) { // TODO: if we want to prevent users from being created with the signup form this is the right place to do it return users.add(object, {context: {internal: true}}); diff --git a/core/server/api/utils.js b/core/server/api/utils.js index a8fc211b7874..ea58a97c0b05 100644 --- a/core/server/api/utils.js +++ b/core/server/api/utils.js @@ -1,8 +1,18 @@ +// # API Utils +// Shared helpers for working with the API var when = require('when'), _ = require('lodash'), utils; utils = { + /** + * ### Check Object + * Check an object passed to the API is in the correct format + * + * @param {Object} object + * @param {String} docName + * @returns {Promise(Object)} resolves to the original object if it checks out + */ checkObject: function (object, docName) { if (_.isEmpty(object) || _.isEmpty(object[docName]) || _.isEmpty(object[docName][0])) { return when.reject({type: 'BadRequest', message: 'No root key (\'' + docName + '\') provided.'});