Talking is cheap! Show me code!
Source address:
Deno Restful API With PostgreSql & TDD
Introduction to the
Deno is Ryan Dahl’s new project. The 1.0.0 release of Deno has caused quite a buzz in the development community, and it works in much the same way as Node.
In software development, TDD development can effectively improve project quality and development efficiency in order to develop maintainable, high-quality programs.
In this post, I’ll use Deno, Typescript, and PostgreSql to develop a user management API.
Deno & oak
The following are from the official website introduction, written very easy to understand, I do not need to read.
Deno
Deno is a simple, modern, and secure JavaScript and TypeScript runtime environment based on the V8 engine and built in the Rust programming language.
- Default security Settings. Unless explicitly enabled, there are no files, no network, and no access to the running environment.
- Built-in support for TypeScript.
- There is only a single executable file.
- Built-in utilities, such as dependency checker (deno Info) and code formatting tool (deno FMT).
- A set of audited (audited) standard modules to ensure compatibility with Deno: DENO. land/ STD.
oak
A middleware framework for Deno’s net server 🦕
Oak is a high-performance framework developed by referring to the design ideas of Node framework Koa, and its ideas of onion model middleware are also very convenient to use in development.
The target
Based on the above basic knowledge, we plan to develop a user management API platform; The backend simply provides add, delete, modify and check (CURD) operations about the user. So our main goal is to provide four interfaces to user Curds.
tool
He that would do a good job must sharpen his tools.
The development tools
VS Code
, Docker
Environmental tools
Deno
, Typescript
, Node
Note: Node is used to debug Deno
Basic Environment Information
My environment information is as follows:
❯ node -v
v12.13.0
❯ deno --version
deno 1.2.0
v8 8.5.216
typescript 3.9.2
❯ docker --version
Docker version 19.03.8, build afacb8b
Copy the code
Other information
type | version | note |
---|---|---|
PostgreSql | 12 | |
PGAdmin | latest |
The project structure
❯ tree -l 1 Deno-restful api-with-postgresql-tdd Deno-restful api-with-postgresql-tdd ├── github // Github action ├─ .vscode // debug and vscode configuration file ├── LICENSE // Repository LICENSE ├── readme.md // Project description, including database connection, │ ├── IaaS // Infrastructure, │ ├── httpClient // ├─ migration │ ├── deps.ts // Json // Check integrity and lock files, see: https://nugine.github.io/deno-manual-cn/linking_to_external_code/integrity_checking.html ├ ─ ─ a makefile / / to simplify the development need of the command line after the directory ├── SRC // ├─ tests // Directories, 5 filesCopy the code
The implementation process
First of all, I think it is not necessary to write the whole development process in text, so I will take the initial health and addUser(POST interface) as an example, other interfaces please refer to the code implementation.
Start the infrastructure (database) and initialize the tables
Starting the database
❯ make db CD./_resources/Iaas && docker-compose up -d Starting iaas_db_1... done Starting iaas_pgadmin_1 ... doneCopy the code
The loginpgadmin
In the default databasepostgres
In the newQuery
Perform the following operations to initialize the database
CREATE TABLE public."user"
(
id uuid NOT NULL,
username character varying(50) NOT NULL,
registration_date timestamp without time zone,
password character varying(20) NOT NULL,
deleted boolean
);
Copy the code
SRC Final directory
❯ tree -a-L 4 ├── Utils │ ├─ class.ts │ ├─ config.ts │ ├─ controllers │ ├── UserController. Ts │ ├─ health └ ─ ─ model │ └ ─ ─ IResponse. Ts ├ ─ ─ the entity │ └ ─ ─ the User. The ts ├ ─ ─ exception │ ├ ─ ─ InvalidedParamsException. Ts │ └ ─ ─ Ts │ ├── index.ts │ ├─ error. Ts │ ├─ logging. ts │ ├─ time Ts ├── Router-.ts ├─ Services ├── UserService.ts ├─ fetchResource. Ts 8 directories, 16 filesCopy the code
Before we start, let’s define some common structures and objects, such as response, exception, etc
// src/controllers/model/IResponse.ts
export default interface IResponse {
success: boolean; // Indicates whether the request was successfulmsg? :String; // Some log information when an error occurreddata? :any; // The data returned to the front end when the request succeeds
}
Copy the code
// src/entity/User.ts
export default interfaceIUser { id? :string; username? :string; password? :string; registrationDate? :string; deleted? :boolean;
}
export class User implements IUser {}
Copy the code
Exceptions are used to handle error situations. When we finally return the result to the user, we can’t return the exception to the user, but in a more friendly way. See SRC/Middlewares /error.ts for details.
// src/exception/InvalidedParamsException.ts
export default class InvalidedParamsException extends Error {
constructor(message: string) {
super(`Invalided parameters, please check, ${message}`); }}Copy the code
// src/exception/NotFoundException.ts
export default class NotFoundException extends Error {
constructor(message: string) {
super(`Not found resource, ${message}`); }}Copy the code
Dependency management
Deno doesn’t have package.json like Node to manage dependencies, because Deno’s dependencies are decentralized, using remote files as libraries, much like Golang.
I store the dependencies used in the system in the root directory deps.ts, and do an integrity check and lock file at the final commit to ensure that all my dependencies are the same as those of other collaborators.
First import the test-related dependencies used. Please add any dependencies you will use in future development to this file. I’ll list the important ones.
export {
assert,
equal,
} from "https://deno.land/std/testing/asserts.ts";
Copy the code
test-first
Now create a new test in the tests directory named index.test.ts and write a basic test to prove that the test and program work.
import { assert, equal } from ".. /deps.ts";
const { test } = Deno;
test("should work".(a)= > {
const universal = 42;
equal(42, universal);
assert(42 === universal);
});
Copy the code
Run the test for the first time
❯ make test
deno test --allow-env --allow-net -L info
Check file:///xxxx/deno-restful-api-with-postgresql-tdd/.deno.test.ts
running 1 tests
test should work ... ok (6ms)
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out (6ms)
Copy the code
Setting up test firmware
The common test information used in the tests is stored in the test firmware (testFixtures), which allows reuse in the tests and simplifies the code.
// tests/testFixtures.ts
export const TEST_PORT = 9000
Copy the code
The health interface
The Health interface serves as an exit for the system health check, which is very practical in the operation and maintenance platform. For this interface, all we need to do is return a status OK. Other cases can be ignored. Then the corresponding Todo should look like this:
When the system is accessed, the state of the system, OK, should be returned.
So, the test code looks like this:
import {
assertEquals,
Application,
Router,
} from ".. /.. /deps.ts";
import { getHealthInfo } from ".. /.. /src/controllers/health.ts";
import {TEST_PORT} from '.. /testFixtures.ts'
const { test } = Deno;
test("health check".async() = > {const expectResponse = {
success: true,
data: "Ok"};const app = new Application();
const router = new Router();
const abortController = new AbortController();
const { signal } = abortController;
router.get("/health".async ({ response }) => {
getHealthInfo({ response });
});
app.use(router.routes());
app.listen({ port: TEST_PORT, signal });
const response = await fetch(` http://127.0.0.1:${TEST_PORT}/health`);
assertEquals(response.ok, true);
const responseJSON = await response.json();
assertEquals(responseJSON, expectResponse);
abortController.abort();
});
Copy the code
given
- In the above code, we first declare our expected data structure, i.e
expectResponse
;- Then you create an application and a route,
- Create a controller that terminates the application and get the signal id from it,
- Next, add one to the route
health
Routing and its handler;- Then hang the route to the application;
- Listen for application ports and incoming application signals.
when
- Send a GET request to the started application
/health
;
then
- According to the result of the fetch to determine, see the received
response
Is it as expected and terminates the above application at the end.- At this point, if you run the test, you’re bound to get an error, and the solution is simply to implement it
getHealthInfo
The handler.
implementationgetHealthInfo
handler
Create health.ts under SRC /controller and implement the desired result in the simplest possible way:
// src/controllers/health.ts
import { Response, Status } from ".. /.. /deps.ts";
import IResponse from "./model/IResponse.ts";
export const getHealthInfo = ({ response }: { response: Response }) = > {
response.status = Status.OK;
const res: IResponse = {
success: true,
data: "Ok"}; response.body = res; };Copy the code
Run the test
Run the test command and the test passes.
❯ make test
deno test --allow-env --allow-net -L info
Check file://xxx/deno-restful-api-with-postgresql-tdd/.deno.test.ts
running 2 tests
test should work ... ok (6ms)
test health check ... ok (3ms)
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out (9ms)
Copy the code
So far, use TDD to complete the first simple health interface; However, the interface is not exposed, so you need to implement an application that exposes the interface in the SRC directory.
newconfig.ts
To make the application’s configuration management file
// src/config.ts
const env = Deno.env.toObject();
export const APP_HOST = env.APP_HOST || "127.0.0.1";
export const APP_PORT = parseInt(env.APP_PORT) || 8000;
export const API_VERSION = env.API_VERSION || "/api/v1";
Copy the code
The configuration file records the default host, port, and database information to start the application, and finally records the prefix of the application API.
To begin, you need to introduce the required libraries in deps.ts;
export {
Application,
Router,
Response,
Status,
Request,
RouteParams,
Context,
RouterContext,
helpers,
send,
} from "https://deno.land/x/oak/mod.ts";
Copy the code
New routingrouter.ts
, the introduction ofHeath.ts
Bind routes
// src/router.ts
import { Router } from ".. /deps.ts";
import { API_VERSION } from "./config.ts";
import { getHealthInfo } from "./controllers/health.ts";
const router = new Router();
router.prefix(API_VERSION);
router
.get("/health", getHealthInfo)
export default router;
Copy the code
newindex.ts
To build the application
// src/index.ts
import { Application, send } from ".. /deps.ts";
import { APP_HOST, APP_PORT } from "./config.ts";
import router from "./router.ts";
export const listenToServer = async (app: Application) => {
console.info(`Application started, and listen to ${APP_HOST}:${APP_PORT}`);
await app.listen({
hostname: APP_HOST,
port: APP_PORT,
secure: false}); };export function createApplication() :Promise<Application> {
const app = new Application();
app.use(router.routes());
return Promise.resolve(app);
}
if (import.meta.main) {
const app = await createApplication();
await listenToServer(app);
}
Copy the code
Start the application
In VSCode, you can use the F5 function key to quickly start the application, and you can start debugging in earlier versions of VSCode (below 1.47.2). You can also run the following command to start it;
❯ make dev deno run --allow-net -- allow-env. / SRC /index.ts The database link is successful! Application started, and Listen to 127.0.0.1:8000Copy the code
Call the interface test results
VS Code’s Rest Client plug-in was used here to assist in testing.
Request body
/ / _resources httpClient healthCheck. HTTP GET http://localhost:8000/api/v1/health HTTP / 1.1Copy the code
Request the results
HTTP/1.1 200 OK
content-length: 28
x-response-time: 0ms
content-type: application/json; charset=utf-8
{
"success": true."data": "Ok"
}
Copy the code
So far, the first interface has been completed, Oak provides application services, and has been tested by Unit Test and RestClient. Complete the Todo you started.
Adding a user interface (addUser
)
Adding users involves controllers, services, and Repositories, so we implement this interface in three steps.
Controller
The Controller is the control layer and provides services externally. Adding a user interface can add a user to the system, so the corresponding Todo is as follows:
- Enter a user name and password to return user information for a specific data structure
- Parameter must be entered, otherwise throw exception
- If an incorrect parameter is entered, an exception is thrown
Along the way, we need to mock third party dependencies.
Import the required dependencies and create userController.test. ts. UserService is required in the Coding process, but addUser is not required. The test is as follows:
// tests/controllers/UserController.test.ts
import {
stub,
Stub,
assertEquals,
v4,
assertThrowsAsync,
Application,
Router,
} from ".. /.. /deps.ts";
import UserController from ".. /.. /src/controllers/UserController.ts";
import IResponse from ".. /.. /src/controllers/model/IResponse.ts";
import UserService from ".. /.. /src/services/UserService.ts";
import IUser, { User } from ".. /.. /src/entity/User.ts";
import InvalidedParamsException from ".. /.. /src/exception/InvalidedParamsException.ts";
import {TEST_PORT} from '.. /testFixtures.ts'
const { test } = Deno;
const userId = v4.generate();
const registrationDate = (new Date()).toISOString();
const mockedUser: User = {
id: userId,
username: "username",
registrationDate,
deleted: false}; test("#addUser should return added user when add user".async() = > {const userService = new UserService();
const queryAllStub: Stub<UserService> = stub(userService, "addUser");
const expectResponse = {
success: true,
data: mockedUser,
};
queryAllStub.returns = [mockedUser];
const userController = new UserController();
userController.userService = userService;
const app = new Application();
const router = new Router();
const abortController = new AbortController();
const { signal } = abortController;
router.post("/users".async (context) => {
return await userController.addUser(context);
});
app.use(router.routes());
app.listen({ port: TEST_PORT, signal });
const response = await fetch(` http://127.0.0.1:${TEST_PORT}/users`, {
method: "POST",
body: "name=name&password=123",
headers: {
"Content-Type": "application/x-www-form-urlencoded",}}); assertEquals(response.ok,true);
const responseJSON = await response.json();
assertEquals(responseJSON, expectResponse);
abortController.abort();
queryAllStub.restore();
});
test("#addUser should throw exception about no params given no params when add user".async() = > {const userService = new UserService();
const queryAllStub: Stub<UserService> = stub(userService, "addUser");
queryAllStub.returns = [mockedUser];
const userController = new UserController();
userController.userService = userService;
const app = new Application();
const router = new Router();
const abortController = new AbortController();
const { signal } = abortController;
router.post("/users".async (context) => {
await assertThrowsAsync(
async() = > {await userController.addUser(context);
},
InvalidedParamsException,
"should given params: name ...",); abortController.abort(); queryAllStub.restore(); }); app.use(router.routes()); app.listen({ port: TEST_PORT, signal });const response = await fetch(` http://127.0.0.1:${TEST_PORT}/users`, {
method: "POST",
body: "",
headers: {
"Content-Type": "application/x-www-form-urlencoded",}});awaitresponse.body! .cancel(); }); test("#addUser should throw exception about no correct params given wrong params when add user".async() = > {const userService = new UserService();
const queryAllStub: Stub<UserService> = stub(userService, "addUser");
queryAllStub.returns = [mockedUser];
const userController = new UserController();
userController.userService = userService;
const app = new Application();
const router = new Router();
const abortController = new AbortController();
const { signal } = abortController;
router.post("/users".async (context) => {
await assertThrowsAsync(
async() = > {await userController.addUser(context);
},
InvalidedParamsException,
"should given param name and password",); abortController.abort(); queryAllStub.restore(); }); app.use(router.routes()); app.listen({ port: TEST_PORT, signal });const response = await fetch(` http://127.0.0.1:${TEST_PORT}/users`, {
method: "POST",
body: "wrong=params",
headers: {
"Content-Type": "application/x-www-form-urlencoded",}});awaitresponse.body! .cancel();Copy the code
The Controller layer calls the service; As a service, the controller is a third-party service, so mock the method of the service and pass it as a parameter. The following code is the application of the mock;
const userService = new UserService();
const queryAllStub: Stub<UserService> = stub(userService, "addUser");
const expectResponse = {
success: true,
data: mockedUser,
};
queryAllStub.returns = [mockedUser];
const userController = new UserController();
userController.userService = userService;
Copy the code
#addUser should return added user when add user is added.
given
- mock
UserService
, to the UserServiceaddUser
Method to pile and return a specific user structure;- Create a test service and set
UserController
Register with the POST interface/users
;
when
- Pass in the correct form parameter, using
fetch
requesthttp://127.0.0.1:9000/users
;
then
- The results obtained are judged, and the test application is interrupted, and the piling method is resumed.
#addUser should throw exception about no params given no params when add user; The given and when parameters in the first test do not look up much, but the body parameter is null; The most important difference is that this time the “THEN” is inside the “when”. Since the throw exception is thrown on the handler, the “THEN” decision needs to be placed on the handler. Deno’s assertThrowsAsync is used to catch and determine exceptions.
given
mock
UserService
, to the UserServiceaddUser
Method to pile and return a specific user structure;- Create a test service and set
UserController
Register with the POST interface/users
;
when
- to
body
Pass an empty parameter, withfetch
requesthttp://127.0.0.1:9000/users
;
then
then
Part in thegiven
Route processing based onhandler
, the exception is caught and determined, and then the test application is interrupted, and the piling method is resumed.
Run the test
❯ make test deno test --allow-env --allow-net -l info Check file:///xxx/deno-restful-api-with-postgresql-tdd/.deno.test.ts running 5 tests test should work ... ok (5ms) test UserController #addUser should return added user when add user ... ok (21ms) test UserController #addUser should throw exception about no params given no params when add user ... ok (4ms) test UserController #addUser should throw exception about no correct params given wrong params when add user . ok (3ms) test health check ... ok (4ms) test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out (37ms)Copy the code
Service
Service is a Service layer that provides services by combining other services and invoking the underlying data interface layer. For user addition, we only need to pass the user object to the Service that adds the user, and then the Repository handles it. So, our Todo corresponds to:
When the desired user information is passed in, the user information for a specific data structure is returned
Create userService.test. ts and import related dependencies.
// tests/services/UserService.test.ts
import {
stub,
Stub,
assertEquals,
v4,
} from ".. /.. /deps.ts";
import UserRepo from ".. /.. /src/repositories/userRepo.ts";
import UserService from ".. /.. /src/services/UserService.ts";
import IUser from ".. /.. /src/entity/User.ts";
const { test } = Deno;
test("UserService #addUser should return added user".async() = > {const parameter: IUser = {
username: "username",
password: "password"};const registrationDate = (new Date()).toISOString();
const id = v4.generate();
constmockedUser: IUser = { ... parameter, id, registrationDate, deleted:false};const userRepo = new UserRepo();
const createUserStub: Stub<UserRepo> = stub(userRepo, "create");
createUserStub.returns = [mockedUser];
const userService = new UserService();
userService.userRepo = userRepo;
assertEquals(await userService.addUser(parameter), mockedUser);
createUserStub.restore();
});
Copy the code
The code logic is simple and requires little explanation. To pass the test, write userService. ts and call the create method of Repository in userService. ts. Therefore, you also need to implement UserRepo simply by adding the create method.
// src/services/UserService.ts
import UserRepo from ".. /repositories/userRepo.ts";
import IUser from ".. /entity/User.ts";
export default class UserService {
constructor() {
this.userRepo = new UserRepo();
}
userRepo = new UserRepo();
async addUser(user: IUser) {
return await this.userRepo.create(user);
}
Copy the code
Run the test
❯ make test deno test --allow-env --allow-net -l info Check file:///xxx/deno-restful-api-with-postgresql-tdd/.deno.test.ts running 6 tests test should work ... ok (5ms) test UserController #addUser should return added user when add user ... ok (21ms) test UserController #addUser should throw exception about no params given no params when add user ... ok (4ms) test UserController #addUser should throw exception about no correct params given wrong params when add user . ok (3ms) test health check ... ok (4ms) test UserService #addUser should return added user ... ok (1ms) test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out (38ms)Copy the code
Repository
Repository typically interacts with a database to persist incoming data into the database. For the user interface, our requirement should be to store the incoming information in the format required by the database and return the result to the Service. Therefore, Todo is roughly as follows:
- Stores incoming users into the data deficit and returns information about a specific data structure
- Throw an exception if the basic field is missing in the parameter
The test is as follows:
// tests/repositories/UserRepo.test.ts
import {
stub,
Stub,
Client,
assertEquals,
v4,
assert,
assertMatch,
assertThrowsAsync,
} from ".. /.. /deps.ts";
import UserRepo from ".. /.. /src/repositories/userRepo.ts";
import client from ".. /.. /src/Utils/client.ts";
import IUser from ".. /.. /src/entity/User.ts";
import NotFoundException from ".. /.. /src/exception/NotFoundException.ts";
import InvalidedParamsException from ".. /.. /src/exception/InvalidedParamsException.ts";
const { test } = Deno;
test("UserRepo #create should return mocked User given username&password when create".async() = > {const queryStub: Stub<Client> = stub(client, "query");
const mockedQueryResult = {
rowCount: 1}; queryStub.returns = [mockedQueryResult];const parameter: IUser = {
username: "username",
password: "password"};const userRepo = new UserRepo();
userRepo.client = client;
const createdUserResult = awaituserRepo.create(parameter); assertEquals(createdUserResult.username, parameter.username); assertEquals(createdUserResult.password, parameter.password); assert(v4.validate(createdUserResult.id!) ); assertMatch( createdUserResult.registrationDate! .] / [\ d {4} - {2} [\ d] - [\ d] {2} T [\ d] {2}, {2} [d \] : [\ d] {2}. \ [d \] {1, 3} Z /,); queryStub.restore(); }); test("UserRepo #create should throw exception given no value for field when create".async() = > {const parameter: IUser = {
username: "",
password: ""};const userRepo = new UserRepo();
assertThrowsAsync(async() = > {await userRepo.create(parameter)
}, InvalidedParamsException,
"should supply valid username and password!")});Copy the code
Because the Repository layer deals with databases, it needs a Repository of processing tools that correspond to database operations. Here we expect to use PostgreSql’s own Client to perform database operations.
In the first test above, we mock the Client’s Query method and return the scheduled data. The create method of UserRepo is then called to determine whether the data field value of the returned data is consistent with the expected value.
Running the test will still fail, so let’s implement the test in the simplest way possible.
Import postgresQL-related dependencies
export { Client } from "https://deno.land/x/postgres/mod.ts";
Copy the code
And define database connection information
// src/config.ts
export const DB_HOST = env.DB_HOST || "localhost";
export const DB_USER = env.DB_USER || "postgres";
export const DB_PASSWORD = env.DB_PASSWORD || "0";
export const DB_DATABASE = env.DB_DATABASE || "postgres";
export const DB_PORT = env.DB_PORT ? parseInt(env.DB_PORT) : 5432;
Copy the code
Get the Client instance that connects to the database
// src/Utils/client.ts
import { Client } from ".. /.. /deps.ts";
import {
DB_HOST,
DB_DATABASE,
DB_PORT,
DB_USER,
DB_PASSWORD,
} from ".. /config.ts";
const client = new Client({
hostname: DB_HOST,
database: DB_DATABASE,
user: DB_USER,
password: DB_PASSWORD,
port: DB_PORT,
});
export default client;
Copy the code
The database should be connected when the application starts, so the client is introduced at index.ts and the connection is established and managed.
if (import.meta.main) {
+ await client.connect();
+ console.info("Database link successful!");
const app = await createApplication();
await listenToServer(app);
+ await client.end();
}
Copy the code
Restart tests
❯ make test deno test --allow-env --allow-net -l info Check file:///xxx/deno-restful-api-with-postgresql-tdd/.deno.test.ts running 8 tests test should work ... ok (2ms) test UserRepo #create should return mocked User given username&password when create ... ok (1ms) test UserRepo #create should throw exception given no value for field when create ... ok (1ms) test UserController #addUser should return added user when add user ... ok (14ms) test UserController #addUser should throw exception about no params given no params when add user ... ok (4ms) test UserController #addUser should throw exception about no correct params given wrong params when add user . ok (2ms) test health check ... ok (3ms) test UserService #addUser should return added user ... ok (1ms) test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out (28ms)Copy the code
Request body
The request is validated by RestClient; Now start the application and send the following request;
/ / _resources httpClient/addUser. HTTP POST HTTP / 1.1 the content-type: http://localhost:8000/api/v1/users application/x-www-form-urlencoded name=foo&password=123Copy the code
Request the results
HTTP/1.1 201 Created
content-length: 149
x-response-time: 34ms
content-type: application/json; charset=utf-8
{
"success": true."data": {
"username": "foo"."password": "123"."id": "7aea0bb7-e0bc-4f1f-a516-3a43f4e30fb6"."registrationDate": "The 2020-07-27 T14: he. 140 z"}}Copy the code
Exceptions can be created by themselves, which will not be demonstrated here, so as to complete the user-added interface.
packaging
According to the above steps, we can complete the query of a single user (GET:/users/: ID), query all users (GET:/users) and DELETE (DELETE:/users/: ID) interface, fast and efficient. When we finished testing and interfaces, using deno’s command-line tools, we were able to package the entire project as a.js file;
❯ make bundle
mkdir dist
deno bundle src/index.ts dist/platform.js
Bundle file:///xxx/deno-restful-api-with-postgresql-tdd/src/index.ts
Emit "dist/platform.js" (856.11 KB)
Copy the code
For backend applications developed with NodeJs, the dreaded node_modules dependency can be a problem when packaging them. Most NodeJs back-end applications simply update environment variables and deploy them in production. Developers don’t write much of a project file, and the node_modules the application depends on are often tens or even hundreds of times as many as the project file. Then Deno solved the problem very well.
Start the application
If necessary, copy the packaged.js to the target directory. As long as there is a Deno environment, we can start the application directly.
❯ make start APP_PORT=1234 deno run --allow-net --allow-env./dist/platform.js The database link is successful! Application started, and Listen to 127.0.0.1:1234Copy the code
Take the whole mess
Through learning Deno, have some experience;
- Compatible browser
API
.Deno
Engineering can be usedJavascript
andTypescript
Programming, greatly reducing the cognitive complexity and learning difficulty; - If you are using
Typescript
Development, then will avoidDynamic one time cool, reconstruction crematorium
“, so it’s recommendedTypescript
To write applications; - Decentralized repositories, distributed as single files, in collaborative development, in order to unify library versions, need to verify dependent versions,
Deno
Provides the ability to generatelock.json
To ensure version dependencies between different collaborators; - .
Finally, thanks to Haimen and Yile for proofreading and guidance. With their help, I successfully completed this blog post.
Reference
- Source: https://github.com/guzhongren/deno-restful-api-with-postgresql-tdd
- Blog: https://guzhongren.github.io/
- Figure bed: https://sm.ms/
- Denoland: https://deno.land/
- VS Code: https://code.visualstudio.com/
- Docker: https://www.docker.com/
- Typescript: https://www.typescriptlang.org/
- Node: https://nodejs.org/
- mock: https://github.com/udibo/mock
If you find it useful, you are welcome to contact or tip.
🏆 technology project phase I | talk about Deno some thing…