एक छोटा Deno API बनाना

इस पोस्ट में मैं डेनो का उपयोग करके एक छोटा एपीआई बनाने की प्रक्रिया को बताना और दिखाना चाहूंगा। डेनो नवीनतम जावास्क्रिप्ट और टाइपस्क्रिप्ट लॉन्चर है जिसे Node.js निर्माता रेयान डाहल द्वारा विकसित किया गया है।



हमारे लक्ष्य :

  • एक एपीआई विकसित करें जो उपयोगकर्ता डेटा के साथ काम करेगा
  • GET, POST, PUT और DELETE विधियों का उपयोग करने की क्षमता प्रदान करें
  • सहेजें और उपयोगकर्ता डेटा को स्थानीय JSON फ़ाइल में अपडेट करें
  • विकास को गति देने के लिए ढांचे का उपयोग करें

केवल एक चीज जिसे हमें स्थापित करने की आवश्यकता है वह है डेनो। Deno बॉक्स के बाहर टाइपस्क्रिप्ट का समर्थन करता है। इस उदाहरण के लिए, मैंने डेनो संस्करण 0.22 का उपयोग किया और यह कोड भविष्य के संस्करणों पर काम नहीं कर सकता है। टर्मिनल में डेनो संस्करण
कमांड के साथ इंस्टॉल किए गए डेनो के संस्करण का पता लगाया जा सकता है

कार्यक्रम की संरचना


handlers
middlewares
models
services
config.ts
index.ts
routing.ts

जैसा कि आप देख सकते हैं, यह Node.js. पर एक छोटे से वेब अनुप्रयोग जैसा दिखता है

  • हैंडलर - मार्ग हैंडलर शामिल हैं
  • बिचौलियों - में ऐसे कार्य शामिल हैं जिन्हें हर अनुरोध पर लॉन्च किया जाएगा
  • मॉडल - इसमें मॉडल का पदनाम होता है, हमारे मामले में यह केवल एक उपयोगकर्ता इंटरफ़ेस है
  • सेवाएं - सम्‍मिलित ... सेवाएं!
  • config.ts - एप्लिकेशन कॉन्फ़िगरेशन फ़ाइल
  • index.ts हमारे आवेदन के लिए प्रवेश बिंदु है
  • routing.ts - एपीआई मार्ग शामिल हैं

फ्रेमवर्क चयन


Node.js. के लिए कई बेहतरीन रूपरेखाएँ हैं सबसे लोकप्रिय में से एक एक्सप्रेस हैExpress'a - Koa का एक आधुनिक संस्करण भी है दुर्भाग्य से, डेनो Node.js पुस्तकालयों का समर्थन नहीं करता है और चुनाव बहुत छोटा है, लेकिन डेनो के लिए एक रूपरेखा है, जो कोआ - ओक पर आधारित है हम अपने छोटे प्रोजेक्ट के लिए इसका इस्तेमाल करेंगे। यदि आपने कभी कोआ का उपयोग नहीं किया है, तो चिंता न करें, यह एक्सप्रेस की तरह दिखता है।

एक आवेदन प्रविष्टि बिंदु बनाना


index.ts

import { Application } from "https://deno.land/x/oak/mod.ts";
import { APP_HOST, APP_PORT } from "./config.ts";
import router from "./routing.ts";
import notFound from "./handlers/notFound.ts";
import errorMiddleware from "./middlewares/error.ts";

const app = new Application();

app.use(errorMiddleware);
app.use(router.routes());
app.use(router.allowedMethods());
app.use(notFound);

console.log(`Listening on ${APP_PORT}...`);

await app.listen(`${APP_HOST}:${APP_PORT}`);

पहली पंक्ति में, हम मुख्य डेनो चिप्स में से एक का उपयोग करते हैं - इंटरनेट से सीधे मॉड्यूल आयात करते हैं। उसके बाद, कुछ भी असामान्य नहीं है: हम एक एप्लिकेशन बनाते हैं, मिडलवेयर, मार्गों को जोड़ते हैं और अंत में, सर्वर शुरू करते हैं। एक्सप्रेस या कोआ का उपयोग करते समय सब कुछ वैसा ही है।

