使用Ext JS访问复杂的REST资源

Chr*_*oph 14 rest extjs parent-child extjs4

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

/users
/users/{userId}/account
Run Code Online (Sandbox Code Playgroud)

因此资源"帐户"不嵌套在资源"用户"中,它必须由第二个请求访问.这里有REST API的例子,例如这里

我使用这些模型将用户及其帐户映射到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"
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

帐户

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

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

问题:是否有某种方法来设置模型,以便Ext Js将访问/ users/{userId}/account而无需使用每个父userId手动更新帐户代理URL?

rix*_*ixo 26

你不会从库存Ext类中获得你想要的东西,你将不得不变得有点脏......

根据我的理解,您需要用户的ID加载其帐户,而不是帐户记录本身的ID.所以,我会配置关联来反映:

associations: [{
    model: "MyApp.model.Account",
    name: "account",
    type: "hasOne",
    reader: "json",
    getterName: "getAccount",
    setterName: "setAccount",
    // foreignKey: "accountId"
    foreignKey: 'id'
}],
Run Code Online (Sandbox Code Playgroud)

这里的一大优势是,当要求用户构建请求的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);
    }
}
Run Code Online (Sandbox Code Playgroud)

此时,我们最终在表单的URL上发出代理触发请求:

rest/users/45/account?id=45
Run Code Online (Sandbox Code Playgroud)

这只是化妆品,但是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;
}
Run Code Online (Sandbox Code Playgroud)

并且,在这里......虽然它可行,但我并不真的建议在代理的配置中以这种方式覆盖方法.在现实生活中,你应该从Rest中扩展你自己的代理类,特别是如果你需要配置许多这样的代理......但我希望我给你开始所需的所有成分!


Leo*_*ina 5

我有同样的问题,我发现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);
                }
Run Code Online (Sandbox Code Playgroud)

这样你可以使用像" / service/{param1}/{param2} /?abc = {param3} " 这样的网址给出"request.params"这样的对象

{"param1":"value1","param2":"value2","param3":"value3"}

并且也不需要覆盖"buildRequest"方法,因为此处使用的任何参数都将从"params"对象中删除,并且以后不会与查询字符串连接.

我希望这有帮助,欢迎任何评论!