API Docs for:
Show:

File: src/loopback-promised.coffee


LoopbackClient        = require('./loopback-client')
LoopbackUserClient    = require('./loopback-user-client')
LoopbackRelatedClient = require('./loopback-related-client')
PushManager           = require('./push-manager')

DebugLogger = require('./util/debug-logger')

fetch = require('fetch-ponyfill')(
    Promise: Promise
    XMLHttpRequest: if typeof XMLHttpRequest is 'function' then XMLHttpRequest else undefined
)

qs = require 'qs'

timeoutLimit = (msec, promise) ->
    new Promise (resolve, reject) ->
        setTimeout ->
            reject(new Error("timeout of #{msec}ms exceeded"))
        , msec
        promise.then(resolve, reject)

###*
LoopbackPromised

@class LoopbackPromised
@module loopback-promised
###

class LoopbackPromised

    ###*
    creates an instance

    @static
    @method createInstance
    @param {LoopbackPromised|Object} lbPromisedInfo
    @param {String} lbPromisedInfo.baseURL base URL of Loopback
    @param {Object} [lbPromisedInfo.logger] logger with info(), warn(), error(), trace().
    @param {String} [lbPromisedInfo.version] version of Loopback API to access
    @return {LoopbackPromised}
    ###
    @createInstance: (lbPromisedInfo = {}) ->

        new LoopbackPromised(
            lbPromisedInfo.baseURL
            lbPromisedInfo.logger
            lbPromisedInfo.version
        )

    ###*

    @constructor
    @private
    ###
    constructor: (
        @baseURL
        @logger
        @version
    ) ->


    ###*
    sends request to Loopback

    @method request
    @param {String} pluralModelName
    @param {String} path
    @param {Object} params request parameters
    @param {String} http_method {GET|POST|PUT|DELETE|HEAD}
    @param {LoopbackClient|Object} [clientInfo]
    @param {String}  [clientInfo.accessToken] Access Token
    @param {Boolean} [clientInfo.debug] shows debug log if true
    @return {Promise(Object)}
    ###
    request: (pluralModelName, path, params = {}, http_method, clientInfo = {}) ->

        endpoint = "/#{pluralModelName}#{path}"

        @constructor.requestStatic(endpoint, params, http_method, clientInfo, @)




    ###*
    calls rest api directly

    @static
    @method requestStatic
    @param {String} endpoint
    @param {Object} [params]
    @param {String} http_method {GET|POST|PUT|DELETE|HEAD}
    @param {LoopbackClient|Object} [clientInfo]
    @param {String}  [clientInfo.accessToken] Access Token
    @param {Boolean} [clientInfo.debug] shows debug log if true
    @param {LoopbackPromised|Object}  lbPromisedInfo
    @param {String} lbPromisedInfo.baseURL base URL of Loopback
    @param {String} [lbPromisedInfo.version] version of Loopback API to access
    @param {Object} [lbPromisedInfo.logger] logger with info(), warn(), error(), trace().

    @return {Promise(Object)}
    ###
    @requestStatic: (endpoint, params = {}, http_method, clientInfo = {}, lbPromisedInfo) ->

        { accessToken, debug, timeout } = clientInfo

        { baseURL, logger, version } = lbPromisedInfo

        debug = @isDebugMode debug

        if debug
            debugLogger = new DebugLogger(endpoint, params, http_method, clientInfo, lbPromisedInfo)


        unless baseURL
            return Promise.reject('baseURL is required.')

        if baseURL.slice(0, 4) isnt 'http'
            baseURL = 'http://' + baseURL


        if debug
            debugLogger.showRequestInfo()

        url = if version?
            baseURL + '/' + version + endpoint
        else
            baseURL + endpoint

        fetchParams =
            method: http_method
            headers: {}
        fetchParams.headers.Authorization = accessToken if accessToken

        if http_method is 'GET'
            flattenParams = {}
            for k, v of params
                continue if typeof v is 'function'
                flattenParams[k] = if typeof v is 'object' then JSON.stringify(v) else v

            queryString = qs.stringify(flattenParams)
            url += '?' + queryString if queryString

        else if Object.keys(params).length
            fetchParams.body = JSON.stringify(params)
            fetchParams.headers['Content-Type'] = 'application/json'

        responseStatus = null

        fetched = fetch(url, fetchParams).then (response) ->
            responseStatus = response.status
            if responseStatus is 204 # No Contents
                return '{}'
            else
                return response.text()

        , (err) ->
            if debug
                debugLogger.showErrorInfo(err)
            throw err

        .then (text) ->
            try
                responseBody = JSON.parse(text)
            catch e
                responseBody = error: text

            if debug
                debugLogger.showResponseInfo(responseBody, responseStatus)

            if responseBody.error

                if typeof responseBody.error is 'object'
                    err = new Error()
                    err[k] = v for k, v of responseBody.error
                    err.isLoopbackResponseError = true
                else
                    err = new Error(responseBody.error)
                    # err.isLoopbackResponseError = true
                throw err
            else
                return responseBody

        return if timeout? then timeoutLimit(timeout, fetched) else fetched

    ###*
    creates client for Loopback

    @method createClient
    @param {String} pluralModelName
    @param {Object}  [options]
    @param {Object}  [options.belongsTo] key: pluralModelName (the "one" side of one-to-many relation), value: id
    @param {Boolean} [options.isUserModel] true if user model
    @param {String}  [options.accessToken] Access Token
    @param {Boolean} [options.debug] shows debug log if true
    @return {LoopbackClient}
    ###
    createClient: (pluralModelName, options = {}) ->

        if options.belongsTo
            pluralModelNameOne = Object.keys(options.belongsTo)[0]
            id = options.belongsTo[pluralModelNameOne]

            return @createRelatedClient
                one         : pluralModelNameOne
                many        : pluralModelName
                id          : id
                timeout     : options.timeout
                accessToken : options.accessToken
                debug       : options.debug

        else if options.isUserModel
            return @createUserClient(pluralModelName, options)

        new LoopbackClient(
            @
            pluralModelName
            options.accessToken
            options.timeout
            options.debug
        )

    ###*
    creates user client for Loopback

    @method createUserClient
    @param {String} pluralModelName
    @param {Object} [clientInfo]
    @param {String}  [clientInfo.accessToken] Access Token
    @param {Boolean} [clientInfo.debug] shows debug log if true
    @return {LoopbackClient}
    ###
    createUserClient: (pluralModelName, clientInfo = {}) ->
        new LoopbackUserClient(
            @
            pluralModelName
            clientInfo.accessToken
            clientInfo.timeout
            clientInfo.debug
        )


    ###*
    creates related client (one-to-many relation)

    @method createRelatedClient
    @param {Object} options
    @param {String} options.one the "one" side plural model of one-to-many relationship
    @param {String} options.many the "many" side plural model of one-to-many relationship
    @param {any} options.id the id of the "one" model
    @param {String}  [options.accessToken] Access Token
    @param {Boolean} [options.debug] shows debug log if true
    @return {LoopbackClient}
    ###
    createRelatedClient: (options) ->
        new LoopbackRelatedClient(
            @
            options.one
            options.many
            options.id
            options.accessToken
            options.timeout
            options.debug
        )

    ###*
    creates push manager

    @method createPushManager
    @public
    @param {Object} [clientInfo]
    @param {String}  [clientInfo.accessToken] Access Token
    @param {Boolean} [clientInfo.debug] shows debug log if true
    @return {PushManager}
    ###
    createPushManager: (clientInfo = {}) ->
        new PushManager(
            @
            clientInfo.accessToken
            clientInfo.debug
        )

    ###*
    check environment variable concerning debug

    @private
    @static
    @method isDebugMode
    @param {Boolean} debug
    @return {Boolean} shows debug log or not
    ###
    @isDebugMode: (debug) ->

        return debug or !!process?.env?.LBP_DEBUG


LoopbackPromised.Promise               = Promise
LoopbackPromised.LoopbackClient        = LoopbackClient
LoopbackPromised.LoopbackUserClient    = LoopbackUserClient
LoopbackPromised.LoopbackRelatedClient = LoopbackRelatedClient

module.exports = LoopbackPromised