कॉन्फ़िगरेशन बनाएँ


config.ts
const env = Deno.env();
export const APP_HOST = env.APP_HOST || "127.0.0.1";
export const APP_PORT = env.APP_PORT || 4000;
export const DB_PATH = env.DB_PATH || "./db/users.json";

हमारी कॉन्फ़िगरेशन फ़ाइल। सेटिंग्स लॉन्च पर्यावरण से स्थानांतरित की जाती हैं, लेकिन हम डिफ़ॉल्ट मान भी जोड़ देंगे। Deno.env () फ़ंक्शन , Node.js. में प्रक्रिया का एक एनालॉग है

उपयोगकर्ता मॉडल जोड़ना


मॉडल / user.ts

export interface User {
  id: string;
  name: string;
  role: string;
  jiraAdmin: boolean;
  added: Date;
}

एक रूट फ़ाइल बनाना


routing.ts

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

import getUsers from "./handlers/getUsers.ts";
import getUserDetails from "./handlers/getUserDetails.ts";
import createUser from "./handlers/createUser.ts";
import updateUser from "./handlers/updateUser.ts";
import deleteUser from "./handlers/deleteUser.ts";

const router = new Router();

router
  .get("/users", getUsers)
  .get("/users/:id", getUserDetails)
  .post("/users", createUser)
  .put("/users/:id", updateUser)
  .delete("/users/:id", deleteUser);

export default router;

फिर, असामान्य कुछ भी नहीं। हमने एक राउटर बनाया और उसमें कई मार्ग जोड़े। यह लगभग ऐसा लगता है जैसे आपने एक एक्सप्रेस एप्लिकेशन से कोड कॉपी किया है, है ना?

मार्गों के लिए इवेंट हैंडलिंग


हैंडलर / getUsers.ts

import { getUsers } from "../services/users.ts";

export default async ({ response }) => {
  response.body = await getUsers();
};

सभी उपयोगकर्ताओं को लौटाता है। यदि आपने कभी कोए का उपयोग नहीं किया है, तो मैं समझाता हूं। प्रतिक्रिया वस्तु के अनुरूप है रेस एक्सप्रेस में। एक्सप्रेस में रेस ऑब्जेक्ट में कुछ तरीके हैं जैसे कि json या send , जिसका उपयोग प्रतिक्रिया भेजने के लिए किया जाता है। ओक और कोआ में, हमें उस मूल्य को निर्धारित करना होगा जिसे हम प्रतिक्रिया पर वापस जाना चाहते हैं संपत्ति

हैंडलर / getUserDetails.ts

import { getUser } from "../services/users.ts";

export default async ({ params, response }) => {
  const userId = params.id;

  if (!userId) {
    response.status = 400;
    response.body = { msg: "Invalid user id" };
    return;
  }

  const foundUser = await getUser(userId);
  if (!foundUser) {
    response.status = 404;
    response.body = { msg: `User with ID ${userId} not found` };
    return;
  }

  response.body = foundUser;
};

यहां भी सब कुछ आसान है। हैंडलर उपयोगकर्ता को वांछित आईडी देता है।

हैंडलर / createUser.ts

import { createUser } from "../services/users.ts";

export default async ({ request, response }) => {
  if (!request.hasBody) {
    response.status = 400;
    response.body = { msg: "Invalid user data" };
    return;
  }

  const {
    value: { name, role, jiraAdmin }
  } = await request.body();

  if (!name || !role) {
    response.status = 422;
    response.body = { msg: "Incorrect user data. Name and role are required" };
    return;
  }

  const userId = await createUser({ name, role, jiraAdmin });

  response.body = { msg: "User created", userId };
};

यह हैंडलर उपयोगकर्ता बनाने के लिए जिम्मेदार है।

हैंडलर / updateUser.ts

import { updateUser } from "../services/users.ts";

export default async ({ params, request, response }) => {
  const userId = params.id;

  if (!userId) {
    response.status = 400;
    response.body = { msg: "Invalid user id" };
    return;
  }

  if (!request.hasBody) {
    response.status = 400;
    response.body = { msg: "Invalid user data" };
    return;
  }

  const {
    value: { name, role, jiraAdmin }
  } = await request.body();

  await updateUser(userId, { name, role, jiraAdmin });

  response.body = { msg: "User updated" };
};

