微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何包装自定义 json:api 客户端并使调用流畅和异步非 ES6

如何解决如何包装自定义 json:api 客户端并使调用流畅和异步非 ES6

我想为遵循 json:api 规范的 Restful API 创建自定义客户端。所以,我创建了这个支持异步的简单客户端:

MyTools.Api = (function () {
    "use strict";
    //#region Private
    function ajax(url,method,data) {
        return new Promise(function (resolve,reject) {
            let request = new XMLHttpRequest();
            request.responseType = 'json';
            //Open first,before setting the request headers.
            request.open(method,url,true);
            request.setRequestHeader('Authorization','Bearer ' + window.headerToken)
            request.onreadystatechange = function () {
                if (request.readyState === XMLHttpRequest.DONE) {
                    if (request.status === 200) {
                        resolve(request.response);
                    } else {
                        reject(Error(request.status));
                    }
                }
            };
            request.onerror = function () {
                reject(Error("Network Error"));
            };
            request.open(method,true);
            request.send(data);
        });
    }

    //#endregion
    //#region Public
    return function (url,data) {
        url = window.apiBasePath + url;
        return ajax(url,data);
    };
    //#endregion
})(MyTools.Api || {});

我将令牌从后端 (.net) 传递到名为 headerToken 的窗口全局变量。与基本路径(apiBasePath)相同。 现在,我可以像这样调用这个客户端

CTools.Api("/dashboard/users/","GET").then(function (result) {
console.log(result);
});

我的目标是创建一种更流畅的方式来使用 api。例如,我想调用类似的东西:

mytools.api.dashboard.users.get().then(function (result) {
    console.log(result);
    });

mytools.api.dashboard.users.get(fliteroptions).then(function (result) {
    console.log(result);
    });

如果有另一个模块可以使用

mytools.api.basket.items.get(fliteroptions).then(function (result) {
    onsole.log(result);
    });

仪表板和购物篮将具有不同的网址。客户端和 url 构建都将在 mytools 命名空间内创建。此外,变量 headerToken 和 apiBasePath 将在休息调用后在 mytools 构造函数中分配。

在这种情况下使用什么设计模式? 请记住,我想要一个非 ES6 的解决方案。

解决方法

基本上只有两种方法可以做你想做的事情;每个路由(dashboardbasket 等)都是具有 fetch 行为等的完整 api 对象,或者 get() 等中的 dashboard 方法映射回api

像这样:

class Route {
    constructor(url,api) {
        this.url = url;
        this.api = api;
    }
    
    get(filterOptions) {
        return this.api.get(this.url,filterOptions)
    }
    
    post(filterOptions) {
        return this.api.post(this.url,filterOptions);
    }
}

class Api {
    constructor(basePath) {
        this.basePath = basePath;
    }
    
    get(route,filterOptions) {
        // filterOptions can be null here
        return fetch(`${this.basePath}/${route}`)
            .then(data => data.json())
    }
    
    post(route,filterOptions) {
        // filterOptions can be null here
        ...
    }
    
    ...
}

mytools.api = new Api();
mytools.api.dashboard = new Route('dashboard',mytools.api);
mytools.api.basket = new Route('basket',mytools.api);
...

您的 Route 类是一个简单的类,其中包含 url 和其他任何内容,以及实际执行提取操作的 api

Api 包装您的 fetch 并处理任何传递的 filterOptions

创建 Api 时,您也创建了所有路由。

缺点是您需要事先了解所有路线。

要更动态地执行此操作,您可以查看Proxyhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy

在这里,您可以实现一个每次访问您的对象时都会调用的函数:

var handler = {
    get: function(target,name) {
        return "Hello," + name;
    }
};
var proxy = new Proxy({},handler);

console.log(proxy.world); // output: Hello,world

您应该能够挂钩它,以便 get 方法返回 Api 对象,然后您可以直接调用它

针对 ES5 进行编辑

我已经有一段时间没有编写纯 ES5 了,但是例如转换 Route 类应该看起来像这样:

function Route(url,api) {
    this.url = url;
    this.api = api;
}

Route.prototype.get = function(filterOptions) {
    return this.api.get(this.url,filterOptions)
}

Route.prototype.post = function(filterOptions) {
    return this.api.post(this.url,filterOptions)
}

创建对象应该保持不变 - new Route(url,api)

我不确定 fetch 是否是 ES5 - 您需要查看代码将在哪里运行以查看它是否受支持。与承诺同上;您要么需要使用 Bluebird 之类的库,要么使用回调。

有关课程的更多信息:https://medium.com/@apalshah/javascript-class-difference-between-es5-and-es6-classes-a37b6c90c7f8

修改动态网址

如果我没理解错的话,您是从 REST 调用中获取 URL。

假设这个调用的返回类似于:

{
    "dashboard": {
        "url": "dashboard/","token": "..."
    },"basket": {
        "url": "basket/",...
}

此时,您现在可以通过并创建您的 api:

mytools.api = new Api();
mytools.api.dashboard = new Route(jsonObj.dashboard.url,mytools.api);
mytools.api.basket = new Route(jsonObj.basket.url,mytools.api);
...

您还可以传入 token 或 REST JSON 对象中的任何其他内容。不过,这确实意味着一些事情:

  1. 在进行初始 REST 调用之前,您无法访问 mytools.api.dashboard 等 - 它不会指向任何内容
  2. 您需要事先了解您的路线 - 例如在这里,我们知道我们在 mytools.api.dashboard 变量后面有一个路由

关于第 2 点,您不能真正拥有真正动态的 url(即您可以将 "profile" 添加到 REST JSON 而无需在您的代码库中添加相应的 mytools.api.profile 调用)而无需重新思考你如何处理事情。您在这里所做的(使 API 更易于使用)是预编译 - 就像在编写代码时一样。但是,直到运行时才知道您的路线

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?