Bonjour à tous. Cette fois, j'ai décidé de faire quelque chose de plus intéressant qu'un autre bot, alors je vais ensuite vous montrer comment implémenter l'API REST avec Deno, connecter et utiliser MongoDB comme base de données et tout exécuter sous Linux.
Une version vidéo de cet article est disponible ci-dessous:
Description de la tâche
A titre d'exemple, j'ai choisi l' API Github Gists et les méthodes suivantes:
[POST] Créez un résumé;
[GET] Liste publique gists;
[GET] Obtenez un aperçu;
[PATCH] Mettre à jour un élément essentiel;
[DELETE] Delete a gist.
api/mod.ts
:
console.log('hello world');
, deno run mod.ts
:
api/deps.ts
:
/* REST API */
export { Application, Router } from "<https://deno.land/x/oak/mod.ts>";
export type { RouterContext } from "<https://deno.land/x/oak/mod.ts>";
export { getQuery } from "<https://deno.land/x/oak/helpers.ts>";
/* MongoDB driver */
export { MongoClient, Bson } from "<https://deno.land/x/mongo@v0.21.0/mod.ts>";
: NodeJS, Deno npm node_modules
, url . Third Party Modules http://deno.land.
API Boilerplate
, API mod.ts
:
import { Application, Router } from "./deps.ts";
const router = new Router();
router
.get("/", (context) => {
context.response.body = "Hello world!";
});
const app = new Application();
app.use(router.routes());
app.use(router.allowedMethods());
await app.listen({ port: 8000 });
Application
Router
deps.ts
.
, :
deno run --allow-net mod.ts
;
http://localhost:8000
;
'Hello world!';
: Deno secure by default. , () (--allow-net
, (--allow-read
--allow-write
, (--allow-env
) .
POST /gists
, .
:
[POST] /gists
:
content: string | body;
:
201 Created;
400 Bad Request;
handlers
create.ts
, handler () :
import { RouterContext } from "../deps.ts";
import { createGist } from "../service.ts";
export async function create(context: RouterContext) {
if (!context.request.hasBody) {
context.throw(400, "Bad Request: body is missing");
}
const body = context.request.body();
const { content } = await body.value;
if (!content) {
context.throw(400, "Bad Request: content is missing");
}
const gist = await createGist(content);
context.response.body = gist;
context.response.status = 201;
}
:
(
request.hasBody
!content
);
createGist
( );
201 Created.
, ( service.ts
):
import { insertGist } from "./db.ts";
export async function createGist(content: string): Promise<IGist> {
const values = {
content,
created_at: new Date(),
};
const _id = await insertGist(values);
return {
_id,
...values,
};
}
interface IGist {
_id: string;
content: string;
created_at: Date;
}
content: string
, IGist
.
MongoDB. db.ts
:
import { Collection } from "<https://deno.land/x/mongo@v0.21.0/src/collection/collection.ts>";
import { Bson, MongoClient } from "./deps.ts";
async function connect(): Promise<Collection<IGistSchema>> {
const client = new MongoClient();
await client.connect("mongodb://localhost:27017");
return client.database("gist_api").collection<IGistSchema>("gists");
}
export async function insertGist(gist: any): Promise<string> {
const collection = await connect();
return (await collection.insertOne(gist)).toString();
}
interface IGistSchema {
_id: { $oid: string };
content: string;
created_at: Date;
}
:
MongoDB;
gist_api
connect
;
,
gist_api
IGistSchema
;
insertOne
(inserted id);
MongoDB
, :
sudo systemctl start mongod sudo systemctl status mongod
, :
deno run --allow-net mod.ts
;
Postman API:
, 201 Created
_id
:
: , TypeScript . - Deno TypeScript .
GET /gists
, .
:
[GET] /gists
:
skip: string | query;
limit: string | query;
:
200 OK;
handlers/list.ts
, handler () :
import { getQuery, RouterContext } from "../deps.ts";
import { getGists } from "../service.ts";
export async function list(context: RouterContext) {
const { skip, limit } = getQuery(context);
const gists = await getGists(+skip || 0, +limit || 0);
context.response.body = gists;
context.response.status = 200;
}
:
query string
getQuery
;
getGists
( );
200 OK;
: number
, string
. +skip || 0
( , NaN
0
).
, :
export function getGists(skip: number, limit: number): Promise<IGist[]> {
return fetchGists(skip, limit);
}
skip: number
limit: number
, , IGist
.
MongoDB. fetchGists
db.ts
:
export async function fetchGists(skip: number, limit: number): Promise<any> {
const collection = await connect();
return await collection.find().skip(skip).limit(limit).toArray();
}
:
gist_api
connect
;
,
skip
-limit
;
deno run --allow-net mod.ts
;
Postman API:
, 200 OK
:
GET /gists/:id
.
:
[GET] /gists/:id
:
id: string | path
:
200 OK;
400 Bad Request;
404 Not Found.
handlers/get.ts
, handler () :
import { RouterContext } from "../deps.ts"
import { getGist } from "../service.ts";
export async function get(context: RouterContext) {
const { id } = context.params;
if(!id) {
context.throw(400, "Bad Request: id is missing");
}
const gist = await getGist(id);
if(!gist) {
context.throw(404, "Not Found: the gist is missing");
}
context.response.body = gist;
context.response.status = 200;
}
:
id
400 ;
getGist
404 ( );
200 OK;
, :
export function getGist(id: string): Promise<IGist> {
return fetchGist(id);
}
interface IGist {
_id: string;
content: string;
created_at: Date;
}
id: string
, IGist
.
MongoDB. fetchGist
db.ts
:
export async function fetchGist(id: string): Promise<any> {
const collection = await connect();
return await collection.findOne({ _id: new Bson.ObjectId(id) });
}
:
gist_api
connect
;
findOne
_id
;
deno run --allow-net mod.ts
;
Postman API:
, 200 OK
:
PATCH /gists/:id
.
, :
[PATCH] /gists/:id
:
id: string | path
content: string | body
:
200 OK;
400 Bad Request;
404 Not Found.
handlers/update.ts
, handler () :
import { RouterContext } from "../deps.ts";
import { getGist, patchGist } from "../service.ts";
export async function update(context: RouterContext) {
const { id } = context.params;
if (!id) {
context.throw(400, "Bad Request: id is missing");
}
const body = context.request.body();
const { content } = await body.value;
if (!content) {
context.throw(400, "Bad Request: content is missing");
}
const gist = await getGist(id);
if (!gist) {
context.throw(404, "Not Found: the gist is missing");
}
await patchGist(id, content);
context.response.status = 200;
}
:
id
400 ;
!content
;
getGist
404 ;
patchGist
( );
200 OK.
, :
export async function patchGist(id: string, content: string): Promise<any> {
return updateGist({ id, content });
}
interface IGist {
_id: string;
content: string;
created_at: Date;
}
id: string
content: string
, any
.
MongoDB. updateGist
db.ts
:
export async function updateGist(gist: any): Promise<any> {
const collection = await connect();
const filter = { _id: new Bson.ObjectId(gist.id) };
const update = { $set: { content: gist.content } };
return await collection.updateOne(filter, update);
}
:
gist_api
connect
;
filter
, ;
update
, ;
updateOne
;
deno run --allow-net mod.ts
;
Postman API:
, 200 OK
:
DELETE /gists/:id
, , .
, :
[DELETE] /gists/:id
:
id: string | path
:
204 No Content;
404 Not Found.
handlers/remove.ts
, handler () :
import { RouterContext } from "../deps.ts";
import { getGist, removeGist } from "../service.ts";
export async function remove(context: RouterContext) {
const { id } = context.params;
if (!id) {
context.throw(400, "Bad Request: id is missing");
}
const gist = await getGist(id);
if (!gist) {
context.throw(404, "Not Found: the gist is missing");
}
await removeGist(id);
context.response.status = 204;
}
:
id
400 ;
getGist
404 ;
removeGist
( );
204 No Content.
, :
export function removeGist(id: string): Promise<number> {
return deleteGist(id);
}
id: string
number
.
MongoDB. deleteGist
db.ts
:
export async function deleteGist(id: string): Promise<any> {
const collection = await connect();
return await collection.deleteOne({ _id: new Bson.ObjectId(id) });
}
:
gist_api
connect
;
deleteOne
_id
;
deno run --allow-net mod.ts
;
Postman API:
, 204 No Content
:
: . isDeleted: boolean
.
FAQ
API 404 Not Found
router
mod.ts
:
import { Application, Router } from "./deps.ts";
import { list } from "./handlers/list.ts";
import { create } from "./handlers/create.ts";
import { remove } from "./handlers/remove.ts";
import { get } from "./handlers/get.ts";
import { update } from "./handlers/update.ts";
const app = new Application();
const router = new Router();
router
.post("/gists", create)
.get("/gists", list)
.get("/gists/:id", get)
.delete("/gists/:id", remove)
.patch("/gists/:id", update);
app.use(router.routes());
app.use(router.allowedMethods());
await app.listen({ port: 8000 });
API 500 Internal Server Error
const app = new Application();
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
console.log(err);
}
});
...
-
-
API;
-
-
.
, , , , -.