DenoのOakフレームワークとは

概要

OakはDenoのWebフレームワークであり、開発者が効率的にWebアプリケーションを作成できるように設計されています。

Oakの主な機能には、ルーティング、リクエストとレスポンスの処理、ミドルウェアのサポートが含まれています。また、ミドルウェアを使用することで、開発者はその機能を簡単に拡張できます。

ここでは、以下バージョンを使用した、Oakの基本的な使い方を紹介します。

Oak v9.0.0
Deno v1.18.0

Oakの基本概念

ルーティング

ルーティングとは、クライアントからのHTTPリクエストを受け取り、それに対応する処理を行うためのメカニズムです。Oakでは、ルーティング機能を使用して、異なるURLパスやHTTPメソッドに対するリクエストを適切に処理することができます。

import { Application, Router } from "https://deno.land/x/oak/mod.ts";

const router = new Router();

const app = new Application();

// GETメソッドに対するルートの定義
router.get('/', (context) => {
  context.response.body = 'こんにちは、世界!';
});

// POSTメソッドに対するルートの定義
router.post('/users', async (context) => {
  const { value: { name, email } } = await context.request.body();
  // ユーザーデータを処理し、レスポンスを返す
  context.response.body = { message: `ユーザーが作成されました: ${name} (${email})` };
});

// パラメータを含むルートの定義
router.get('/users/:id', (context) => {
  const userId = context.params.id;
  // データベースや他のソースからユーザーデータを取得
  const user = { id: userId, name: '山田太郎' };
  context.response.body = user;
});

app.use(router.routes());

// サーバーの起動
app.listen({ port: 3000 });
console

.log('サーバーがポート3000で起動しました');

ミドルウェア

Oakでは、ミドルウェアを作成し、リクエストごとに処理を実装することが可能です。

import { Application, Router } from "https://deno.land/x/oak/mod.ts";

const router = new Router();
const app = new Application();

app.use(async (context, next) => {
  console.log(`${context.request.method} ${context.request.url}`);
  await next();
});

// GETメソッドに対するルートの定義
router.get('/', (context) => {
  context.response.body = 'こんにちは、世界!';
});

// POSTメソッドに対するルートの定義
router.post('/users', async (context) => {
  const { value: { name, email } } = await context.request.body();
  if (!name || !email) {
    context.response.status = 400;
    context.response.body = '名前とメールアドレスは必須です';
  } else {
    // データの保存や処理を行う
    saveUserData(name, email);
    context.response.body = { message: `ユーザーが作成されました: ${name} (${email})` };
  }
});

// パラメータを含むルートの定義
router.get('/users/:id', (context) => {
  const userId = context.params.id;
  // データベースや他のソースからユーザーデータを取得
  const user = { id: userId, name: '山田太郎' };
  context.response.body = user;
});

app.use(router.routes());

// サーバーの起動
app.listen({ port: 3000 });
console.log('サーバーがポート3000で起動しました');

// データベースからデータを取得する非同期関数の例
async function getDataFromDatabase() {
  // データベースアクセスの非同期処理を実行
  return await db.query('SELECT * FROM users');
}

// ユーザーデータを保存する処理の例
function saveUserData(name, email) {
  // データの保存処理
  // ...
}

この例では、Oakフレームワークを利用しています。ルーティングのためにRouterを、アプリケーションの管理のためにApplicationを使っています。ミドルウェアはapp.use()メソッドを利用しています。

ハンドラー

Oakでは、ルーティングされたリクエストに対して実行する処理は、ハンドラー関数によって定義されます。ハンドラーは、リクエストを受け取り、必要な処理を実行してレスポンスを返す役割を果たします。

以下に、DenoのOakでのハンドラーの例を示します。

import { Application, Router } from "https://deno.land/x/oak/mod.ts";

const router = new Router();
const app = new Application();

// GETメソッドに対するハンドラーの定義
router.get('/', async (context) => {
  try {
    // リクエストの処理を行う非同期関数を実行
    const data = await getDataFromDatabase();
    context.response.body = data;
  } catch (error) {
    console.error('エラーが発生しました:', error);
    context.response.status = 500;
    context.response.body = 'エラーが発生しました';
  }
});

// POSTメソッドに対するハンドラーの定義
router.post('/users', async (context) => {
  const { value: { name, email } } = await context.request.body();
  // ユーザーデータの処理
  if (!name || !email) {
    context.response.status = 400;
    context.response.body = '名前とメールアドレスは必須です';
  } else {
    // データの保存や処理を行う
    saveUserData(name, email);
    context.response.body = { message: `ユーザーが作成されました: ${name} (${email})` };
  }
});

app.use(router.routes());