हैंडलर यह जांचता है कि क्या निर्दिष्ट आईडी वाला उपयोगकर्ता मौजूद है और उपयोगकर्ता डेटा को अपडेट करता है।

हैंडलर / deleteUser.ts

import { deleteUser, getUser } from "../services/users.ts";

export default async ({ params, response }) => {
  const userId = params.id;

  if (!userId) {
    response.status = 400;
    response.body = { msg: "Invalid user id" };
    return;
  }

  const foundUser = await getUser(userId);
  if (!foundUser) {
    response.status = 404;
    response.body = { msg: `User with ID ${userId} not found` };
    return;
  }

  await deleteUser(userId);
  response.body = { msg: "User deleted" };
};

उपयोगकर्ता को हटाने के लिए जिम्मेदार है।

गैर-मौजूद मार्गों के लिए अनुरोधों को संसाधित करने और त्रुटि संदेश वापस करने की भी सलाह दी जाती है।

हैंडलर / notFound.ts

export default ({ response }) => {
  response.status = 404;
  response.body = { msg: "Not Found" };
};

सेवाएँ जोड़ना


उपयोगकर्ता डेटा के साथ काम करने वाली सेवाओं को बनाने से पहले, हमें दो छोटी सहायक सेवाएं बनाने की आवश्यकता है।

सेवाएं / createId.ts

import { v4 as uuid } from "https://deno.land/std/uuid/mod.ts";

export default () => uuid.generate();

प्रत्येक नए उपयोगकर्ता को एक विशिष्ट आईडी प्राप्त होगी। रैंडम नंबर जेनरेट करने के लिए हम Deno Standard लाइब्रेरी से uuid मॉड्यूल का इस्तेमाल करेंगे।

सेवाएं / db.ts

import { DB_PATH } from "../config.ts";
import { User } from "../models/user.ts";

export const fetchData = async (): Promise<User[]> => {
  const data = await Deno.readFile(DB_PATH);

  const decoder = new TextDecoder();
  const decodedData = decoder.decode(data);

  return JSON.parse(decodedData);
};

export const persistData = async (data): Promise<void> => {
  const encoder = new TextEncoder();
  await Deno.writeFile(DB_PATH, encoder.encode(JSON.stringify(data)));
};

यह सेवा JSON फ़ाइल के साथ सहभागिता करने में मदद करेगी जिसमें उपयोगकर्ता डेटा संग्रहीत किया जाएगा।
सभी उपयोगकर्ताओं को प्राप्त करने के लिए, फ़ाइल की सामग्री पढ़ें। ReadFile फ़ंक्शन , Uint8Array प्रकार का ऑब्जेक्ट देता है , जिसे JSON फ़ाइल में दर्ज करने से पहले स्ट्रिंग प्रकार में परिवर्तित किया जाना चाहिए

और अंत में, उपयोगकर्ता डेटा के साथ काम करने के लिए मुख्य सेवा।

सेवाओं / उपयोगकर्ताओं

import { fetchData, persistData } from "./db.ts";
import { User } from "../models/user.ts";
import createId from "../services/createId.ts";

type UserData = Pick<User, "name" | "role" | "jiraAdmin">;

export const getUsers = async (): Promise<User[]> => {
  const users = await fetchData();

  // sort by name
  return users.sort((a, b) => a.name.localeCompare(b.name));
};

export const getUser = async (userId: string): Promise<User | undefined> => {
  const users = await fetchData();

  return users.find(({ id }) => id === userId);
};

export const createUser = async (userData: UserData): Promise<string> => {
  const users = await fetchData();

  const newUser: User = {
    id: createId(),
    name: String(userData.name),
    role: String(userData.role),
    jiraAdmin: "jiraAdmin" in userData ? Boolean(userData.jiraAdmin) : false,
    added: new Date()
  };

  await persistData([...users, newUser]);

  return newUser.id;
};

