UNPKG

realworld-api

Version:

RealWorld library for open API calls using JavaScript

565 lines (528 loc) 16.1 kB
var request = require('nets') var xtend = require('xtend') module.exports.base = 'https://conduit.productionready.io/api' module.exports = RealWorld /** * Realworld library for open API calls using JavaScript * @param {Object} [opts] options for configuring API * @param {string} [opts.token=null] authentication token from RealWorld * @param {string} [opts.apiRoot=https://conduit.productionready.io/api] the url * to Realworld API * @example * var client = new RealWorld() * @example * var client = new RealWorld({ * apiRoot: 'http://localhost:8000/api', * token: 'my-secret-authentication-token' * }) * @see [RealWorld API Spec](https://github.com/gothinkster/realworld/tree/master/api#realworld-api-spec) */ function RealWorld (opts) { if (!(this instanceof RealWorld)) return new RealWorld(opts) if (!opts) opts = {} this.token = opts.token || null this.apiRoot = opts.apiRoot || 'https://conduit.productionready.io/api' } var defaults = { json: true } var limit = function (count, p) { return `limit=${count}&offset=${p ? p * count : 0}` } RealWorld.prototype._useToken = function () { if (this.token) { return xtend(defaults, { headers: { Authorization: `Token ${this.token}` } }) } } var encode = encodeURIComponent RealWorld.prototype._getRequest = function (url, cb) { request( xtend(defaults, this._useToken(), { method: 'GET', url: `${this.apiRoot}${url}` }), cb ) } RealWorld.prototype._postRequest = function (url, body, cb) { request( xtend(defaults, this._useToken(), { method: 'POST', url: `${this.apiRoot}${url}`, body: body }), cb ) } RealWorld.prototype._putRequest = function (url, body, cb) { request( xtend(defaults, this._useToken(), { method: 'PUT', url: `${this.apiRoot}${url}`, body: body }), cb ) } RealWorld.prototype._delRequest = function (url, cb) { request( xtend(defaults, this._useToken(), { method: 'DELETE', url: `${this.apiRoot}${url}` }), cb ) } /** * Log in to the RealWorld API * If successful, the `data` result will be type {User} * @param {Object} opts * @param {string} opts.email email address of user * @param {string} opts.password password of user * @param {RealWorld~requestCallback} cb Callback function * @example * client.login( * { * email: 'mike@example.com', * password: 'secret' * }, * handleResponse * ) */ RealWorld.prototype.login = function (opts, cb) { if (typeof opts === 'function') { cb = opts opts = {} } if (opts.email && opts.password) { this._postRequest( `/users/login`, { user: { email: opts.email, password: opts.password } }, cb ) } else { cb(new Error('Must supply username and password')) } } /** * Register a new user with the RealWorld API * @param {Object} opts * @param {string} opts.username username of registering user * @param {string} opts.email email address of registering user * @param {string} opts.password password of registering user * @param {RealWorld~requestCallback} cb Callback function * @example * client.register( * { * email: 'rick@example.com', * password: 'shhhh', * username: 'rick' * }, * handleResponse * ) */ RealWorld.prototype.register = function (opts, cb) { if (typeof opts === 'function') { cb = opts opts = {} } if (opts.username && opts.email && opts.password) { this._postRequest( `/users`, { user: { username: opts.username, email: opts.email, password: opts.password } }, cb ) } else { cb(new Error('Must supply a username, email, and password')) } } /** * Get the logged in user * @param {RealWorld~requestCallback} cb Callback function * @example * client.getUser(handleResponse) */ RealWorld.prototype.getUser = function (cb) { this._getRequest(`/user`, cb) } /** * Update the logged in user info * @param {Object} opts * @param {string} [opts.email=null] email address of user * @param {string} [opts.username=null] username of user * @param {string} [opts.bio=null] biography of user * @param {string} [opts.password=null] password of user * @param {string} [opts.image=null] url of user image * @param {RealWorld~requestCallback} cb Callback function * @example * client.updateUser( * { * email: 'stacy@example.com', * password: 'hush', * username: 'stace', * bio: 'riot grrl' * }, * handleResponse * ) */ RealWorld.prototype.updateUser = function (opts, cb) { if (typeof opts === 'function') { cb = opts opts = {} } this._putRequest( `/user`, { user: opts }, cb ) } /** * Get profile of a user * @param {string} username username of profile to retrieve * @param {RealWorld~requestCallback} cb Callback function * @example * client.getProfile('rick', handleResponse) */ RealWorld.prototype.getProfile = function (username, cb) { this._getRequest(`/profiles/${username}`, cb) } /** * Follow a user (authentication required) * @param {string} username username to follow * @param {RealWorld~requestCallback} cb Callback function * @example * client.followUser('rick', handleResponse) */ RealWorld.prototype.followUser = function (username, cb) { this._postRequest(`/profiles/${username}/follow`, {}, cb) } /** * Unfollow a user (authentication required) * @param {string} username username to unfollow * @param {RealWorld~requestCallback} cb Callback function * @example * client.unFollowUser('rick', handleResponse) */ RealWorld.prototype.unFollowUser = function (username, cb) { this._delRequest(`/profiles/${username}/follow`, cb) } /** * Request a list of 20 articles sorted by most recent in descending order * @param {Number} [page=0] page specify which page of articles to show * @param {RealWorld~requestCallback} cb Callback function * @example * client.listAllArticles(handleResponse) * @example * client.listAllArticles(2, handleResponse) */ RealWorld.prototype.listAllArticles = function (page, cb) { if (typeof page === 'function') { cb = page page = null } this._getRequest(`/articles?${limit(20, page)}`, cb) } /** * Request a list of 10 articles filtered by a tag and sorted by most recent * in descending order * @param {string} tag tag name to filter by * @param {Number} [page=0] specify which page of articles to show * @param {RealWorld~requestCallback} cb Callback function * @example * client.listArticlesByTag('JavaScript', handleResponse) * @example * client.listArticlesByTag('JavaScript', 2, handleResponse) */ RealWorld.prototype.listArticlesByTag = function (tag, page, cb) { if (typeof page === 'function') { cb = page page = null } this._getRequest(`/articles?tag=${encode(tag)}&${limit(10, page)}`, cb) } /** * Request a list of five articles filtered by author and sorted by most recent * in descending order * @param {string} author username of author to filter by * @param {Number} [page=0] specify which page of articles to show * @param {RealWorld~requestCallback} cb Callback function * @example * client.listArticlesByAuthor('rick', handleResponse) * @example * client.listArticlesByAuthor('rick', 2, handleResponse) */ RealWorld.prototype.listArticlesByAuthor = function (author, page, cb) { if (typeof page === 'function') { cb = page page = null } this._getRequest(`/articles?author=${encode(author)}&${limit(5, page)}`, cb) } /** * Request a list of 20 articles filtered by author favorites and sorted by most * recent in descending order * @param {string} author username of author to filter favorite articles by * @param {Number} [page=0] specify which page of articles to show * @param {RealWorld~requestCallback} cb Callback function * @example * client.listArticlesByAuthorFavorites('rick', handleResponse) * @example * client.listArticlesByAuthorFavorites('rick', 1, handleResponse) */ RealWorld.prototype.listArticlesByAuthorFavorites = function (author, page, cb) { if (typeof page === 'function') { cb = page page = null } this._getRequest( `/articles?favorited=${encode(author)}&${limit(20, page)}`, cb ) } /** * Request a list of ten articles from the currently logged in users feed sorted * by most recent in descending order (authentication required) * @param {Number} [page=0] specify which page of articles to show * @param {RealWorld~requestCallback} cb Callback function * @example * client.feedArticles(handleResponse) * @example * client.feedArticles(2, handleResponse) */ RealWorld.prototype.feedArticles = function (page, cb) { if (typeof page === 'function') { cb = page page = null } this._getRequest(`/articles/feed?${limit(10, page)}`, cb) } /** * Request contents from a single article with the specified slug * @param {string} slug shortname (slug) of article * @param {RealWorld~requestCallback} cb Callback function * @example * client.getArticle('angular-app-dev-e33mn9', handleResponse) */ RealWorld.prototype.getArticle = function (slug, cb) { this._getRequest(`/articles/${slug}`, cb) } /** * Create a new article (authentication required) * @param {Object} opts * @param {string} opts.title title of article * @param {string} opts.description short description of article * @param {string} opts.body content of article * @param {[string]} [opts.tagList=null] array of tags to add to article * @param {RealWorld~requestCallback} cb Callback function * @example * client.createArticle( * { * title: 'My awesome article', * description: 'beep boop', * body: 'wham bam thank you ma\'am', * tagList: ['awesomeness', 'robots'] * }, * handleResponse * ) */ RealWorld.prototype.createArticle = function (opts, cb) { if (typeof opts === 'function') { cb = opts opts = {} } this._postRequest( `/articles`, { article: opts }, cb ) } /** * Update an existing article with given slug and options (authentication * required) * @param {string} slug shortname (slug) of article to update * @param {Object} opts * @param {string} [opts.title=null] title of article * @param {string} [opts.description=null] short description of article * @param {string} [opts.body=null] content of article * @param {RealWorld~requestCallback} cb Callback function * @example * client.updateArticle('my-awesome-article-ew9439', { * title: 'my awesome gender neutral article', * description: 'boop beep', * body: 'wham bam thank you friend' * }) */ RealWorld.prototype.updateArticle = function (slug, opts, cb) { if (typeof opts === 'function') { cb = opts opts = {} } this._putRequest( `/articles/${slug}`, { article: opts }, cb ) } /** * Delete an existing article with the given slug (authentication required) * @param {string} slug shortname (slug) of article to delete * @param {RealWorld~requestCallback} cb Callback function * @example * client.deleteArticle('my-awesome-article-ew9439', handleResponse) */ RealWorld.prototype.deleteArticle = function (slug, cb) { this._delRequest(`/articles/${slug}`, cb) } /** * Add a comment to an article with the given slug (authentication required) * @param {string} slug shortname (slug) of article to add comment to * @param {Object} opts * @param {string} opts.body content of comment * @param {RealWorld~requestCallback} cb Callback function * @example * client.addComment( * 'my-awesome-article-ew9439', * { * body: 'this is a good article' * }, * handleResponse * ) */ RealWorld.prototype.addComment = function (slug, opts, cb) { if (typeof opts === 'function') { cb = opts opts = {} } this._postRequest( `/articles/${slug}/comments`, { comment: opts }, cb ) } /** * Get comments from an article * @param {string} slug shortname (slug) of article from which to retrieve * comments * @param {RealWorld~requestCallback} cb Callback function * @example * client.getComments('angular-app-dev-e33mn9', handleResponse) */ RealWorld.prototype.getComments = function (slug, cb) { this._getRequest(`/articles/${slug}/comments`, cb) } /** * Delete comment from an article (authentication required) * @param {string} slug shortname (slug) of article * @param {string} commentId unique id of comment to delete * @param {RealWorld~requestCallback} cb Callback function * @example * client.deleteComment('angular-app-dev-e33mn9', 'e11dfeg', handleResponse) */ RealWorld.prototype.deleteComment = function (slug, commentId, cb) { this._delRequest(`/articles/${slug}/comments/${commentId}`, cb) } /** * Favorite an article (authentication required) * @param {string} slug shortname (slug) of article to favorite * @param {RealWorld~requestCallback} cb Callback function * @example * client.favoriteArticle('my-awesome-article-ew9439', handleResponse) */ RealWorld.prototype.favoriteArticle = function (slug, cb) { this._postRequest(`/articles/${slug}/favorite`, {}, cb) } /** * Unfavorite an article (authentication required) * @param {string} slug shortname (slug) of article to unfavorite * @param {RealWorld~requestCallback} cb Callback function * @example * client.unFavoriteArticle('my-awesome-article-ew9439', handleResponse) */ RealWorld.prototype.unFavoriteArticle = function (slug, cb) { this._delRequest(`/articles/${slug}/favorite`, cb) } /** * Get a list of tags * @param {RealWorld~requestCallback} cb Callback function * @example * client.getTags(handleResponse) */ RealWorld.prototype.getTags = function (cb) { this._getRequest(`/tags`, cb) } /** * Set the authentication token * @param {string} _token authentication token to set * @example * client.setToken('my-secret-authentication-token') */ RealWorld.prototype.setToken = function (_token) { this.token = _token } /** * This callback is displayed as part of the RealWorld class. The error should * be null if the method was able to run. HTTP and API errors are not caught as * errors so that you can catch them yourself. For example, a response code 500 * may return `(null, { res.statusCode: 500, res.statusMessage: 'Internal Server Error' }, null)`. * * API errors are returned with a 422 status code. Errors are included as JSON * in the `data` result and are in the form of * * `{ * "errors":{ * "body": [ * "can't be empty" * ] * } * }` * * where `body` may be any parameter such as `password`, `email`, etc. * * Successful API requests will return JSON data as seen in the * {@link https://github.com/gothinkster/realworld/tree/master/api#realworld-api-spec RealWorld API Spec} * @callback RealWorld~requestCallback * @param {Error} err error if method was unable to run * @param {Object} res response object from server * @param {Object} data data result from the server as JSON * @example * function handleResponse (err, res, data) { * if (err) return console.error(err) * if (res.statusCode === 422 && data.errors) { * Object.keys(data.errors).forEach(function (err) { * var values = data.errors[err] * values.forEach(function (v) { * console.error(`${err} ${v}`) * }) * }) * return * } * if (res.statusCode !== 200) { * return console.log(`${res.statusCode}: ${res.statusMessage}`) * } * return console.log(data) * } * */