简体   繁体   English

用于缓存外部API的API设计

[英]API Design that Caches an External API

I have built a lightweight Ruby code to wrap an external API: 我已经构建了一个轻量级的Ruby代码来包装外部API:

api = ExternalAPI.new
api.expensive_operation(object)

It works fine. 它工作正常。 However, since the API is expensive, I don't want to call it unless necessary. 但是,由于API很昂贵,我不想在必要时调用它。 This is why I am creating a higher-level API that wraps the API call with local caching. 这就是为什么我要创建一个用本地缓存包装API调用的更高级API。 I don't want the application to have to worry about the details about how the API is cached. 我不希望应用程序不必担心有关如何缓存API的详细信息。 (Caching could be accomplished by memory, disk, abaci , even pigeons -- it is not the application's concern.) (缓存可以通过内存,磁盘, abaci甚至是鸽子来实现 - 这不是应用程序的关注点。)

Here is what I am currently considering: 以下是我目前正在考虑的内容:

wrapper = ExternalAPIWrapper.new
wrapper.expensive_operation(object)

I don't like about the name ExternalAPIWrapper . 我不喜欢ExternalAPIWrapper这个名字。 It is generic, does not convey the purpose of the wrapper. 它是通用的,不传达包装器的目的 In particular, it does not indicate that it is checks a local cache first and only hits the low-level API if necessary. 特别是,它并不表示它首先检查本地缓存,只在必要时才会访问低级API。

I'm looking for answers that improve upon this starting point. 我正在寻找能够改善这个起点的答案。 Here are some things I'm looking for: 以下是我正在寻找的一些东西:

  1. A better name for the high-level class 高级班级的更好名称
  2. A better style API 一个更好的样式API
  3. Design pattern(s) that might help 可能有帮助的设计模式
  4. (Perhaps a longshot...) a Ruby gem that wraps and caches API calls (也许是一个长篇...)一个包装和缓存API调用的Ruby gem

For #1 the name that comes to mind is CachedExternalAPI :) Not sure what you mean by "a better style API", though. 对于#1,我想到的名字是CachedExternalAPI :)但是不确定“更好的样式API”是什么意思。

As for #3/4: I don't know of a RubyGem that does this sort of caching thing, but I'd implement the cached API in a "metaprogramming" fashion, automatically generating the methods for the cached API calls, eg 至于#3/4:我不知道RubyGem做了这种缓存的事情,但是我以“元编程”的方式实现了缓存的API,自动生成缓存的API调用的方法,例如

class CachedExternalAPI
  @cache = { }

  class << self

    [:foo, :bar, :baz].each do |m|
      define_method m do
        return (puts "Totally cached!"; @cache[m]) if not @cache[m].nil?
        puts "Not cached :("
        @cache[m] = 42
      end
    end

  end
end

CachedExternalAPI.foo()
CachedExternalAPI.foo()

CachedExternalAPI.bar()
CachedExternalAPI.bar()

Which will yield 哪个会产生

Not cached :( 没有缓存:(
Totally cached! 完全缓存!
Not cached :( 没有缓存:(
Totally cached! 完全缓存!

This of course assumes that the caching mechanism for all API calls is the same. 这当然假设所有API调用的缓存机制都是相同的。 But if your API is cachable that way, you can keep the cached API wrapper pretty DRY. 但是,如果您的API可以通过这种方式缓存,则可以使缓存的API包装器保持干净。

Rob, a friend of mine, found APICache : Rob,我的一个朋友,发现了APICache

APICache (aka api_cache) APICache(又名api_cache)

APICache allows any API client library to be easily wrapped with a robust caching layer. APICache允许使用强大的缓存层轻松包装任何API客户端库。 It supports caching (obviously), serving stale data and limits on the number of API calls. 它支持缓存(显然),提供陈旧数据和限制API调用的数量。 It's also got a handy syntax if all you want to do is cache a bothersome url. 如果你想要做的就是缓存一个麻烦的网址,它也有一个方便的语法。

APICache supports multiple caching strategies, including: APICache支持多种缓存策略,包括:

  • A simple in-memory cache 一个简单的内存缓存
  • Various backends via Moneta , a "unified interface to key-value stores" 通过Moneta的各种后端,“键值存储的统一接口”
  • Memcached via Dalli , named after Dalí's Persistence of Memory Memcached通过Dalli ,以达利的记忆持久性命名

很少细节知道你想要什么,但我直接想到了一个桥接模式,因为你实际上是在尝试在改变你的缓存后端时解耦你的抽象和实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM