Aを構築するアプリケーションを行うと雲の硝酸
54175 ワード
概要
Nitric クラウドアプリケーションを急速に開発し、展開するためのServerlessなフレームワークです.このガイドでは、次を使用して簡単なリストを作成する方法を示します.窒素関数によるAPIを持つJSまた、データの永続性のコレクションを使用します.もとはhere 硝酸サイト
ガイドでは次のように使います.
必要条件
次から始めなさい。jsアプリ
我々は、完成品を起動し、そのように沿って従って、ちょうどクローンNitric to-do Githubのプロジェクトオフ
git clone https://github.com/nitrictech/nitric-todo.git
NPMや糸で依存関係をインストールします.cd nitric-todo
yarn install
次に、選択したエディタでプロジェクトを開きます.code .
プロジェクト構造
プロジェクトは2つの主要な領域に分割されます.
これは窒素APIが格納されている場所です
Web -これはあなたの次です.アプリケーションを格納
タイピング
我々のタスクとAPIの要求/応答のいくつかのタイピングを追加します.
// todo-api/types.ts
/* Base Types */
export interface Task {
id: string;
createdAt: number;
name: string;
complete: boolean;
description?: string;
dueDate?: number;
}
export interface TaskList {
id: string;
createdAt: number;
name: string;
tasks: Task[];
}
/* Task List */
export type Filters = Partial<Task>;
export type TaskListResponse = TaskList;
export type TaskListRequest = Omit<TaskList, 'id' | 'tasks'>;
export type TaskListPostRequest = Omit<TaskList, 'id' | 'complete'>;
/* Task Post */
export type TaskPostRequest = Omit<Task, 'id'>;
/* Task Update */
export type TaskPatchRequest = { completed: boolean };
資源
アプリケーションは、コード内のリソースを定義してビルドすると、任意のルートでこれを書くことができます
.js
or .ts
ファイルが、組織のために我々は一緒に入れをお勧めします.では、新しいAPIをサポートするために必要なリソースを定義することから始めましょうresources
ディレクトリ.// todo-api/resources/apis.ts
import { api } from '@nitric/sdk';
export const taskListApi = api('taskList');
その後、我々のタスクリストを格納するために私たちのコレクションを作成したい.我々は、代わりにサブコレクションとしてそれらを格納できるようにタスクを省略します.これは将来的に個々のタスクを問い合わせるのを容易にします.// todo-api/resources/collections.ts
import { collections } from '@nitric/sdk';
import { TaskList } from 'types';
type TaskCollection = Omit<TaskList, 'tasks'>;
export const taskListCol = collection<TaskCollection>('taskLists');
路線
APIルートを設定し始めると、これらを空にするまで空の関数として残ります.
// todo-api/functions/tasks.ts
import { taskListApi } from '../resources/apis.ts';
taskListApi.get("/:listid/:id", async (ctx) => {}); // Get task with [id]
taskListApi.get("/:listid", async (ctx) => {); // Get task list with [id]
taskListApi.get("/", async (ctx) => {}); // Get all task lists
taskListApi.post("/:listid", async (ctx) => {}); // Post new task for task list
taskListApi.post("/", async (ctx) => {}); // Post new task list
taskListApi.patch("/:listid/:id", async (ctx) => {}); // Update task
taskListApi.delete("/:listid", async (ctx) => {}); // Delete task list
taskListApi.delete("/:listid/:id", async (ctx) => {}); // Delete task
それから、我々は前のコレクションを得ることができて、この機能の範囲内で使用のためにそれに許可を適用することができます.// todo-api/functions/tasks.ts
import { taskListCol } from '../resources/collections.ts';
const taskLists = taskListCol.for('reading', 'writing', 'deleting');
今我々はコレクションを持って、我々はタスクやタスクのリストを追加を開始することができます.私たちは私たちのコレクションを使用して、私たちのタスクのリストを格納するために、各タスクのリスト上のサブコレクション私たちのタスクを格納します.我々は、最初の新しいタスクのリストを使用して
POST /
終点// todo-api/functions/tasks.ts
taskListApi.post('/', async (ctx) => {
const { name, tasks } = ctx.req.json() as TaskListPostRequest;
try {
if (!name) {
ctx.res.body = 'A new task list requires a name';
ctx.res.status = 400;
return;
}
const id = uuid.generate();
await taskLists.doc(id).set({
id,
name,
createdAt: new Date().getTime(),
});
// add any tasks if supplied
if (tasks) {
for (const task of tasks) {
const taskId = uuid.generate();
await taskLists
.doc(id)
.collection<Task>('tasks')
.doc(taskId)
.set({
...task,
complete: false,
createdAt: new Date().getTime(),
});
}
}
ctx.res.body = 'Successfully added task list!';
} catch (err) {
console.log(err);
ctx.res.body = 'Failed to add task list';
ctx.res.status = 400;
}
return ctx;
});
使用POST /:listid
タスクリストのサブコレクションに新しいドキュメントを追加することで、タスクリストに新しいタスクを置くことができます.まず、タスクリストIDを受け取り、
listid -> tasks
サブコレクション.// todo-api/functions/tasks.ts
taskListApi.post('/:listid', async (ctx) => {
const { listid } = ctx.req.params;
const task = ctx.req.json() as TaskPostRequest;
try {
if (!listid) {
ctx.res.body = 'A task list id is required';
ctx.res.status = 400;
return;
}
if (!task || !task.name) {
ctx.res.body = 'A task with a name is required';
ctx.res.status = 400;
return;
}
const taskId = uuid.generate();
await taskLists
.doc(listid)
.collection<Omit<Task, 'id'>>('tasks')
.doc(taskId)
.set({
...task,
complete: false,
createdAt: new Date().getTime(),
});
ctx.res.body = 'Successfully added task!';
} catch (err) {
console.log(err);
ctx.res.body = 'Failed to add task list';
ctx.res.status = 400;
}
return ctx;
});
GET /
すべてのタスクのリストとそのタスクを返します.// todo-api/functions/tasks.ts
import { sortByCreatedAt } from "../common/utils";
...
taskListApi.get("/", async (ctx) => {
try {
const taskList = await taskLists.query().fetch();
const taskListsWithTasks = await Promise.all(
taskList.documents.map(async (doc) => {
const { documents: tasks } = await taskLists
.doc(doc.id)
.collection<Task>("tasks")
.query()
.fetch();
return {
id: doc.id,
...doc.content,
tasks: tasks
.map(({ id, content }) => ({ id, ...content }))
.sort(sortByCreatedAt),
};
})
);
ctx.res.json(taskListsWithTasks.sort(sortByCreatedAt));
} catch (err) {
console.log(err);
ctx.res.body = "Failed to retrieve taskList list";
ctx.res.status = 400;
}
return ctx;
});
// todo-api/common/utils.ts
import { Task } from 'types';
type CreatedAtData = Pick<Task, 'createdAt'>;
export const sortByCreatedAt = (a: CreatedAtData, b: CreatedAtData) => {
return a.createdAt < b.createdAt ? 1 : -1;
};
中GET /:listid
エンドポイントは、単一のリストを取得することができますし、タスクのクエリにフィルタを適用します.// todo-api/functions/tasks.ts
// Get all tasks from a task list, with filters
taskListApi.get('/:listid', async (ctx) => {
const { listid } = ctx.req.params;
const filters = ctx.req.query as Filters;
try {
const taskListRef = taskLists.doc(listid);
let query = taskListRef.collection<Task>('tasks').query();
// Apply filters to query before executing query;
Object.entries(filters).forEach(([k, v]) => {
switch (k) {
case 'complete': {
query = query.where(k, '==', v === 'true');
break;
}
case 'dueDate': {
query = query.where(k, '>=', v);
break;
}
default: {
query = query.where(k, 'startsWith', v as string);
break;
}
}
});
const taskList = await taskListRef.get();
const tasks = await query.fetch();
ctx.res.json({
...taskList,
tasks: tasks.documents
.map((doc) => ({ id: doc.id, ...doc.content }))
.sort(sortByCreatedAt),
});
} catch (err) {
console.log(err);
ctx.res.body = 'Failed to retrieve tasks';
ctx.res.status = 400;
}
return ctx;
});
中でGET /:listid/:id
エンドポイントは、特定のリストから特定のタスクを取得し始めることができます.// todo-api/functions/tasks.ts
taskListApi.get('/:listid/:id', async (ctx) => {
const { listid, id } = ctx.req.params;
try {
// Get our task list with id [listId]
const taskListRef = taskListCol.doc(listid);
// Get all tasks from the collection with id [id]
const task = await taskListRef.collection<Task>('tasks').doc(id).get();
ctx.res.json(task);
} catch (err) {
console.log(err);
ctx.res.body = 'Failed to retrieve tasks';
ctx.res.status = 400;
}
return ctx;
});
内部PATCH :listid/:id
パッチルートは、タスクが完了したかどうかを更新するロジックを書くことができます.// todo-api/functions/tasks.ts
taskListApi.patch('/:listid/:id', async (ctx) => {
const { listid: listId, id } = ctx.req.params;
const { completed } = ctx.req.json() as ToggleRequest;
try {
const taskListRef = taskLists.doc(listId);
const taskRef = taskListRef.collection<Task>('tasks').doc(id);
const originalTask = await taskRef.get();
await taskListRef
.collection<Task>('tasks')
.doc(id)
.set({
...originalTask,
complete: completed,
});
ctx.res.body = 'Successfully updated task';
} catch (err) {
console.log(err);
ctx.res.body = 'Failed to retrieve tasks';
ctx.res.status = 400;
}
return ctx;
});
削除ルートDELETE /:listid/:id
and DELETE /:id
関連するドキュメントを取得し、コレクションから削除します.// todo-api/functions/tasks.ts
taskListApi.delete('/:listid/:id', async (ctx) => {
const { listid: listId, id } = ctx.req.params;
try {
const taskListRef = taskLists.doc(listId);
await taskListRef.collection('tasks').doc(id).delete();
ctx.res.body = 'Successfully deleted task';
} catch (err) {
console.log(err);
ctx.res.body = 'Failed to delete task';
ctx.res.status = 400;
}
return ctx;
});
taskListApi.delete('/:id', async (ctx) => {
const { id } = ctx.req.params;
try {
await taskLists.doc(id).delete();
ctx.res.body = 'Successfully deleted task list';
} catch (err) {
console.log(err);
ctx.res.body = 'Failed to delete task list';
ctx.res.status = 400;
}
return ctx;
});
APIプロキシの設定
あなたの作成
.env
ファイル名の変更.env.example
ファイルmv web/.env.example web/.env
内部next.config.js
次のプロキシ間でプロキシに定義された書き換えを行う必要があります.JS APIルートとあなたの硝酸アピール.それはAPI_BASE_URL
に定義されている変数.env
ファイル.// web/next.config.js
module.exports = {
reactStrictMode: true,
api: {
bodyParser: {
bodyParser: false, // Disallow body parsing, consume as stream
},
},
// To avoid any CORs issues use Next.js as a proxy for Nitric API
// We are working on it :)
async rewrites() {
return [
{
source: '/apis/:path*',
destination: `${process.env.API_BASE_URL}/apis/:path*`, // Proxy to Backend
},
];
},
};
ローカルに動く
ローカルAPIをテストするには、次のようにします.
cd todo-api
nitric run
我々は次を起動することができます.JSフロントエンドcd ../web
yarn dev
展開
窒素APIの配備
あなたの資格情報と他のどのクラウド特有の設定を設定してください.
Warning: Publishing services to the cloud may incur costs.
nitric stack up -s todo
展開が完了すると、関連クラウドコンソールに移動し、APIを参照して対話することができます.When you're done, you can destroy the stack with
nitric down -s todo
次を展開します。jsアプリ
次の配備ボタンのいずれかを選択し、
API_BASE_URL
展開されたAPI URLでこの設定プロセス中に変数を設定します.展開する
Netlifyに配備する
注意:
Netlify.toml
このリポジトリのファイルには、API_BASE_URL
初期配置のプロパティ.Reference
この問題について(Aを構築するアプリケーションを行うと雲の硝酸), 我々は、より多くの情報をここで見つけました https://dev.to/homelessdinosaur/building-a-to-do-app-for-the-cloud-with-nitric-2l8aテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol