정보실

웹학교

정보실

Nodejs Deno 웹 서버 + API 학습서

본문

Deno web server + API Tutorial 


Deno는 현재 유형 안전 및 녹 편집 기능을 갖춘 블록에서 가장 멋진 아이입니다. 또한 Deno는 귀하가 명시적으로 허용 한 것에 대해서만 귀하의 컴퓨터에 액세스 할 수 있습니다. 그것이 당신이 중요하게 생각하는 것이라면 node.js를 남겨 두십시오.


Deno 설치 


Shell:


curl -fsSL https://deno.land/x/install/install.sh | sh -s v0.38.0

Powershell (Windows):


iwr https://deno.land/x/install/install.ps1 -useb -outf install.ps1; .\install.ps1 v0.38.0

시스템에 Deno가 설치되어 있는지 확인


deno --help

그렇지 않은 경우 PATH에 추가해야 합니다. 자세한 내용은 여기


https://github.com/denoland/deno_install


첫 번째 Deno 파일을 만들 준비가 되었습니다!


touch api.ts

Deno 패키지는 npm과 다르게 반입됩니다.


이것이 Deno 서버를 가져 오는 방법입니다


import { serve } from "https://deno.land/std@v0.42.0/http/server.ts";

import { serve } from "https://deno.land/std@v0.42.0/http/server.ts";


응용 프로그램 작성에 관심이 없고 시작하고 실행하고 싶습니까? 🍦 tasty를 사용하여 예제 코드를 확인하십시오! 🍦 Deno 라이브러리 https://crunchskills.com/deno-http-web-server-example-like-express/


데이터베이스를 위한 SQLite


import { open, save } from "<https://deno.land/x/sqlite/mod.ts>";


Hello world, we are running a server! 


통합을 테스트하려면 항상 처음과 같이 간단한 것을 작성해야 합니다. 테스트 할 대상 서버에 배치하십시오.


const PORT = 8162;
const s = serve({ port: PORT });

console.log(` Listening on <http://localhost>:${PORT}/`);

for await (const req of s) {
  req.respond({ body: "Hello World\\n" });
}

이제 응용 프로그램을


Deno api —allow-net

넷 플래그 허용은 Deno가 네트워크 액세스를 허용 함


이것은 노드와 Deno의 힘의 또 다른 차이점입니다. 그것은 당신이 허용 한 것에 대해서만 액세스 할 수 있습니다.


그리고 localhost : 8162를 방문하십시오


페이지가 게재되는 것을 볼 수 있습니다!


Building blocks of an API 


요청 문자열로 더 놀아 볼 수 있습니다.


for await (const req of s) {
  const url = req.url;

  req.respond({ body: `Hi there, accessing from ${url}` });
}

이제 웹 사이트 내부의 모든 URL을 방문 할 수 있습니다.


localhost:8162/hello/world


req.url 변수는 모든 경로에 대한 것입니다.


물음표로 분할하여 URL 매개 변수와 실제 요청 URL을 제공합니다. 이를 통해 API가 데이터베이스에서 반환 해야 하는 레코드 수와 같은 것을 가질 수 있습니다.


const params = req.url.split("?");

요청에 이상한 것이 있는지 신속하게 확인할 수 있습니다.


 if (params.length > 2) {
    req.respond(bad_request);
    continue;
  }

즉, 사용자가 둘 이상의 물음표를 지정 했으므로 지원하지 않으므로 잘못된 요청 응답을 보내드립니다.


우리는 for 루프에 있으므로 오류 응답을 보낸 후에이 반복에서 다른 모든 코드를 계속 건너 뜁니다.


나중에 요청을 더 빨리 오류화 할 수 있도록 위에 선언 할 수 있습니다.


 const bad_request = { body: "Error 400 bad request.", status: 400 };

내장 된 urlSearchParams 클래스를 사용하여 검색 매개 변수를 가져올 수 있습니다.


const url = params[0];
const search_params = new URLSearchParams(params[1]);

데이터베이스 


이제 데이터베이스에 추가 할 준비가 되었습니다.


파일의 상단에 단순히 데이터베이스 파일을 열 수 있습니다


const db = await open("jobboard.db");

이것은 이제 Deno가 파일 쓰기에 액세스 할 수 있어야 한다는 것을 의미합니다. 이제 --allow-write 플래그로 시작해야 합니다.


Deno api --allow-net --allow-write

우리는 API를 사용하여 구인 게시를 얻고 추가 ​​할 것입니다.


테이블이 존재하지 않는 경우 해당 테이블을 만들 수 있습니다.


db.query(
  "CREATE TABLE IF NOT EXISTS jobs (id INTEGER PRIMARY KEY AUTOINCREMENT, created_at DATETIME, last_updated DATETIME , active BOOLEAN, company_id INTEGER, apply_url TEXT, job_title CHARACTER(140), details TEXT, pay_range TEXT)"
);
db.query(
  "CREATE TABLE IF NOT EXISTS companies (id INTEGER PRIMARY KEY AUTOINCREMENT,  logo_url TEXT, name CHARACTER(50), description TEXT, created_at DATETIME, last_updated DATETIME , active BOOLEAN)"
);

