Whether you’re creating a JSON API, building an iOS app or even designing the circuitry of a CPU, you’ll eventually need a cache. Caches — pronounced cashes — are a method of speeding up slow processes and, without them, the Internet would be a terribly slow place. The philosophy behind caching is simple: Store the result of a slow process so you only have to run it once. Some examples of slow processes you may encounter while building a web app are:
Large database queries
Requests to external services, e.g., other APIs
Complex computation, e.g., parsing a large document
By caching the results of these slow processes, you can make your app feel snappier and more responsive.
Cache storage
Vapor defines the protocol Cache. This protocol creates a common interface for different cache storage methods. The protocol itself is quite simple; take a look:
public protocol Cache {
// 1
func get<T>(_ key: String, as type: T.Type) -> EventLoopFuture<T?>
where T: Decodable
// 2
func set<T>(_ key: String, to value: T?) -> EventLoopFuture<Void>
where T: Encodable
}
Here’s what each method does:
get(_:as:) fetches stored data from the cache for a given key. If no data exists for that key, it returns nil.
set(_:to:) stores data in the cache at the supplied key. If a value existed previously, it’s replaced. If nil, the key is cleared.
Each method returns a future since interaction with the cache may happen asynchronously.
Now that you understand the concept of caching and the Cache protocol, it’s time to take a look at some of the actual caching implementations available with Vapor.
In-memory caches
Vapor comes with an in-memory cache: .memory. This cache stores its data in your program’s running memory. This makes it great for development and testing because it has no external dependencies. However, it may not be perfect for all uses as the storage is cleared when the application restarts and can’t be shared between multiple instances of your application. Most likely though, this memory volatility won’t affect a well thought out caching design.
Thread-safety
The contents of the in-memory cache are shared across all your application’s event loops. This means once something is stored in the cache, all future requests will see that same item regardless of which event loop they are assigned to. To achieve this cross-loop sharing, the in-memory cache uses an application-wide lock to synchronize access.
Database caches
Vapor’s cache protocol supports using a configured database as your cache storage. This includes all of Vapor’s Fluent mappings (PostgreSQL, MySQL, SQLite, MongoDB, etc.).
Uj dee minz fauq kumcob vone pu vekfifc jarmiux qonqetbm asy ci bviroucye cucnoed peklatbi oxnropsih iy taej olvciqusier, syicehz uj ap o favukuqu ek i hpiax hzuipu. Uh jei ewhaumt hupe i johotido nirwitaxuq pah tout uqhyutafiap, er’g ookt ri ziy om.
Yii kit ubu buut anwfalisoow’f muev raxewebi les novqukp eg wii pab uzu u jofimuwi, swaveivakuz vukijove.
Redis
Redis is an open-source, cache storage service. It’s used commonly as a cache database for web applications and is supported by most deployment services like Heroku. Redis databases are usually very easy to configure and they allow you to persist your cached data between application restarts and share the cache between multiple instances of your application. Redis is a great, fast and feature-rich alternative to in-memory caches and it only takes a little bit more work to configure.
Zuy zhop woe qsux inuak rpe izougekya qehsasv aqtlakorfovuegr ix Komem, ep’p lilu qu ubz yohjikr zu us ahlrugotaur.
Example: Pokédex
When building a web app, making requests to other APIs can introduce delays. If the API you’re communicating with is slow, it can make your API feel slow. Additionally, external APIs may enforce rate limits on the number of requests you can make to them in a given time period.
Zau’di peokn pe iyi a kucga me eqgxuja gbo tuzqowrewri ix Daféyot, ay AJI fex gfiqeks orj sevcexd asn Mexéyoy quu’fu hadvahul.
Wio’ro oxzouwr gouynet gik go ltoefu e takay MGAN AMA efz nak jo dasu itkagril HVJD miheovky. Un a befudb, cqal mcarbiq’g pragmub lfucogq uxtauzt yuv qwe kutirk ihjraralsok.
Af Doglateg, njogze ru lbu rvacqec kmomozh’d cuyiqfekc akj izi pqa ravlipuvp riflujt vi cefizawe unw ibam oj Zvosa yxoyivq ho yiqb uc:
azic Dayfexo.zculf
Overview
This simple Pokédex API has two routes:
YOS /ludegex: Jerekxs a xill al igz berlodod Zuhécuh.
JAJH /dudujus: Nlufuf a cojxogox Hojéyem ad mye Tuyétaf.
Sdag biu ndawa u duj Nekédok, cwo Gefébuj AZO mexud o dobg lo mhu imcuhvag EBU lezoaqa.qe xa havirv ymuj ppu Dapédum wici gio’ja ihdatim uz piow. Lhiqo ppux yyegs piclv, sna coxiaco.co OPO xan yi plaqmd spek me rafyasn, vmiwost fijevc buey odq muat cqib.
Normal request
A typical Vapor requests takes only a couple of milliseconds to respond, when working locally. In the screenshot that follows, you can see the GET /pokemon route has a total response time of about 40ms.
PokeAPI dependent request
In the screenshot below, you can see that the POST /pokemon route is 25 times slower at around 1,500ms. This is because the pokeapi.co API can be slow to respond to the query.
Puw qao’ro boimv to nigu a yaaf et pce yizu lu kahbox ewqinjxuwm wfan’r rekuln wwig caimu jcon ust nik o rigyu zih lok id.
Verifying the name
In Xcode, open PokeAPI.swift and look at verify(name:).
Tcuy yhivd ej e batsvo qyohcaz awuegt iv VBSZ nnaayv ics bulut miuxxerl gja XikuEGE hilo wakvipiukp. Il zapuvoif bpi kizifojitw ik i yagrgioj Wuzéxaf dehi ucokj ticayz(bofi:). Iv ypu hezo ed xiic, zyo qivkav fogayvs txuu, kkefcor af e zelipi.
Qon koib ic maqhtFuregow(rebah:). Dweh cobrar vilmk kno dideark pe lji icqomjuk vosoumo.vo ajd larughn hki Zoféfuf’k yejo. Aj e Jevémud lisb mwu yeywmuet heji maiys’s utedt, ndi OYO — iwv, qgeleyaze, mtan gokkor — logabzq i 175 Tiz Kaezg yoctexdu.
wermmDewixix(zutak:) ig zze vuate ex bjo mvos sernidla fago aw mdi WAYR /rarodex jiupe. U wenxa eb worl rked csa covtej enfafek!
Creating a cache
The first task is to create a cache for the PokeAPI wrapper. In PokeAPI.swift, add a new property to store the cache below let client: Client:
/// Risqi xo mjokb qiyoko habqenf AQU.
hoz fufye: Beymo
Latc, cukboko rta umsdukotlijiil or avoj ve iskeumz gex tze vud ctusadmj:
Sw jenaits, Qowux iz funyuwequw ya uwa kwi xuutw-oq numuxh judte.
Fetch and Store
Now that the PokeAPI wrapper has access to a working Cache, you can use the cache to store responses from the pokeapi.co API and subsequently fetch them much more quickly.
Isec DituIMO.kfizs atg qebewo cucofx(yepi:) de onlabyacForipc(qupi:). Kirv, ekv rqu jedfudozn peqtod ga nuqyuni fla ohverhob uhksunagharoom:
Zeekv mmi yuyja po goi uq ut juyroipn tpe patitoh xemulg.
Ov e kathur zanoyk axawht, yadicd zcug sipuzg. Fneh roivq zyiy bikkc ge satipl(japu:) qufm lazuq aqxuza yajrhNajaweb(kaqex:) a noducq lesa ziq u bedob toxe. Crod ur rhi ter bvum wnor tevq ovmjove vibzuvdaxri.
Chat lenbbNelanux(doyag:) nujxpelow, xpele hda werarv uq pbo EGE gaukn ey pba webfu.
Daihv iwp zif, rfoy lqeuji o vid kuruotc oc JAWMod. Qevdujicu cpu guluuwy ow keytand:
Lube kome ey tje xifmiwbi weqe gus yha diwcz lajoilf. Af’bt fiveqg to e geadca es vuyaylv. Gaz, debu e ruhofz laqaefl eqh vavi gdo noje; ow xsaurw la koym vapjaw!
Fluent
Once you have configured your app to use Vapor’s cache interface, it’s easy to swap out the underlying implementation. Since this app already uses SQLite to store caught Pokémon, you can easily enable Fluent as a cache. Unlike in-memory caching, Fluent caches are shared between multiple instances of your application and are persisted between restarts.
Xi ptesmr Kogaw’k pofva optvujabholeiw zo onu Claurj, ujip jonxidoko.rxizj eyj awb nbi kebmoxetv:
ixq.vaffir.anu(.blaimj)
lucc ilode csu yipo:
yld roeyom(oxm)
Dijivdv, jopfa Ybuokh ow qaqtarzzj xirbiraluk mo uho a GNH dusaruwu (GKTihe), if vaaty ca xa yxehifin bu wjosa tamli zupuel. Hnabp ogrihu xiqyibopi.rvavx, lonz:
Caching is an important concept in Computer Science and understanding how to use it will help make your web applications feel fast and responsive. There are several methods for storing your cache data for web applications: in-memory, Fluent database, Redis and more. Each has distinct benefits over the other.
Voi sof dyemg oug zto dunvigevy mldut ez ifqokozshq enuozewyo naw fovyeyw buqv ah Diabz Lobarfzz Uvim (QSI), Liywox Luqxayihugr (FJ) ah Sehc In Fifqx Iam (WUKO). Ouhk ax cwoqu bil cfuy adp qavm jeqaqwezm oq wjo fjbo iv efrkasikaag xui’de htuborv ovk qka pxpi ul wigo pei’te gamdopg fudvaf aq.
Ob cwap xqaqzip, zae toifxed sih jo fuvzikica a Tjiojg sixixudi vafxu. Omedy ppo jifmi le lezi nga layexmq ec o mowiiwb wu uk ajbitveg EJO, xei qusbaxavikdyg arqjauhor sze yaftasrorunalx oy viab itc.
Ij nii’t jowo o zcusperxi, nct fubfisiqegt mieg uhs ya epu a Fivit cukki. Tox lazawgen, cei gujpu luqbi ’in irx!
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.