#

API Docs for: v3.8.1
Show: Inherited Protected Private Deprecated

# File: addon/-private/adapters/build-url-mixin.js

    import { camelize } from '@ember/string';
    import Mixin from '@ember/object/mixin';
    import { get } from '@ember/object';
    import { pluralize } from 'ember-inflector';

    /**

      WARNING: This interface is likely to change in order to accommodate [RFC: Ember Data url templates](https://github.com/emberjs/rfcs/pull/4)

      ## Using BuildURLMixin

      To use URL building, include the mixin when extending an adapter, and call `buildURL` where needed.
      The default behaviour is designed for RESTAdapter.

      ### Example

      ```javascript
      export default DS.Adapter.extend(BuildURLMixin, {
        findRecord: function(store, type, id, snapshot) {
          var url = this.buildURL(type.modelName, id, snapshot, 'findRecord');
          return this.ajax(url, 'GET');
        }
      });
      ```

      ### Attributes

      The `host` and `namespace` attributes will be used if defined, and are optional.

      @class BuildURLMixin
      @namespace DS
    */
    export default Mixin.create({
      /**
        Builds a URL for a given type and optional ID.

        By default, it pluralizes the type's name (for example, 'post'
        becomes 'posts' and 'person' becomes 'people'). To override the
        pluralization see [pathForType](#method_pathForType).

        If an ID is specified, it adds the ID to the path generated
        for the type, separated by a `/`.

        When called by `RESTAdapter.findMany()` the `id` and `snapshot` parameters
        will be arrays of ids and snapshots.

        @method buildURL
        @param {String} modelName
        @param {(String|Array|Object)} id single id or array of ids or query
        @param {(DS.Snapshot|Array)} snapshot single snapshot or array of snapshots
        @param {String} requestType
        @param {Object} query object of query parameters to send for query requests.
        @return {String} url
      */
      buildURL(modelName, id, snapshot, requestType, query) {
        switch (requestType) {
          case 'findRecord':
            return this.urlForFindRecord(id, modelName, snapshot);
          case 'findAll':
            return this.urlForFindAll(modelName, snapshot);
          case 'query':
            return this.urlForQuery(query, modelName);
          case 'queryRecord':
            return this.urlForQueryRecord(query, modelName);
          case 'findMany':
            return this.urlForFindMany(id, modelName, snapshot);
          case 'findHasMany':
            return this.urlForFindHasMany(id, modelName, snapshot);
          case 'findBelongsTo':
            return this.urlForFindBelongsTo(id, modelName, snapshot);
          case 'createRecord':
            return this.urlForCreateRecord(modelName, snapshot);
          case 'updateRecord':
            return this.urlForUpdateRecord(id, modelName, snapshot);
          case 'deleteRecord':
            return this.urlForDeleteRecord(id, modelName, snapshot);
          default:
            return this._buildURL(modelName, id);
        }
      },

      /**
        @method _buildURL
        @private
        @param {String} modelName
        @param {String} id
        @return {String} url
      */
      _buildURL(modelName, id) {
        let path;
        let url = [];
        let host = get(this, 'host');
        let prefix = this.urlPrefix();

        if (modelName) {
          path = this.pathForType(modelName);
          if (path) {
            url.push(path);
          }
        }

        if (id) {
          url.push(encodeURIComponent(id));
        }
        if (prefix) {
          url.unshift(prefix);
        }

        url = url.join('/');
        if (!host && url && url.charAt(0) !== '/') {
          url = '/' + url;
        }

        return url;
      },

      /**
       Builds a URL for a `store.findRecord(type, id)` call.

       Example:

       ```app/adapters/user.js
       import DS from 'ember-data';

       export default DS.JSONAPIAdapter.extend({
         urlForFindRecord(id, modelName, snapshot) {
           let baseUrl = this.buildURL(modelName, id, snapshot);
           return `${baseUrl}/users/${snapshot.adapterOptions.user_id}/playlists/${id}`;
         }
       });
       ```

       @method urlForFindRecord
       @param {String} id
       @param {String} modelName
       @param {DS.Snapshot} snapshot
       @return {String} url

       */
      urlForFindRecord(id, modelName, snapshot) {
        return this._buildURL(modelName, id);
      },

      /**
       Builds a URL for a `store.findAll(type)` call.

       Example:

       ```app/adapters/comment.js
       import DS from 'ember-data';

       export default DS.JSONAPIAdapter.extend({
         urlForFindAll(modelName, snapshot) {
           return 'data/comments.json';
         }
       });
       ```

       @method urlForFindAll
       @param {String} modelName
       @param {DS.SnapshotRecordArray} snapshot
       @return {String} url
       */
      urlForFindAll(modelName, snapshot) {
        return this._buildURL(modelName);
      },

      /**
       Builds a URL for a `store.query(type, query)` call.

       Example:

       ```app/adapters/application.js
       import DS from 'ember-data';

       export default DS.RESTAdapter.extend({
         host: 'https://api.github.com',
         urlForQuery (query, modelName) {
           switch(modelName) {
             case 'repo':
               return `https://api.github.com/orgs/${query.orgId}/repos`;
             default:
               return this._super(...arguments);
           }
         }
       });
       ```

       @method urlForQuery
       @param {Object} query
       @param {String} modelName
       @return {String} url
       */
      urlForQuery(query, modelName) {
        return this._buildURL(modelName);
      },

      /**
       Builds a URL for a `store.queryRecord(type, query)` call.

       Example:

       ```app/adapters/application.js
       import DS from 'ember-data';

       export default DS.RESTAdapter.extend({
         urlForQueryRecord({ slug }, modelName) {
           let baseUrl = this.buildURL();
           return `${baseUrl}/${encodeURIComponent(slug)}`;
         }
       });
       ```

       @method urlForQueryRecord
       @param {Object} query
       @param {String} modelName
       @return {String} url
       */
      urlForQueryRecord(query, modelName) {
        return this._buildURL(modelName);
      },

      /**
       Builds a URL for coalescing multiple `store.findRecord(type, id)`
       records into 1 request when the adapter's `coalesceFindRequests`
       property is `true`.

       Example:

       ```app/adapters/application.js
       import DS from 'ember-data';

       export default DS.RESTAdapter.extend({
         urlForFindMany(ids, modelName) {
           let baseUrl = this.buildURL();
           return `${baseUrl}/coalesce`;
         }
       });
       ```

       @method urlForFindMany
       @param {Array} ids
       @param {String} modelName
       @param {Array} snapshots
       @return {String} url
       */
      urlForFindMany(ids, modelName, snapshots) {
        return this._buildURL(modelName);
      },

      /**
       Builds a URL for fetching an async `hasMany` relationship when a URL
       is not provided by the server.

       Example:

       ```app/adapters/application.js
       import DS from 'ember-data';

       export default DS.JSONAPIAdapter.extend({
         urlForFindHasMany(id, modelName, snapshot) {
           let baseUrl = this.buildURL(modelName, id);
           return `${baseUrl}/relationships`;
         }
       });
       ```

       @method urlForFindHasMany
       @param {String} id
       @param {String} modelName
       @param {DS.Snapshot} snapshot
       @return {String} url
       */
      urlForFindHasMany(id, modelName, snapshot) {
        return this._buildURL(modelName, id);
      },

      /**
       Builds a URL for fetching an async `belongsTo` relationship when a url
       is not provided by the server.

       Example:

       ```app/adapters/application.js
       import DS from 'ember-data';

       export default DS.JSONAPIAdapter.extend({
         urlForFindBelongsTo(id, modelName, snapshot) {
           let baseUrl = this.buildURL(modelName, id);
           return `${baseUrl}/relationships`;
         }
       });
       ```

       @method urlForFindBelongsTo
       @param {String} id
       @param {String} modelName
       @param {DS.Snapshot} snapshot
       @return {String} url
       */
      urlForFindBelongsTo(id, modelName, snapshot) {
        return this._buildURL(modelName, id);
      },

      /**
       Builds a URL for a `record.save()` call when the record was created
       locally using `store.createRecord()`.

       Example:

       ```app/adapters/application.js
       import DS from 'ember-data';

       export default DS.RESTAdapter.extend({
         urlForCreateRecord(modelName, snapshot) {
           return this._super(...arguments) + '/new';
         }
       });
       ```

       @method urlForCreateRecord
       @param {String} modelName
       @param {DS.Snapshot} snapshot
       @return {String} url
       */
      urlForCreateRecord(modelName, snapshot) {
        return this._buildURL(modelName);
      },

      /**
       Builds a URL for a `record.save()` call when the record has been updated locally.

       Example:

       ```app/adapters/application.js
       import DS from 'ember-data';

       export default DS.RESTAdapter.extend({
         urlForUpdateRecord(id, modelName, snapshot) {
           return `/${id}/feed?access_token=${snapshot.adapterOptions.token}`;
         }
       });
       ```

       @method urlForUpdateRecord
       @param {String} id
       @param {String} modelName
       @param {DS.Snapshot} snapshot
       @return {String} url
       */
      urlForUpdateRecord(id, modelName, snapshot) {
        return this._buildURL(modelName, id);
      },

      /**
       Builds a URL for a `record.save()` call when the record has been deleted locally.

       Example:

       ```app/adapters/application.js
       import DS from 'ember-data';

       export default DS.RESTAdapter.extend({
         urlForDeleteRecord(id, modelName, snapshot) {
           return this._super(...arguments) + '/destroy';
         }
       });
       ```

       @method urlForDeleteRecord
       @param {String} id
       @param {String} modelName
       @param {DS.Snapshot} snapshot
       @return {String} url
       */
      urlForDeleteRecord(id, modelName, snapshot) {
        return this._buildURL(modelName, id);
      },

      /**
        @method urlPrefix
        @private
        @param {String} path
        @param {String} parentURL
        @return {String} urlPrefix
      */
      urlPrefix(path, parentURL) {
        let host = get(this, 'host');
        let namespace = get(this, 'namespace');

        if (!host || host === '/') {
          host = '';
        }

        if (path) {
          // Protocol relative url
          if (/^\/\//.test(path) || /http(s)?:\/\//.test(path)) {
            // Do nothing, the full host is already included.
            return path;

            // Absolute path
          } else if (path.charAt(0) === '/') {
            return `${host}${path}`;
            // Relative path
          } else {
            return `${parentURL}/${path}`;
          }
        }

        // No path provided
        let url = [];
        if (host) {
          url.push(host);
        }
        if (namespace) {
          url.push(namespace);
        }
        return url.join('/');
      },

      /**
        Determines the pathname for a given type.

        By default, it pluralizes the type's name (for example,
        'post' becomes 'posts' and 'person' becomes 'people').

        ### Pathname customization

        For example, if you have an object `LineItem` with an
        endpoint of `/line_items/`.

        ```app/adapters/application.js
        import DS from 'ember-data';
        import { decamelize } from '@ember/string';
        import { pluralize } from 'ember-inflector';

        export default DS.RESTAdapter.extend({
          pathForType: function(modelName) {
            var decamelized = decamelize(modelName);
            return pluralize(decamelized);
          }
        });
        ```

        @method pathForType
        @param {String} modelName
        @return {String} path
      **/
      pathForType(modelName) {
        let camelized = camelize(modelName);
        return pluralize(camelized);
      },
    });