API 


이제 데이터베이스 설정이 완료되었습니다


볼 수 있는 경로와 채용 공고를 추가 할 수 있는 경로를 만들 수 있습니다


요청 응답 루프 내부의 URL에서 간단한 if 문 수행

 if (url == "/api/v1/jobs") {
}

그런 다음 html 쿼리 안에 count 매개 변수가 있는지 확인하십시오. 그리고 그렇다면 100보다 큰지 확인하십시오. 사용자가 한 번에 쿼리 할 수 ​​있도록 허용하는 최대 레코드는 어느 것입니까?


let count = 10; // base  
let request_count = search_params.get("count");
  if (request_count) {
    // enforcing max 100 record request
    if (parseInt(request_count) > 100) {
      req.respond(bad_request);
      continue;
    } else {
      count = parseInt(request_count);
    }
  }

회사 ID에서 두 테이블을 결합하여 job_title 및 회사 이름에 대한 데이터베이스를 조회하십시오. 회사는 여러 개의 직업 게시를 할 수 있고, 직업 게시는 하나의 회사 만 가질 수 있으므로 별도의 테이블에 보관합니다.


for (const [
      job_title,
      name,
    ] of db.query(
      "SELECT job_title,name FROM jobs JOIN companies ON company_id = companies.id ORDER BY jobs.id DESC LIMIT ?",
      [count]
    )) {
      results.push({ company_name: name, job_title: job_title });
    }

그리고 요청에 응답


req.respond({
      body: JSON.stringify(results),
      status: 200,
    });
    continue;

전체 경로의 코드 :


if (url == "/api/v1/jobs") {
    // base values
    let count = 10; // 10 records

    // safe type get count param
    let request_count = search_params.get("count");
    if (request_count) {
      // enforcing max 100 record request
      if (parseInt(request_count) > 100) {
        req.respond(bad_request);
        continue;
      } else {
        count = parseInt(request_count);
      }
    }
    const results = [];
    for (const [
      job_title,
      name,
    ] of db.query(
      "SELECT job_title,name FROM jobs JOIN companies ON company_id = companies.id ORDER BY jobs.id DESC LIMIT ?",
      [count]
    )) {
      results.push({ company_name: name, job_title: job_title });
    }
    req.respond({
      body: JSON.stringify(results),
      status: 200,
    });
    continue;
  }

이제 작업 보드에 작업을 추가하기 위해 비밀번호로 보호 된 경로를 구현해야 합니다.


 if (url == "/api/v1/jobs/add") {
}

우리는 암호를 빠르게 하드 코딩하고 나중에 Deno 파일 자체에서 더 복잡하게 만들 수 있습니다. 사용자가 URL URL 매개 변수를 제공 한 경우 유효한지 확인합니다.


let password_valid = false; // initialize to false
  const password = "supersecurepassword"; // set our pasword
  let request_password = search_params.get("pw"); // check the search param pw if its a valid password
  if (request_password) {
    if (request_password == password) {
      password_valid = true;
    } 
  }

그렇지 않으면 "허용되지 않음"으로 응답하고 연결을 닫습니다.


if (password_valid == false) {
      req.respond({
        body: "Not Allowed",
        status: 405,
      });
      continue;
    }

이제 유효성을 확인 했으므로 제공된 매개 변수에서 레코드를 안전하게 추가 할 수 있습니다. 주 – 회사 테이블 이름을 쿼리하지 않고 회사 ID를 알 수 있는 방법이 없습니다.


const apply_url = search_params.get("apply_url");
      const job_title = search_params.get("job_title");
      const company = search_params.get("company");
      const details = search_params.get("details");
      const pay_range = search_params.get("pay_range");
      let company_id;
      // To get the company ID we need to know if from the other table
      for (const [id] of db.query("SELECT id FROM companies WHERE name = ?", [
        company,
      ]))
        company_id = id;
			// companies are added in a different endpoint
      if (!company_id) {
        req.respond({ body: "Company Name not specified.", status: 400 });
        continue;
      }
			// write into database
      db.query(
        "INSERT INTO jobs (company_id, apply_url, job_title, details, pay_range,created_at,last_updated,active) VALUES (?,?,?,?,?,?,?,?)",
        [company_id, apply_url, job_title, details, pay_range, time, time, 1]
      );
      req.respond({
        status: 200,
      });

전체 비밀번호 보호 경로의 코드


