教程:使用 Azure Cosmos DB 模拟器生成 TypeScript 应用并部署到Azure Cosmos DB

在本教程中,将使用 Azure Cosmos DB Linux 模拟器作为本地开发数据库,生成 TypeScript 应用程序,然后通过交换凭据迁移到Azure Cosmos DB。

在本教程中,你将了解:

  • 在 Docker 容器中启动Azure Cosmos DB模拟器
  • 创建 TypeScript 应用程序
  • 将应用程序连接到本地模拟器
  • 创建 Azure Cosmos DB 帐户
  • 将应用程序部署到Azure Cosmos DB

先决条件

启动模拟器

使用基于 Linux 的 Azure Cosmos DB 模拟器的 Docker 容器映像创建本地开发数据库。

  1. 拉取模拟器容器映像。

    docker pull mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-latest
    
  2. 启动模拟器容器。

    docker run --detach --publish 8081:8081 --publish 1234:1234 --name cosmos-db mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-latest
    
  3. 验证容器是否正在运行。

    docker ps --filter "name=cosmos-db"
    

    Important

    仿真器网关终结点可通过https://localhost:8081获得,数据资源管理器可通过http://localhost:1234使用。 模拟器使用已知的身份验证密钥:

    AccountEndpoint=http://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==;
    
    设置 价值
    终结点 https://localhost:8081
    关键 C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==

创建应用程序

创建 Next.js 应用程序并将其连接到本地模拟器。

  1. 在空文件夹中创建新的 Next.js 应用程序。 接受任何默认设置。

    npx create-next-app .
    
  2. 安装用于Azure Cosmos DB的 Node.js 客户端库。

    npm install --save @azure/cosmos
    
  3. 使用以下代码创建一 app/data.tsx 个名为的新文件。 此文件包含与数据库交互的服务器操作。

    "use server";
    
    import { CosmosClient } from "@azure/cosmos";
    import { revalidatePath } from "next/cache";
    
    const connectionString = "<cosmos-db-connection-string>";
    
    const client = new CosmosClient(connectionString);
    
    const { database } = await client.databases.createIfNotExists({ id: "work-management" });
    const { container } = await database.containers.createIfNotExists({ id: "tasks", partitionKey: "/id" });
    
    export type Todo = {
      id: string;
      title: string;
      completed: boolean;
    };
    
    export async function getTodos(): Promise<Todo[]> {
      const { resources } = await container.items
        .query("SELECT * FROM c ORDER BY c._ts DESC")
        .fetchAll();
      return resources.map((doc) => ({
        id: doc.id,
        title: doc.title,
        completed: doc.completed,
      }));
    }
    
    export async function addTodo(formData: FormData) {
      const title = formData.get("title") as string;
      if (!title?.trim()) return;
      await container.items.create({
        title: title.trim(),
        completed: false,
      });
      revalidatePath("/");
    }
    
    export async function toggleTodo(formData: FormData) {
      const id = formData.get("id") as string;
      const { resource: doc } = await container.item(id, id).read();
      if (doc) {
        await container.item(id, id).replace({
          ...doc,
          completed: !doc.completed,
        });
      }
      revalidatePath("/");
    }
    
    export async function deleteTodo(formData: FormData) {
      const id = formData.get("id") as string;
      await container.item(id, id).delete();
      revalidatePath("/");
    }
    

    Important

    在启动容器时,请将连接字符串占位符替换为本教程前面指定的凭据。

  4. 删除现有 app/page.tsx 文件并将其替换为以下代码。

    import { getTodos, addTodo, toggleTodo, deleteTodo } from "./data";
    
    export default async function Home() {
      const todos = await getTodos();
    
      return (
        <div className="min-h-screen bg-black text-zinc-50 font-sans">
          <main className="max-w-lg mx-auto py-16 px-8">
            <h1 className="text-2xl font-semibold tracking-tight mb-8">Todo App</h1>
    
            <form action={addTodo} className="flex gap-2 mb-8">
              <input
                name="title"
                placeholder="Add a todo..."
                required
                className="flex-1 rounded-md border border-zinc-700 bg-zinc-900 px-3 py-2 text-sm text-zinc-100 placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-zinc-600"
              />
              <button type="submit" className="rounded-md bg-zinc-100 px-4 py-2 text-sm font-medium text-zinc-900 hover:bg-zinc-300 transition-colors">
                Add
              </button>
            </form>
    
            <ul className="space-y-2">
              {todos.map((todo) => (
                <li key={todo.id} className="flex items-center gap-3 rounded-md border border-zinc-800 bg-zinc-900 px-3 py-2">
                  <form action={toggleTodo}>
                    <input type="hidden" name="id" value={todo.id} />
                    <button type="submit" className="text-lg leading-none">{todo.completed ? "✅" : "⬜"}</button>
                  </form>
                  <span className={`flex-1 text-sm ${todo.completed ? "line-through text-zinc-500" : "text-zinc-100"}`}>{todo.title}</span>
                  <form action={deleteTodo}>
                    <input type="hidden" name="id" value={todo.id} />
                    <button type="submit" className="text-sm text-red-400 hover:text-red-300 transition-colors">✕</button>
                  </form>
                </li>
              ))}
            </ul>
    
            {todos.length === 0 && <p className="text-center text-sm text-zinc-500 mt-4">No todos yet.</p>}
          </main>
        </div>
      );
    }
    
  5. 在本地运行应用程序。

    npm run dev
    
  6. 在浏览器中打开 http://localhost:3000 ,验证应用程序是否正在运行并连接到模拟器。

    Web 浏览器中运行的新应用程序的屏幕截图,其中多个项保存到数据库。

    小窍门

    可以查看此应用程序在 Azure Cosmos DB Emulator 数据资源管理器 http://localhost:1234 中创建的数据。 还可以将 Azure Cosmos DB 扩展用于 Visual Studio Code 数据库名为 work-management,容器命名为 tasks

  7. 停止应用程序。