// サーバーの起動
app.listen({ port: 3000 });
console.log('サーバーがポート3000で起動しました');

// データベースからデータを取得する非同期関数の例
async function getDataFromDatabase() {
  // データベースアクセスの非同期処理を実行
  return await db.query('SELECT * FROM users');
}

// ユーザーデータを保存する処理の例
function saveUserData(name, email) {
  // データの保存処理
  // ...
}

上記の例では、GETメソッドとPOSTメソッドに対するハンドラーを定義しています。GETメソッドのハンドラーでは、非同期関数を使用してデータベースからデータを取得し、レスポンスとして返しています。POSTメソッドのハンドラーでは、リクエストのボディから必要なデータを取得し、バリデーションやデータの保存処理を行っています。

ハンドラー関数内では、リクエストの処理を非同期に行う場合には

asyncawaitを使用し、エラーハンドリングにはtry-catch構文を使用しています。エラーが発生した場合には、適切なステータスコードとエラーメッセージをレスポンスとして返しています。

以上がDenoのOakでのハンドラーの例です。これによって、リクエストの処理やデータの加工など、必要なロジックをハンドラー関数内で実装することができます。

バリデーション

Oak自体にはバリデーションの機能は組み込まれていませんが、Denoの他のライブラリを使用してバリデーションを行うことができます。

import { Application, Router } from "https://deno.land/x/oak/mod.ts";
import * as yup from "https://deno.land/x/yup/mod.ts";

const router = new Router();
const app = new Application();

// ユーザーデータのバリデーションスキーマの定義
const userSchema = yup.object().shape({
  name: yup.string().required(),
  age: yup.number().required().positive().integer(),
  email: yup.string().required().email(),
});

// POSTメソッドに対するルートの定義とバリデーションの適用
router.post('/users', async (context) => {
  const { value } = await context.request.body();
  
  try {
    // バリデーションの実行
    const validatedData = await userSchema.validate(value);

    // ユーザーデータの処理
    const userData = { ...validatedData };

    // レスポンスの送信
    context.response.body = userData;
  } catch (error) {
    context.response.status = 400;
    context.response.body = error.errors;
  }
});

app.use(router.routes());

// サーバーの起動
app.listen({ port: 3000 });
console.log('サーバーがポート3000で起動しました');

上記の例では、yupというライブラリを使用してリクエストのバリデーションを行っています。ユーザーデータのバリデーションルールを定義しています。それぞれのフィールドには、データの型やバリデーションルールを指定しています。

POSTメソッドに対するルートの定義では、リクエストボディのデータがバリデーションルールに合致しているかを検証します。バリデーションエラーがあれば、エラーメッセージをレスポンスとして返します。

これにより、Oakを使用してリクエストのバリデーションを行い、柔軟なレスポンスを生成することができます。

Oakの特徴

非同期な処理とイベント駆動アーキテクチャ:

Oakもまた、DenoのEventEmitterを活用した非同期な処理とイベント駆動アーキテクチャを採用しています。これにより、リクエストの処理を同時に並列実行することが可能となります。従来の同期型のWebフレームワークと比べて、Oakは非同期な処理の柔軟性と効率性に優れています。 イベント駆動アーキテクチャにより、Oakはイベントループの特性を最大限に活用し、リクエストの非同期処理を効率的に処理します。これにより、複数のリクエストを同時に処理することができ、レスポンス時間の短縮やスケーラビリティの向上が実現されます。

ミドルウェア (Middleware) サポートによるリソースの最適化

OakはHTTPリクエストおよびレスポンスの処理を行うためのミドルウェアを活用します。これにより、リクエストとレスポンスのライフサイクル内で実行する関数を容易に指定することができます。

さらに、Oakはリソースの最適化にも注力しています。依存関係の管理やメモリ使用量の最適化など、細部にまで渡る最適化が行われています。これにより、Oakアプリケーションは効率的に動作し、スケーラビリティに優れたパフォーマンスを提供します。

どの程度優れているか、公式サイトにドキュメンテーションが公開されているので、確認してみましょう。

高い拡張性

Oakはミドルウェアのコンセプトを活用し、簡単にカスタマイズや拡張が可能です。多数のミドルウェアを利用することで、機能の追加やモジュールの組み込みが容易になります。また、ミドルウェアの追加や削除は、アプリケーションの再起動なしに行うことができます。

リクエストとレスポンスの簡易なハンドリング

Oakはリクエストとレスポンスのハンドリングを簡易

化しました。これにより開発者は簡単にコントロールフローを作成し、エラーハンドリングも簡単に行うことができます。これらはすべてDenoの非同期処理とイベント駆動アーキテクチャをフル活用しています。