【问题标题】:Accessing complex REST resources with Ext JS使用 Ext JS 访问复杂的 REST 资源
【发布时间】:2013-07-25 03:12:30
【问题描述】:

我正在访问一个 REST 服务,它公开了这两个资源,一个父资源和一个子资源:

/users
/users/{userId}/account

所以资源“帐户”没有嵌套在资源“用户”中,它必须由第二个请求访问。有此类 REST API 的示例,例如here

我使用这些模型将用户及其帐户映射到 Ext Js 4 数据模型:

用户

Ext.define("MyApp.model.User", {
    extend: "Ext.data.Model",
    fields: [ { name: "id", type: "string" }],
    associations: [{
            model: "MyApp.model.Account",
            name: "account",
            type: "hasOne",
            reader: "json",
            getterName: "getAccount",
            setterName: "setAccount", 
            foreignKey: "accountId"
        }
    ],
    proxy: {
        type: "rest",
        url: "/rest/users",
        reader: {
            type: "json",
            totalProperty: "total",
            root: "users"
        }
    }
});

帐户

Ext.define("MyApp.model.Account", {
    extend: "Ext.data.Model",
    fields: [ { name: "id", type: "string" }],
    belongsTo: "MyApp.model.User",
    proxy: {
        type: "rest",
        reader: { type: "json"}
    }
});

帐户代理没有 url(我希望这将基于父用户模型创建)。当我调用 user.getAccount() 时出现异常,因为代理缺少 url。

问题有没有办法设置模型,让 Ext Js 访问 /users/{userId}/account 而不用每个父 userId 手动更新帐户代理 url?

【问题讨论】:

  • Account模型真的有自己的id吗?如果帐户和用户之间存在一对一的关系,这似乎没有必要。
  • 对了,不需要账号id。

标签: rest extjs extjs4 parent-child


【解决方案1】:

你不会从现有的 Ext 类中得到你想要的东西,你将不得不变得有点肮脏......

据我了解,您需要用户的 id 来加载其帐户,而不是帐户记录本身的 id。因此,我会配置关联以反映这一点:

associations: [{
    model: "MyApp.model.Account",
    name: "account",
    type: "hasOne",
    reader: "json",
    getterName: "getAccount",
    setterName: "setAccount",
    // foreignKey: "accountId"
    foreignKey: 'id'
}],

这里最大的优势是当代理被要求为请求构建 url 时,用户 ID 将可供代理使用。

现在,为了使用您需要的格式构建 url,我们必须替换代理的 buildUrl 方法。而且,正如您已经发现的那样,您首先需要一个 url 才能访问此方法。

所以,下面是我将如何配置帐户代理:

proxy: {
    type: "rest",
    reader: {type: "json"},

    // Give it an URL to avoid the error
    url: '/rest/users/{}/account',

    // Replace the buildUrl method
    buildUrl: function(request) {
        var me        = this,
            operation = request.operation,
            records   = operation.records || [],
            record    = records[0],
            url       = me.getUrl(request),
            id        = record ? record.getId() : operation.id;

        // Here's the part honoring your URL format
        if (me.isValidId(id)) {
            url = url.replace('{}', id);
        } else {
            throw new Error('A valid id is required');
        }

        // That's enough, but we lose the cache buster param (see bellow)
        return url;

        // If we want the cache buster param (_dc=...) to be added,
        // we must call the superclass, which will read the url from
        // the request.
        request.url = url;
        return Ext.data.proxy.Rest.superclass.buildUrl.apply(this, arguments);
    }
}

此时,我们在表单的 url 上得到了代理触发请求:

rest/users/45/account?id=45

这只是装饰性的,但那个 id 查询参数让我很烦,所以我还将代理的 buildRequest 方法替换为以下方法:

buildRequest: function(operation, callback, scope) {
    var me = this,
        params = operation.params = Ext.apply({}, operation.params, me.extraParams),
        request;

    Ext.applyIf(params, me.getParams(operation));

    // if (operation.id !== undefined && params[me.idParam] === undefined) {
    //     params[me.idParam] = operation.id;
    // }

    request = new Ext.data.Request({
        params   : params,
        action   : operation.action,
        records  : operation.records,
        operation: operation,
        url      : operation.url,
        proxy: me
    });

    request.url = me.buildUrl(request);

    operation.request = request;

    return request;
}

而且,你在这里......虽然它会起作用,但我真的不建议在代理的配置中以这种方式覆盖方法。在现实生活中,您应该从 Rest 扩展您自己的代理类,特别是如果您需要配置许多这样的代理......但我希望我已经为您提供了开始使用所需的所有要素!

【讨论】:

  • 很抱歉我只能接受一次这个答案:-) 你的第一句话对我来说是最重要的,也许我应该考虑改变其余的api。我测试了您发布的解决方法,它适用于我,我真的不需要“手动更新帐户代理 url”。干得好!
  • 我必须使用operation.filters[0].value 来获取外键。
【解决方案2】:

我遇到了同样的问题,我发现 rixo 的回答绝对令人惊叹。因此我自己采用了它,但后来我做了一些修改,所以这是我目前正在使用的代码。 优点是它允许您完全按照自己的喜好设置服务 URL 的格式,甚至可以连接多个参数。

// Replace the buildUrl method
                buildUrl: function (request) {
                    var me = this,
                        url = me.getUrl(request);
                    var added = [];
                    for(var p in request.params)
                    {
                        if (url.indexOf('{' + p + '}') >= 0) {
                            url = url.replace('{' + p + '}', request.params[p]);
                            added.push(p);
                        }
                    }
                    for(var a in added)
                    {
                        delete request.params[added[a]];
                    }

                    // That's enough, but we lose the cache buster param (see bellow)
                    return url;

                    // If we want the cache buster param (_dc=...) to be added,
                    // we must call the superclass, which will read the url from
                    // the request.
                    request.url = url;
                    return Ext.data.proxy.Rest.superclass.buildUrl.apply(this, arguments);
                }

这样你就可以使用像“/service/{param1}/{param2}/?abc={param3}”这样的url,给定一个像

这样的“request.params”对象

{ “参数 1”:“值 1”, “参数 2”:“值 2”, “参数 3”:“值 3” }

而且还有不需要重写“buildRequest”方法,因为这里使用的任何参数都从“params”对象中删除,并且以后不会连接到查询字符串。

希望对你有帮助,欢迎评论!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-30
    • 2018-10-11
    • 2017-12-19
    • 2011-10-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多