export const updateUser = async (
  userId: string,
  userData: UserData
): Promise<void> => {
  const user = await getUser(userId);

  if (!user) {
    throw new Error("User not found");
  }

  const updatedUser = {
    ...user,
    name: userData.name !== undefined ? String(userData.name) : user.name,
    role: userData.role !== undefined ? String(userData.role) : user.role,
    jiraAdmin:
      userData.jiraAdmin !== undefined
        ? Boolean(userData.jiraAdmin)
        : user.jiraAdmin
  };

  const users = await fetchData();
  const filteredUsers = users.filter(user => user.id !== userId);

  persistData([...filteredUsers, updatedUser]);
};

export const deleteUser = async (userId: string): Promise<void> => {
  const users = await getUsers();
  const filteredUsers = users.filter(user => user.id !== userId);

  persistData(filteredUsers);
};

यहां बहुत कोड है, लेकिन यह शुद्ध टाइपस्क्रिप्ट है।

प्रसंस्करण में त्रुटि


उपयोगकर्ता डेटा के साथ काम करने में त्रुटि होने की स्थिति में इससे अधिक बुरा क्या हो सकता है? पूरा कार्यक्रम क्रैश हो सकता है। इस परिदृश्य से बचने के लिए, आप प्रत्येक हैंडलर में कोशिश / कैच निर्माण का उपयोग कर सकते हैं। लेकिन एक और अधिक सुंदर समाधान है - प्रत्येक मार्ग के सामने मिडलवेयर जोड़ें और किसी भी अप्रत्याशित त्रुटियों को रोकें जो हो सकती हैं।

midwares / error.ts

export default async ({ response }, next) => {
  try {
    await next();
  } catch (err) {
    response.status = 500;
    response.body = { msg: err.message };
  }
};

कार्यक्रम को शुरू करने से पहले, हमें चलाने के लिए डेटा जोड़ना होगा।

db / users.json

[
  {
    "id": "1",
    "name": "Daniel",
    "role": "Software Architect",
    "jiraAdmin": true,
    "added": "2017-10-15"
  },
  {
    "id": "2",
    "name": "Markus",
    "role": "Frontend Engineer",
    "jiraAdmin": false,
    "added": "2018-09-01"
  }
]

बस इतना ही! अब आप हमारे एप्लिकेशन को चलाने का प्रयास कर सकते हैं:

deno -A index.ts

"ए" ध्वज का अर्थ है कि कार्यक्रम को किसी भी अलग से अनुमति देने की आवश्यकता नहीं है। यह मत भूलो कि इस ध्वज का उपयोग उत्पादन में असुरक्षित है।

सबसे अधिक संभावना है, आपको डाउनलोड (डाउनलोड) और संकलन (संकलन) के साथ कई लाइनें दिखाई देंगी। अंत में, प्रतिष्ठित लाइन दिखाई देनी चाहिए:

Listening on 4000

संक्षेप में


हमने किन उपकरणों का उपयोग किया?

  1. Deno वैश्विक वस्तु पढ़ने / फ़ाइलें लिखने के लिए
  2. एक अद्वितीय आईडी बनाने के लिए डेनो मानक पुस्तकालय से uuid
  3. ओक - नोड के लिए कोआ द्वारा प्रेरित एक तृतीय-पक्ष ढांचा
  4. शुद्ध टाइपस्क्रिप्ट, TextEncode या JSON ऑब्जेक्ट्स जावास्क्रिप्ट में शामिल हैं

Node.js से क्या अंतर है?


  • टाइपस्क्रिप्ट या ts- नोड जैसे अन्य उपकरणों के लिए संकलक को स्थापित और कॉन्फ़िगर करने की आवश्यकता नहीं है। आप बस इन्डेक्स इंडेक्स कमांड के साथ प्रोग्राम चला सकते हैं
  • इंस्टालेशन की आवश्यकता के बिना कोड में सीधे सभी तृतीय-पक्ष मॉड्यूल शामिल हैं
  • Package.json और पैकेज- lock.json की कमी
  • हमारे कार्यक्रम की जड़ निर्देशिका में node_modules की अनुपस्थिति। सभी डाउनलोड की गई फाइलें वैश्विक कैश में स्थित हैं

यदि आवश्यक हो, तो स्रोत कोड यहां पाया जा सकता है

Source: https://habr.com/ru/post/undefined/


All Articles