0
0

REST API Caching (忘備録)

Posted at

キャッシング

キャッシング(caching)は、特定のリソースのコピーを保存し、要求された時にそれを提供する技術である。

キャッシングを使用してネットワークを最適化することで、以下のようにサービスの品質全体を向上させる。

  • バンド幅の削減
  • レイテンシーの削減
  • サーバーへの負荷の削減
  • ネットワークの障害を隠す

REST apiのキャッシング

GETリクエストは、デフォルトでキャッシュ可能であるべきである。ブラウザは、通常全てのGETリクエストをキャッシュ可能として扱う。

POSTリクエストは、デフォルトでキャッシュ不可である。Expiresヘッダ又はCache-Controlヘッダを設定すると、キャッシュ可能になる。

PUT及びDELETEリクエストはキャッシュ不可である。

キャッシングヘッダ

キャッシングヘッダ(Cache Headers)は、RESP APIにおけるキャッシングの重要な部分である。キャッシングヘッダはクライアントに対してリソースのキャッシュ可能性の情報を提供する。最も一般的なキャッシュヘッダ:

  • Cache-Control
  • Expires
  • ETag
  • Last-Modified

Cache-Control

Cache-Controlヘッダーは、クライアントに対してキャッシュの指示を指定するためのものである。最も一般的なディレクティブのいくつかは以下の通りです:

  • public: レスポンスはどのキャッシュでもキャッシュ可能。
  • private: レスポンスはクライアントのブラウザキャッシュだけでキャッシュ可能。
  • no-cache: レスポンスはキャッシュされたコピーを使用する前に検証する必要がある
  • no-store: レスポンスはどこにもキャッシュされないべき。
  • max-age: レスポンスがキャッシュできる最大の時間(秒単位)

node.jsの例:

const express = require('express');
const app = express();

app.get('/api/cachedData', (req, res) => {
  res.set('Cache-Control', 'public, max-age=1000');
  res.json({ message: 'Hello world. This is a cached data.' });
});

app.listen(3000, () => console.log('Server listening on port 3000'));const express = require('express');

次、curlでテストする。

$ curl -v http://localhost:3000/api/cachedData
*   Trying 127.0.0.1:3000...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /api/cachedData HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.79.1
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Cache-Control: public, max-age=1000
< Content-Type: application/json; charset=utf-8
< Content-Length: 49
< ETag: W/"31-y/DCZtuS4N3R0s0BWizoxeyiX6E"
< Date: Sun, 19 Nov 2023 14:32:19 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< 
* Connection #0 to host localhost left intact
{"message":"Hello world. This is a cached data."}%

「Cache-Control: public, max-age=1000」が確認できた。

Expires

Expiresヘッダーは、キャッシュされたレスポンスが古くなる(stale)具体的な日時を指定する。

node.jsの例

const express = require('express');
const app = express();

app.get('/api/cachedData', (req, res) => {
  const expiryDate = new Date(Date.now() + 3600 * 1000);
  res.set('Expires', expiryDate.toUTCString());
  res.json({ message: 'Cached data with expiry' });
});

app.listen(3000, () => console.log('Server listening on port 3000'));

curlでテストする、

$ curl -v http://localhost:3000/api/cachedData
*   Trying 127.0.0.1:3000...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /api/cachedData HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.79.1
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Expires: Sun, 19 Nov 2023 15:35:04 GMT
< Content-Type: application/json; charset=utf-8
< Content-Length: 37
< ETag: W/"25-qaOhAnwI84qys32mcK7UPUI8LcE"
< Date: Sun, 19 Nov 2023 14:35:04 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< 
* Connection #0 to host localhost left intact
{"message":"Cached data with expiry"}%

「Date: Sun, 19 Nov 2023 14:35:04 GMT」と「Expires: Sun, 19 Nov 2023 15:35:04 GMT」により、 expiryDate = new Date(Date.now() + 3600 * 1000)が確認できた。

ETag

Etagヘッダーは、特定のリソースの特定バージョンの一意の識別子である。

node.jsの例

const express = require('express');
const app = express();

app.get('/api/cachedData',(req, res) => {
  const data = { message: 'ETag example' };
  const etag = generateETag(data); // Assume generateETag is a custom function that generates an ETag for the given data

  res.set('ETag', etag);
  res.json(data);
});

app.listen(3000, () => console.log('Server listening on port 3000'));

function generateETag(data) {
  // Implement your custom ETag generation logic here, e.g., a hash of the data
  return require('crypto').createHash('md5').update(JSON.stringify(data)).digest('hex');
}

curlでテストする、

$ curl -v http://localhost:3000/api/cachedData
*   Trying 127.0.0.1:3000...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /api/cachedData HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.79.1
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< X-Powered-By: Express
< ETag: ee8963b1f82a8785673ff212daae5f90
< Content-Type: application/json; charset=utf-8
< Content-Length: 26
< Date: Sun, 19 Nov 2023 14:37:33 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< 
* Connection #0 to host localhost left intact
{"message":"ETag example"}%

「ETag: ee8963b1f82a8785673ff212daae5f90」である。

Last-Modified

Last-Modifiedヘッダーは、リソースが最後に変更された日時を示す。

node.jsの例

const express = require('express');
const app = express();

app.get('/api/cachedData', (req, res) => {
  const lastModifiedDate = new Date();
  res.set('Last-Modified', lastModifiedDate.toUTCString());
  res.json({ message: 'Last-Modified example' });
});

app.listen(3000, () => console.log('Server listening on port 3000'));

curlでテストする、

$ curl -v http://localhost:3000/api/cachedData
*   Trying 127.0.0.1:3000...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /api/cachedData HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.79.1
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Last-Modified: Sun, 19 Nov 2023 14:39:36 GMT
< Content-Type: application/json; charset=utf-8
< Content-Length: 35
< ETag: W/"23-idYE3NoGknldNZGWvPSFSOLhjcY"
< Date: Sun, 19 Nov 2023 14:39:36 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< 
* Connection #0 to host localhost left intact
{"message":"Last-Modified example"}%

「Last-Modified: Sun, 19 Nov 2023 14:39:36 GMT」が確認できた。

参考

  1. https://restfulapi.net/caching/
  2. https://codedamn.com/news/backend/rest-api-caching-advanced-techniques#:~:text=Caching in REST APIs improves,provides a better user experience.
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0