【问题标题】:Need insight on how to build javascript fetch API需要了解如何构建 javascript fetch API
【发布时间】:2017-11-15 08:12:36
【问题描述】:

我正在创建一个以 django rest 框架为后端并以响应为前端的 Web 应用程序。我从 create-react-app 生成的反应应用程序。要进行 api 调用,我使用 fetch Api。我在我的 api 调用中看到了一些需要重构的重复。但我知道这里哪种模式更好。

代码如下:

Api.js

let _options = {headers: new Headers({'Content-Type': 'application/json'})}

const _url = {
  'users': '/api/users/',
  'obtain-token': '/api/obtain-token/',
  'verify-token': '/api/verify-token/',
  'refresh-token': '/api/refresh-token/'
}

const _fetch = (request) => {
  return fetch(request)
    .then(res => {
      if ( ! res.ok) {
        let err = {
          'status': res.status,
          'statusText': res.statusText,
          'data': {}
        }
        return res.json().then(
          data => {
            err.data = data
            return Promise.reject(new Error(JSON.stringify(err)))
          },
          () => Promise.reject(new Error(JSON.stringify(err)))
        )
      }

      return res.json()
    })
    .catch(err => {
      return Promise.reject(err)
    })
}

export const obtainToken = (username, password) => {
  const credential = {username, password}

  let options = _options
  options.method = 'POST'
  options.body = JSON.stringify(credential)

  const request = new Request(_url['obtain-token'], options)

  return _fetch(request)
}

export const verifyToken = (token) => {
  let options = _options
  options.method = 'POST'
  options.body = JSON.stringify({token})

  const request = new Request(_url['verify-token'], options)

  return _fetch(request)
}

export const refreshToken = (token) => {
  let options = _options
  options.method = 'POST'
  options.body = JSON.stringify({token})

  const request = new Request(_url['refresh-token'], options)

  return _fetch(request)
}

export const getUser = (username, token='') => {
  let options = _options
  options.method = 'GET'
  if (token) options.headers.append('Authorization', `JWT ${token}`)

  const request = new Request(`${_url['users']}/${username}`, options)

  return _fetch(request)
}

我喜欢这段代码的地方是,当我需要请求资源时,我只是运行一个带有所需参数的函数,而不知道它是 get 或 post 还是其他,我不需要传递 header 配置和 url。

// example api call
let token = '4346h9r7yt47t9...'

verifyToken(token)
  .then(data => {
    // server response json available here

    token = data.token
  })
  .catch(err => {
    // handle network error and bad response here

    console.log(err)
  })

我正在关注@challenge 解决方案。并设法缩短它:

// Change _build function name to makeRequest and export it
const makeRequest = (name, _url='', body=undefined, headers={}) => {
  let [method, url] = source[name]
  let options = {
     headers: new Headers({
       'Content-Type': 'application/json',
       ...headers,
     })
   }
  options.method = method
  if (body) options.body = JSON.stringify(body)
  return _fetch(url+_url, options)
}

export default makeRequest

但是,当然要调用这个函数,我需要提供附加的 url,如果需要,还需要一个自定义标题。但是随着这个项目的进行,证明需要附加 url(由用户详细资源使用)和 costum 标头(由需要身份验证的资源使用)。

【问题讨论】:

    标签: javascript rest api design-patterns refactoring


    【解决方案1】:
    let source = {
      'getUser': (..._p) => ['GET', `/api/users/${_p[0]}`, undefined, {'Authorization': `JWT ${_p[1]}`}],
      'obtainToken': (..._p) => ['POST','/api/obtain-token/', {username:_p[0], password:_p[1]}],
      'verifyToken': (..._p) => ['POST','/api/verify-token/', {token:_p[0]}],
      'refreshToken': (..._p) => ['POST', '/api/refresh-token/',{token:_p[0]}]
    }
    
    
    const requests = {}
    Object.keys(source).forEach(key => {
      requests[key] = (...params) => {
        let [method, url, body, headers ={}] = source[key](...params)
        let options = {
           headers: new Headers({
             'Content-Type': 'application/json',
             ...headers,
           })
         }
        options.method = method
        if (body) options.body = JSON.stringify(body)
        return _fetch(new Request(url, options))
      }
    })
    
    export default requests
    

    它需要更多的测试和审查..

    【讨论】:

    • 你检查了吗?
    • 有趣,在以前的解决方案中,发送给 api 调用的参数是严格的(它需要按一定的顺序),我想知道我是否可以像 python 那样进行函数调用(使用 kwargs,例如:makeRequest(名称='用户'))。但是我认为这个解决方案在某些方面回答了它。有人认为,我的用户资源不必有授权标头。在后端,如果存在令牌,用户端点将响应不同的数据。
    • 我遗漏了一些东西...我想我现在已经修好了...如果您检查过请通知我
    • 你考虑过使用 axios 吗? npmjs.com/package/axios 很棒很简单...
    • 我会坚持使用 fetch,因为现在我的代码对我来说仍然可读。
    【解决方案2】:
    let source = {
      'getUser': ['GET', '/api/users/'],
      'obtain-token': ['POST','/api/obtain-token/'],
      'verify-token': ['POST','/api/verify-token/'],
      'refresh-token':['POST', '/api/refresh-token/']
    }
    
    let _build = (name, _url, body, headers) => {
      let [method, url] = source[name]
      let options = {
         headers: new Headers({
           'Content-Type': 'application/json',
           ...headers,
         })
       }
      options.method = method
      if (body) options.body = JSON.stringify(body)
      return new Request(url+_url, options)
    }
    

    然后

    export const obtainToken = (username, password) => {
      const credential = {username, password}
      const request = _build('obtainToken','', credential, {})
      return _fetch(request)
    }
    export const verifyToken = (token) => {
      const request = _build('verifyToken', '',{token}, {})
      return _fetch(request)
    }
    
    export const refreshToken = (token) => {
      const request = _build('refreshToken', '', {token}, {})
      return _fetch(request)
    }
    export const getUser = (username, token='') => {
      let headers = {'Authorization': `JWT ${token}`}
    
      const request = _build('getUser',`/${username}`, undefined, headers)
      return _fetch(request)
    }
    

    更多,而不是...

    return new Request(url+_url, options)
    

    在 _build 函数中,您可以将其替换为

    return _fetch(new Request(url+_url, options))
    

    这让你有这个:

       export const obtainToken = (username, password) => {
          const credential = {username, password}
          return _build('obtainToken','', credential, {})
        }
        export const verifyToken = (token) => {
          return _build('verifyToken', '',{token}, {})
        }
    
        export const refreshToken = (token) => {
          retun _build('refreshToken', '', {token}, {})
        }
    
        export const getUser = (username, token='') => {
          let headers = {'Authorization': `JWT ${token}`}
          return _build('getUser',`/${username}`, undefined, headers)
        }
    

    【讨论】:

    • 谢谢,这正是我想要的。
    • 不客气,您甚至可以通过使用 export default {...在这里您使用将直接从源构建的构建函数 } 做更多事情,它更复杂...
    • 我现在使用您的解决方案更新了我的问题并设法缩短了它。
    猜你喜欢
    • 1970-01-01
    • 2019-01-23
    • 1970-01-01
    • 2013-07-13
    • 2015-07-22
    • 2015-01-12
    • 1970-01-01
    • 2020-07-28
    • 1970-01-01
    相关资源
    最近更新 更多