创建 Azure Cosmos DB 帐户

创建Azure Cosmos DB帐户以在云中托管应用程序数据。

  1. 为帐户名称和目标资源组名称创建变量。

    RESOURCE_GROUP_NAME="<resource-group-name>"
    ACCOUNT_NAME="<account-name>"
    

    Important

    <resource-group-name><account-name> 替换为自己的值。 帐户名称必须具有多区域唯一性。

  2. 创建Azure Cosmos DB帐户。

    az cosmosdb create \
      --resource-group $RESOURCE_GROUP_NAME \
      --name $ACCOUNT_NAME
    
  3. 获取帐户的连接字符串。

    az cosmosdb keys list \
      --resource-group $RESOURCE_GROUP_NAME \
      --name $ACCOUNT_NAME \
      --type connection-strings \
      --query "connectionStrings[0].connectionString" \
      --output tsv
    
  4. 记录连接字符串的值。 你在下一步中使用它。

将应用程序连接到Azure Cosmos DB

更新应用程序以连接到Azure Cosmos DB而不是本地模拟器。

  1. app/data.tsx中,将模拟器连接字符串替换为Azure Cosmos DB连接字符串。

    const connectionString = "<azure-cosmos-db-connection-string>";
    

    Important

    <azure-cosmos-db-connection-string> 替换为在上一步中记录的连接字符串。

  2. 再次启动应用程序。

    npm run dev
    
  3. 在浏览器中打开 http://localhost:3000 。 应用程序现在将数据读取并写入Azure Cosmos DB帐户。

清理资源

如果不再需要在本教程中创建的资源,请将其删除以避免产生费用。

  1. 删除Azure Cosmos DB帐户。

    az cosmosdb delete \
      --resource-group $RESOURCE_GROUP_NAME \
      --name $ACCOUNT_NAME \
      --yes
    
  2. 停止并删除模拟器容器。

    docker stop cosmos-db
    docker rm cosmos-db
    

后续步骤