if (url == "/api/v1/jobs/add") {
    let password_valid = false;
    const password = "supesecuredpassword";
    let request_password = search_params.get("pw");
    if (request_password) {
      if (request_password == password) {
        password_valid = true;
      }
    }
    if (password_valid == false) {
      req.respond({
        body: "Not Allowed",
        status: 405,
      });
      continue;
    }
    // validated can add
    else {
      const apply_url = search_params.get("apply_url");
      const job_title = search_params.get("job_title");
      const company = search_params.get("company");
      const details = search_params.get("details");
      const pay_range = search_params.get("pay_range");
      let company_id;
      // To get the company ID we need to know if from the other table
      for (const [id] of db.query("SELECT id FROM companies WHERE name = ?", [
        company,
      ]))
        company_id = id;
      // companies are added in a different endpoint
      if (!company_id) {
        req.respond({ body: "Company Name not specified.", status: 400 });
        continue;
      }
      // write into database
      db.query(
        "INSERT INTO jobs (company_id, apply_url, job_title, details, pay_range,created_at,last_updated,active) VALUES (?,?,?,?,?,?,?,?)",
        [company_id, apply_url, job_title, details, pay_range, time, time, 1]
      );
      req.respond({
        status: 200,
      });
			continue;
    }
  }

API 완료! 


파일 끝에서 데이터베이스를 닫으면 됩니다.


await save(db);
db.close()

암호로 보호 된 경로를 만들고 경로를 얻고 모든 쿼리 문자열에 액세스 할 수 있는 기능을 통해 원하는 모든 종류의 API를 만들 수 있습니다. 하늘이 한계입니다.


전체 API는 함께 


import { serve } from "https://deno.land/std@v0.42.0/http/server.ts";
import { open, save } from "https://deno.land/x/sqlite/mod.ts";

const PORT = 8162;

const db = await open("jobboard.db");
db.query(
  "CREATE TABLE IF NOT EXISTS jobs (id INTEGER PRIMARY KEY AUTOINCREMENT, created_at DATETIME, last_updated DATETIME , active BOOLEAN, company_id INTEGER, apply_url TEXT, job_title CHARACTER(140), details TEXT, pay_range TEXT)"
);
db.query(
  "CREATE TABLE IF NOT EXISTS companies (id INTEGER PRIMARY KEY AUTOINCREMENT,  logo_url TEXT, name CHARACTER(50), description TEXT, created_at DATETIME, last_updated DATETIME , active BOOLEAN)"
);

const time = new Date().getTime();

const s = serve({ port: PORT });

const bad_request = { body: "Error 400 bad request.", status: 400 };
console.log(` Listening on http://localhost:${PORT}/`);

for await (const req of s) {
  //split the request url
  const params = req.url.split("?");
  // error out on more than one ?
  if (params.length > 2) {
    req.respond(bad_request);
    continue;
  }

  // before ? is base url
  const url = params[0];
  // after the ? theres params
  const search_params = new URLSearchParams(params[1]);

  // get endpoint of jobs
  if (url == "/api/v1/jobs") {
    // base values
    let count = 10; // 10 records

    // safe type get count param
    let request_count = search_params.get("count");
    if (request_count) {
      // enforcing max 100 record request
      if (parseInt(request_count) > 100) {
        req.respond(bad_request);
        continue;
      } else {
        count = parseInt(request_count);
      }
    }
    const results = [];
    for (const [
      job_title,
      name,
    ] of db.query(
      "SELECT job_title,name FROM jobs JOIN companies ON company_id = companies.id ORDER BY jobs.id DESC LIMIT ?",
      [count]
    )) {
      results.push({ company_name: name, job_title: job_title });
    }
    req.respond({
      body: JSON.stringify(results),
      status: 200,
    });
    continue;
  }
  //write endpoint
  if (url == "/api/v1/jobs/add") {
    let password_valid = false;
    const password = "supersecurepassword";
    let request_password = search_params.get("pw");
    if (request_password) {
      if (request_password == password) {
        password_valid = true;
      }
    }
    if (password_valid == false) {
      req.respond({
        body: "Not Allowed",
        status: 405,
      });
      continue;
    }
    // validated can add
    else {
      const apply_url = search_params.get("apply_url");
      const job_title = search_params.get("job_title");
      const company = search_params.get("company");
      const details = search_params.get("details");
      const pay_range = search_params.get("pay_range");
      let company_id;
      // To get the company ID we need to know if from the other table
      for (const [id] of db.query("SELECT id FROM companies WHERE name = ?", [
        company,
      ]))
        company_id = id;
      // companies are added in a different endpoint
      if (!company_id) {
        req.respond({ body: "Company Name not specified.", status: 400 });
        continue;
      }
      // write into database
      db.query(
        "INSERT INTO jobs (company_id, apply_url, job_title, details, pay_range,created_at,last_updated,active) VALUES (?,?,?,?,?,?,?,?)",
        [company_id, apply_url, job_title, details, pay_range, time, time, 1]
      );
      req.respond({
        status: 200,
      });
      continue;
    }
  }
}
// Save and close connection
await save(db);
db.close();


페이지 정보

조회 20회 ]  작성일20-05-16 20:57

웹학교