Hurtig CRUD-oprettelse med nest, @nestjsx/crud og TestMace

Hurtig CRUD-oprettelse med nest, @nestjsx/crud og TestMace

I øjeblikket er REST API blevet en standard for webapplikationsudvikling, hvilket gør det muligt at opdele udvikling i uafhængige dele. Forskellige populære rammer såsom Angular, React, Vue og andre bruges i øjeblikket til UI. Backend-udviklere kan vælge mellem en bred vifte af sprog og rammer. I dag vil jeg gerne tale om sådan en ramme som NestJS. Vi er inde TestMace Vi bruger det aktivt til interne projekter. Brug af rede og pakke @nestjsx/crud, vil vi oprette en simpel CRUD-applikation.

Hvorfor NestJS

For nylig er der dukket en hel del backend-rammer op i JavaScript-fællesskabet. Og hvis de med hensyn til funktionalitet giver lignende muligheder som Nest, så vinder den helt sikkert i én ting - dette er arkitekturen. Følgende NestJS-funktioner giver dig mulighed for at skabe industrielle applikationer og skalere udvikling til store teams:

  • ved at bruge TypeScript som det primære udviklingssprog. Selvom NestJS understøtter JavaScript, virker nogle funktioner muligvis ikke, især hvis vi taler om tredjepartspakker;
  • tilstedeværelsen af ​​en DI-beholder, som giver dig mulighed for at skabe løst koblede komponenter;
  • Funktionaliteten af ​​selve rammen er opdelt i uafhængige udskiftelige komponenter. For eksempel kan den under emhætten som ramme bruges som ExpressOg fastgøre, for at arbejde med databasen, nest out of the box giver bindinger til typorm, desmerdyr, fortsættelse;
  • NestJS er platformagnostisk og understøtter REST, GraphQL, Websockets, gRPC osv.

Selve rammeværket er inspireret af Angular frontend-rammeværket og har konceptuelt meget til fælles med det.

Installation af NestJS og implementering af projektet

Reden indeholder en pakke reden/cli, som giver dig mulighed for hurtigt at implementere en grundlæggende applikationsramme. Lad os installere denne pakke globalt:

npm install --global @nest/cli

Efter installationen genererer vi den grundlæggende ramme for vores applikation med navnet rede-rest. Dette gøres ved hjælp af kommandoen nest new nest-rest.

rede ny rede-hvile

dmitrii@dmitrii-HP-ZBook-17-G3:~/projects $ nest new nest-rest
  We will scaffold your app in a few seconds..

CREATE /nest-rest/.prettierrc (51 bytes)
CREATE /nest-rest/README.md (3370 bytes)
CREATE /nest-rest/nest-cli.json (84 bytes)
CREATE /nest-rest/nodemon-debug.json (163 bytes)
CREATE /nest-rest/nodemon.json (67 bytes)
CREATE /nest-rest/package.json (1805 bytes)
CREATE /nest-rest/tsconfig.build.json (97 bytes)
CREATE /nest-rest/tsconfig.json (325 bytes)
CREATE /nest-rest/tslint.json (426 bytes)
CREATE /nest-rest/src/app.controller.spec.ts (617 bytes)
CREATE /nest-rest/src/app.controller.ts (274 bytes)
CREATE /nest-rest/src/app.module.ts (249 bytes)
CREATE /nest-rest/src/app.service.ts (142 bytes)
CREATE /nest-rest/src/main.ts (208 bytes)
CREATE /nest-rest/test/app.e2e-spec.ts (561 bytes)
CREATE /nest-rest/test/jest-e2e.json (183 bytes)

? Which package manager would you ️ to use? yarn
 Installation in progress... 

  Successfully created project nest-rest
  Get started with the following commands:

$ cd nest-rest
$ yarn run start

                          Thanks for installing Nest 
                 Please consider donating to our open collective
                        to help us maintain this package.

                 Donate: https://opencollective.com/nest

Vi vælger garn som vores pakkeansvarlige.
På dette tidspunkt kan du starte serveren med kommandoen npm start og går til adressen http://localhost:3000 du kan se hovedsiden. Det er dog ikke derfor, vi er samlet her, og vi går videre.

Opsætning af arbejde med databasen

Jeg valgte PostrgreSQL som DBMS for denne artikel. Der er ingen uenighed om smag; efter min mening er dette det mest modne DBMS, der har alle de nødvendige muligheder. Som allerede nævnt giver Nest integration med forskellige pakker til at arbejde med databaser. Fordi Da mit valg faldt på PostgreSQL, ville det være logisk at vælge TypeORM som en ORM. Lad os installere de nødvendige pakker til integration med databasen:

yarn add typeorm @nestjs/typeorm pg

I rækkefølge, hvad hver pakke skal bruges til:

  1. typeorm - en pakke direkte fra selve ORM'en;
  2. @nestjs/typeorm - TypeORM-pakke til NestJS. Tilføjer moduler til import til projektmoduler samt et sæt hjælperdekoratører;
  3. pg - driver til at arbejde med PostgreSQL.

Okay, pakkerne er installeret, nu skal du starte selve databasen. For at implementere databasen vil jeg bruge docker-compose.yml med følgende indhold:

havnearbeider-compose.yml

version: '3.1'

services:
  db:
    image: postgres:11.2
    restart: always
    environment:
      POSTGRES_PASSWORD: example
    volumes:
      - ../db:/var/lib/postgresql/data
      - ./postgresql.conf:/etc/postgresql/postgresql.conf
    ports:
      - 5432:5432
  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080

Som du kan se, konfigurerer denne fil lanceringen af ​​2 containere:

  1. db er en container, der direkte indeholder databasen. I vores tilfælde bruges postgresql version 11.2;
  2. adminer - databaseadministrator. Giver en webgrænseflade til visning og styring af databasen.

For at arbejde med tcp-forbindelser tilføjede jeg følgende konfiguration.

postgresql.conf

# -----------------------------
# PostgreSQL configuration file
# -----------------------------
#
# This file consists of lines of the form:
#
#   name = value
#
# (The "=" is optional.)  Whitespace may be used.  Comments are introduced with
# "#" anywhere on a line.  The complete list of parameter names and allowed
# values can be found in the PostgreSQL documentation.
#
# The commented-out settings shown in this file represent the default values.
# Re-commenting a setting is NOT sufficient to revert it to the default value;
# you need to reload the server.
#
# This file is read on server startup and when the server receives a SIGHUP
# signal.  If you edit the file on a running system, you have to SIGHUP the
# server for the changes to take effect, run "pg_ctl reload", or execute
# "SELECT pg_reload_conf()".  Some parameters, which are marked below,
# require a server shutdown and restart to take effect.
#
# Any parameter can also be given as a command-line option to the server, e.g.,
# "postgres -c log_connections=on".  Some parameters can be changed at run time
# with the "SET" SQL command.
#
# Memory units:  kB = kilobytes        Time units:  ms  = milliseconds
#                MB = megabytes                     s   = seconds
#                GB = gigabytes                     min = minutes
#                TB = terabytes                     h   = hours
#                                                   d   = days
#------------------------------------------------------------------------------
# FILE LOCATIONS
#------------------------------------------------------------------------------
# The default values of these variables are driven from the -D command-line
# option or PGDATA environment variable, represented here as ConfigDir.
#data_directory = 'ConfigDir'       # use data in another directory
# (change requires restart)
#hba_file = 'ConfigDir/pg_hba.conf' # host-based authentication file
# (change requires restart)
#ident_file = 'ConfigDir/pg_ident.conf' # ident configuration file
# (change requires restart)
# If external_pid_file is not explicitly set, no extra PID file is written.
#external_pid_file = ''         # write an extra PID file
# (change requires restart)
#------------------------------------------------------------------------------
# CONNECTIONS AND AUTHENTICATION
#------------------------------------------------------------------------------
# - Connection Settings -
listen_addresses = '*'
#listen_addresses = 'localhost'     # what IP address(es) to listen on;
# comma-separated list of addresses;
# defaults to 'localhost'; use '*' for all
# (change requires restart)
#port = 5432                # (change requires restart)
#max_connections = 100          # (change requires restart)
#superuser_reserved_connections = 3 # (change requires restart)
#unix_socket_directories = '/tmp'   # comma-separated list of directories
# (change requires restart)
#unix_socket_group = ''         # (change requires restart)
#unix_socket_permissions = 0777     # begin with 0 to use octal notation
# (change requires restart)
#bonjour = off              # advertise server via Bonjour
# (change requires restart)
#bonjour_name = ''          # defaults to the computer name
# (change requires restart)
# - TCP Keepalives -
# see "man 7 tcp" for details
#tcp_keepalives_idle = 0        # TCP_KEEPIDLE, in seconds;
# 0 selects the system default
#tcp_keepalives_interval = 0        # TCP_KEEPINTVL, in seconds;
# 0 selects the system default
#tcp_keepalives_count = 0       # TCP_KEEPCNT;
# 0 selects the system default
# - Authentication -
#authentication_timeout = 1min      # 1s-600s
#password_encryption = md5      # md5 or scram-sha-256
#db_user_namespace = off
# GSSAPI using Kerberos
#krb_server_keyfile = ''
#krb_caseins_users = off
# - SSL -
#ssl = off
#ssl_ca_file = ''
#ssl_cert_file = 'server.crt'
#ssl_crl_file = ''
#ssl_key_file = 'server.key'
#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
#ssl_prefer_server_ciphers = on
#ssl_ecdh_curve = 'prime256v1'
#ssl_min_protocol_version = 'TLSv1'
#ssl_max_protocol_version = ''
#ssl_dh_params_file = ''
#ssl_passphrase_command = ''
#ssl_passphrase_command_supports_reload = off
#------------------------------------------------------------------------------
# RESOURCE USAGE (except WAL)
#------------------------------------------------------------------------------
# - Memory -
#shared_buffers = 32MB          # min 128kB
# (change requires restart)
#huge_pages = try           # on, off, or try
# (change requires restart)
#temp_buffers = 8MB         # min 800kB
#max_prepared_transactions = 0      # zero disables the feature
# (change requires restart)
# Caution: it is not advisable to set max_prepared_transactions nonzero unless
# you actively intend to use prepared transactions.
#work_mem = 4MB             # min 64kB
#maintenance_work_mem = 64MB        # min 1MB
#autovacuum_work_mem = -1       # min 1MB, or -1 to use maintenance_work_mem
#max_stack_depth = 2MB          # min 100kB
#shared_memory_type = mmap      # the default is the first option
# supported by the operating system:
#   mmap
#   sysv
#   windows
# (change requires restart)
#dynamic_shared_memory_type = posix # the default is the first option
# supported by the operating system:
#   posix
#   sysv
#   windows
#   mmap
# (change requires restart)
# - Disk -
#temp_file_limit = -1           # limits per-process temp file space
# in kB, or -1 for no limit
# - Kernel Resources -
#max_files_per_process = 1000       # min 25
# (change requires restart)
# - Cost-Based Vacuum Delay -
#vacuum_cost_delay = 0          # 0-100 milliseconds (0 disables)
#vacuum_cost_page_hit = 1       # 0-10000 credits
#vacuum_cost_page_miss = 10     # 0-10000 credits
#vacuum_cost_page_dirty = 20        # 0-10000 credits
#vacuum_cost_limit = 200        # 1-10000 credits
# - Background Writer -
#bgwriter_delay = 200ms         # 10-10000ms between rounds
#bgwriter_lru_maxpages = 100        # max buffers written/round, 0 disables
#bgwriter_lru_multiplier = 2.0      # 0-10.0 multiplier on buffers scanned/round
#bgwriter_flush_after = 0       # measured in pages, 0 disables
# - Asynchronous Behavior -
#effective_io_concurrency = 1       # 1-1000; 0 disables prefetching
#max_worker_processes = 8       # (change requires restart)
#max_parallel_maintenance_workers = 2   # taken from max_parallel_workers
#max_parallel_workers_per_gather = 2    # taken from max_parallel_workers
#parallel_leader_participation = on
#max_parallel_workers = 8       # maximum number of max_worker_processes that
# can be used in parallel operations
#old_snapshot_threshold = -1        # 1min-60d; -1 disables; 0 is immediate
# (change requires restart)
#backend_flush_after = 0        # measured in pages, 0 disables
#------------------------------------------------------------------------------
# WRITE-AHEAD LOG
#------------------------------------------------------------------------------
# - Settings -
#wal_level = replica            # minimal, replica, or logical
# (change requires restart)
#fsync = on             # flush data to disk for crash safety
# (turning this off can cause
# unrecoverable data corruption)
#synchronous_commit = on        # synchronization level;
# off, local, remote_write, remote_apply, or on
#wal_sync_method = fsync        # the default is the first option
# supported by the operating system:
#   open_datasync
#   fdatasync (default on Linux)
#   fsync
#   fsync_writethrough
#   open_sync
#full_page_writes = on          # recover from partial page writes
#wal_compression = off          # enable compression of full-page writes
#wal_log_hints = off            # also do full page writes of non-critical updates
# (change requires restart)
#wal_buffers = -1           # min 32kB, -1 sets based on shared_buffers
# (change requires restart)
#wal_writer_delay = 200ms       # 1-10000 milliseconds
#wal_writer_flush_after = 1MB       # measured in pages, 0 disables
#commit_delay = 0           # range 0-100000, in microseconds
#commit_siblings = 5            # range 1-1000
# - Checkpoints -
#checkpoint_timeout = 5min      # range 30s-1d
#max_wal_size = 1GB
#min_wal_size = 80MB
#checkpoint_completion_target = 0.5 # checkpoint target duration, 0.0 - 1.0
#checkpoint_flush_after = 0     # measured in pages, 0 disables
#checkpoint_warning = 30s       # 0 disables
# - Archiving -
#archive_mode = off     # enables archiving; off, on, or always
# (change requires restart)
#archive_command = ''       # command to use to archive a logfile segment
# placeholders: %p = path of file to archive
#               %f = file name only
# e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f'
#archive_timeout = 0        # force a logfile segment switch after this
# number of seconds; 0 disables
# - Archive Recovery -
# These are only used in recovery mode.
#restore_command = ''       # command to use to restore an archived logfile segment
# placeholders: %p = path of file to restore
#               %f = file name only
# e.g. 'cp /mnt/server/archivedir/%f %p'
# (change requires restart)
#archive_cleanup_command = ''   # command to execute at every restartpoint
#recovery_end_command = ''  # command to execute at completion of recovery
# - Recovery Target -
# Set these only when performing a targeted recovery.
#recovery_target = ''       # 'immediate' to end recovery as soon as a
# consistent state is reached
# (change requires restart)
#recovery_target_name = ''  # the named restore point to which recovery will proceed
# (change requires restart)
#recovery_target_time = ''  # the time stamp up to which recovery will proceed
# (change requires restart)
#recovery_target_xid = ''   # the transaction ID up to which recovery will proceed
# (change requires restart)
#recovery_target_lsn = ''   # the WAL LSN up to which recovery will proceed
# (change requires restart)
#recovery_target_inclusive = on # Specifies whether to stop:
# just after the specified recovery target (on)
# just before the recovery target (off)
# (change requires restart)
#recovery_target_timeline = 'latest'    # 'current', 'latest', or timeline ID
# (change requires restart)
#recovery_target_action = 'pause'   # 'pause', 'promote', 'shutdown'
# (change requires restart)
#------------------------------------------------------------------------------
# REPLICATION
#------------------------------------------------------------------------------
# - Sending Servers -
# Set these on the master and on any standby that will send replication data.
#max_wal_senders = 10       # max number of walsender processes
# (change requires restart)
#wal_keep_segments = 0      # in logfile segments; 0 disables
#wal_sender_timeout = 60s   # in milliseconds; 0 disables
#max_replication_slots = 10 # max number of replication slots
# (change requires restart)
#track_commit_timestamp = off   # collect timestamp of transaction commit
# (change requires restart)
# - Master Server -
# These settings are ignored on a standby server.
#synchronous_standby_names = '' # standby servers that provide sync rep
# method to choose sync standbys, number of sync standbys,
# and comma-separated list of application_name
# from standby(s); '*' = all
#vacuum_defer_cleanup_age = 0   # number of xacts by which cleanup is delayed
# - Standby Servers -
# These settings are ignored on a master server.
#primary_conninfo = ''          # connection string to sending server
# (change requires restart)
#primary_slot_name = ''         # replication slot on sending server
# (change requires restart)
#promote_trigger_file = ''      # file name whose presence ends recovery
#hot_standby = on           # "off" disallows queries during recovery
# (change requires restart)
#max_standby_archive_delay = 30s    # max delay before canceling queries
# when reading WAL from archive;
# -1 allows indefinite delay
#max_standby_streaming_delay = 30s  # max delay before canceling queries
# when reading streaming WAL;
# -1 allows indefinite delay
#wal_receiver_status_interval = 10s # send replies at least this often
# 0 disables
#hot_standby_feedback = off     # send info from standby to prevent
# query conflicts
#wal_receiver_timeout = 60s     # time that receiver waits for
# communication from master
# in milliseconds; 0 disables
#wal_retrieve_retry_interval = 5s   # time to wait before retrying to
# retrieve WAL after a failed attempt
#recovery_min_apply_delay = 0       # minimum delay for applying changes during recovery
# - Subscribers -
# These settings are ignored on a publisher.
#max_logical_replication_workers = 4    # taken from max_worker_processes
# (change requires restart)
#max_sync_workers_per_subscription = 2  # taken from max_logical_replication_workers
#------------------------------------------------------------------------------
# QUERY TUNING
#------------------------------------------------------------------------------
# - Planner Method Configuration -
#enable_bitmapscan = on
#enable_hashagg = on
#enable_hashjoin = on
#enable_indexscan = on
#enable_indexonlyscan = on
#enable_material = on
#enable_mergejoin = on
#enable_nestloop = on
#enable_parallel_append = on
#enable_seqscan = on
#enable_sort = on
#enable_tidscan = on
#enable_partitionwise_join = off
#enable_partitionwise_aggregate = off
#enable_parallel_hash = on
#enable_partition_pruning = on
# - Planner Cost Constants -
#seq_page_cost = 1.0            # measured on an arbitrary scale
#random_page_cost = 4.0         # same scale as above
#cpu_tuple_cost = 0.01          # same scale as above
#cpu_index_tuple_cost = 0.005       # same scale as above
#cpu_operator_cost = 0.0025     # same scale as above
#parallel_tuple_cost = 0.1      # same scale as above
#parallel_setup_cost = 1000.0   # same scale as above
#jit_above_cost = 100000        # perform JIT compilation if available
# and query more expensive than this;
# -1 disables
#jit_inline_above_cost = 500000     # inline small functions if query is
# more expensive than this; -1 disables
#jit_optimize_above_cost = 500000   # use expensive JIT optimizations if
# query is more expensive than this;
# -1 disables
#min_parallel_table_scan_size = 8MB
#min_parallel_index_scan_size = 512kB
#effective_cache_size = 4GB
# - Genetic Query Optimizer -
#geqo = on
#geqo_threshold = 12
#geqo_effort = 5            # range 1-10
#geqo_pool_size = 0         # selects default based on effort
#geqo_generations = 0           # selects default based on effort
#geqo_selection_bias = 2.0      # range 1.5-2.0
#geqo_seed = 0.0            # range 0.0-1.0
# - Other Planner Options -
#default_statistics_target = 100    # range 1-10000
#constraint_exclusion = partition   # on, off, or partition
#cursor_tuple_fraction = 0.1        # range 0.0-1.0
#from_collapse_limit = 8
#join_collapse_limit = 8        # 1 disables collapsing of explicit
# JOIN clauses
#force_parallel_mode = off
#jit = on               # allow JIT compilation
#plan_cache_mode = auto         # auto, force_generic_plan or
# force_custom_plan
#------------------------------------------------------------------------------
# REPORTING AND LOGGING
#------------------------------------------------------------------------------
# - Where to Log -
#log_destination = 'stderr'     # Valid values are combinations of
# stderr, csvlog, syslog, and eventlog,
# depending on platform.  csvlog
# requires logging_collector to be on.
# This is used when logging to stderr:
#logging_collector = off        # Enable capturing of stderr and csvlog
# into log files. Required to be on for
# csvlogs.
# (change requires restart)
# These are only used if logging_collector is on:
#log_directory = 'log'          # directory where log files are written,
# can be absolute or relative to PGDATA
#log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'    # log file name pattern,
# can include strftime() escapes
#log_file_mode = 0600           # creation mode for log files,
# begin with 0 to use octal notation
#log_truncate_on_rotation = off     # If on, an existing log file with the
# same name as the new log file will be
# truncated rather than appended to.
# But such truncation only occurs on
# time-driven rotation, not on restarts
# or size-driven rotation.  Default is
# off, meaning append to existing files
# in all cases.
#log_rotation_age = 1d          # Automatic rotation of logfiles will
# happen after that time.  0 disables.
#log_rotation_size = 10MB       # Automatic rotation of logfiles will
# happen after that much log output.
# 0 disables.
# These are relevant when logging to syslog:
#syslog_facility = 'LOCAL0'
#syslog_ident = 'postgres'
#syslog_sequence_numbers = on
#syslog_split_messages = on
# This is only relevant when logging to eventlog (win32):
# (change requires restart)
#event_source = 'PostgreSQL'
# - When to Log -
#log_min_messages = warning     # values in order of decreasing detail:
#   debug5
#   debug4
#   debug3
#   debug2
#   debug1
#   info
#   notice
#   warning
#   error
#   log
#   fatal
#   panic
#log_min_error_statement = error    # values in order of decreasing detail:
#   debug5
#   debug4
#   debug3
#   debug2
#   debug1
#   info
#   notice
#   warning
#   error
#   log
#   fatal
#   panic (effectively off)
#log_min_duration_statement = -1    # logs statements and their durations
# according to log_statement_sample_rate. -1 is disabled,
# 0 logs all statement, > 0 logs only statements running at
# least this number of milliseconds.
#log_statement_sample_rate = 1  # Fraction of logged statements over
# log_min_duration_statement. 1.0 logs all statements,
# 0 never logs.
# - What to Log -
#debug_print_parse = off
#debug_print_rewritten = off
#debug_print_plan = off
#debug_pretty_print = on
#log_checkpoints = off
#log_connections = off
#log_disconnections = off
#log_duration = off
#log_error_verbosity = default      # terse, default, or verbose messages
#log_hostname = off
#log_line_prefix = '%m [%p] '       # special values:
#   %a = application name
#   %u = user name
#   %d = database name
#   %r = remote host and port
#   %h = remote host
#   %p = process ID
#   %t = timestamp without milliseconds
#   %m = timestamp with milliseconds
#   %n = timestamp with milliseconds (as a Unix epoch)
#   %i = command tag
#   %e = SQL state
#   %c = session ID
#   %l = session line number
#   %s = session start timestamp
#   %v = virtual transaction ID
#   %x = transaction ID (0 if none)
#   %q = stop here in non-session
#        processes
#   %% = '%'
# e.g. '<%u%%%d> '
#log_lock_waits = off           # log lock waits >= deadlock_timeout
#log_statement = 'none'         # none, ddl, mod, all
#log_replication_commands = off
#log_temp_files = -1            # log temporary files equal or larger
# than the specified size in kilobytes;
# -1 disables, 0 logs all temp files
#log_timezone = 'GMT'
#------------------------------------------------------------------------------
# PROCESS TITLE
#------------------------------------------------------------------------------
#cluster_name = ''          # added to process titles if nonempty
# (change requires restart)
#update_process_title = on
#------------------------------------------------------------------------------
# STATISTICS
#------------------------------------------------------------------------------
# - Query and Index Statistics Collector -
#track_activities = on
#track_counts = on
#track_io_timing = off
#track_functions = none         # none, pl, all
#track_activity_query_size = 1024   # (change requires restart)
#stats_temp_directory = 'pg_stat_tmp'
# - Monitoring -
#log_parser_stats = off
#log_planner_stats = off
#log_executor_stats = off
#log_statement_stats = off
#------------------------------------------------------------------------------
# AUTOVACUUM
#------------------------------------------------------------------------------
#autovacuum = on            # Enable autovacuum subprocess?  'on'
# requires track_counts to also be on.
#log_autovacuum_min_duration = -1   # -1 disables, 0 logs all actions and
# their durations, > 0 logs only
# actions running at least this number
# of milliseconds.
#autovacuum_max_workers = 3     # max number of autovacuum subprocesses
# (change requires restart)
#autovacuum_naptime = 1min      # time between autovacuum runs
#autovacuum_vacuum_threshold = 50   # min number of row updates before
# vacuum
#autovacuum_analyze_threshold = 50  # min number of row updates before
# analyze
#autovacuum_vacuum_scale_factor = 0.2   # fraction of table size before vacuum
#autovacuum_analyze_scale_factor = 0.1  # fraction of table size before analyze
#autovacuum_freeze_max_age = 200000000  # maximum XID age before forced vacuum
# (change requires restart)
#autovacuum_multixact_freeze_max_age = 400000000    # maximum multixact age
# before forced vacuum
# (change requires restart)
#autovacuum_vacuum_cost_delay = 2ms # default vacuum cost delay for
# autovacuum, in milliseconds;
# -1 means use vacuum_cost_delay
#autovacuum_vacuum_cost_limit = -1  # default vacuum cost limit for
# autovacuum, -1 means use
# vacuum_cost_limit
#------------------------------------------------------------------------------
# CLIENT CONNECTION DEFAULTS
#------------------------------------------------------------------------------
# - Statement Behavior -
#client_min_messages = notice       # values in order of decreasing detail:
#   debug5
#   debug4
#   debug3
#   debug2
#   debug1
#   log
#   notice
#   warning
#   error
#search_path = '"$user", public'    # schema names
#row_security = on
#default_tablespace = ''        # a tablespace name, '' uses the default
#temp_tablespaces = ''          # a list of tablespace names, '' uses
# only default tablespace
#check_function_bodies = on
#default_transaction_isolation = 'read committed'
#default_transaction_read_only = off
#default_transaction_deferrable = off
#session_replication_role = 'origin'
#statement_timeout = 0          # in milliseconds, 0 is disabled
#lock_timeout = 0           # in milliseconds, 0 is disabled
#idle_in_transaction_session_timeout = 0    # in milliseconds, 0 is disabled
#vacuum_freeze_min_age = 50000000
#vacuum_freeze_table_age = 150000000
#vacuum_multixact_freeze_min_age = 5000000
#vacuum_multixact_freeze_table_age = 150000000
#vacuum_cleanup_index_scale_factor = 0.1    # fraction of total number of tuples
# before index cleanup, 0 always performs
# index cleanup
#bytea_output = 'hex'           # hex, escape
#xmlbinary = 'base64'
#xmloption = 'content'
#gin_fuzzy_search_limit = 0
#gin_pending_list_limit = 4MB
# - Locale and Formatting -
#datestyle = 'iso, mdy'
#intervalstyle = 'postgres'
#timezone = 'GMT'
#timezone_abbreviations = 'Default'     # Select the set of available time zone
# abbreviations.  Currently, there are
#   Default
#   Australia (historical usage)
#   India
# You can create your own file in
# share/timezonesets/.
#extra_float_digits = 1         # min -15, max 3; any value >0 actually
# selects precise output mode
#client_encoding = sql_ascii        # actually, defaults to database
# encoding
# These settings are initialized by initdb, but they can be changed.
#lc_messages = 'C'          # locale for system error message
# strings
#lc_monetary = 'C'          # locale for monetary formatting
#lc_numeric = 'C'           # locale for number formatting
#lc_time = 'C'              # locale for time formatting
# default configuration for text search
#default_text_search_config = 'pg_catalog.simple'
# - Shared Library Preloading -
#shared_preload_libraries = ''  # (change requires restart)
#local_preload_libraries = ''
#session_preload_libraries = ''
#jit_provider = 'llvmjit'       # JIT library to use
# - Other Defaults -
#dynamic_library_path = '$libdir'
#------------------------------------------------------------------------------
# LOCK MANAGEMENT
#------------------------------------------------------------------------------
#deadlock_timeout = 1s
#max_locks_per_transaction = 64     # min 10
# (change requires restart)
#max_pred_locks_per_transaction = 64    # min 10
# (change requires restart)
#max_pred_locks_per_relation = -2   # negative values mean
# (max_pred_locks_per_transaction
#  / -max_pred_locks_per_relation) - 1
#max_pred_locks_per_page = 2            # min 0
#------------------------------------------------------------------------------
# VERSION AND PLATFORM COMPATIBILITY
#------------------------------------------------------------------------------
# - Previous PostgreSQL Versions -
#array_nulls = on
#backslash_quote = safe_encoding    # on, off, or safe_encoding
#escape_string_warning = on
#lo_compat_privileges = off
#operator_precedence_warning = off
#quote_all_identifiers = off
#standard_conforming_strings = on
#synchronize_seqscans = on
# - Other Platforms and Clients -
#transform_null_equals = off
#------------------------------------------------------------------------------
# ERROR HANDLING
#------------------------------------------------------------------------------
#exit_on_error = off            # terminate session on any error?
#restart_after_crash = on       # reinitialize after backend crash?
#data_sync_retry = off          # retry or panic on failure to fsync
# data?
# (change requires restart)
#------------------------------------------------------------------------------
# CONFIG FILE INCLUDES
#------------------------------------------------------------------------------
# These options allow settings to be loaded from files other than the
# default postgresql.conf.
#include_dir = 'conf.d'         # include files ending in '.conf' from
# directory 'conf.d'
#include_if_exists = 'exists.conf'  # include file only if it exists
#include = 'special.conf'       # include file
#------------------------------------------------------------------------------
# CUSTOMIZED OPTIONS
#------------------------------------------------------------------------------
# Add settings for extensions here

Det er alt, du kan starte containere med kommandoen docker-compose up -d. Eller i en separat konsol med kommandoen docker-compose up.

Så pakkerne er blevet installeret, databasen er blevet lanceret, alt der er tilbage er at gøre dem venner med hinanden. For at gøre dette skal du tilføje følgende fil til projektets rod: ormconfig.js:

ormconfig.js

const process = require('process');
const username = process.env.POSTGRES_USER || "postgres";
const password = process.env.POSTGRES_PASSWORD || "example";
module.exports = {
"type": "postgres",
"host": "localhost",
"port": 5432,
username,
password,
"database": "postgres",
"synchronize": true,
"dropSchema": false,
"logging": true,
"entities": [__dirname + "/src/**/*.entity.ts", __dirname + "/dist/**/*.entity.js"],
"migrations": ["migrations/**/*.ts"],
"subscribers": ["subscriber/**/*.ts", "dist/subscriber/**/.js"],
"cli": {
"entitiesDir": "src",
"migrationsDir": "migrations",
"subscribersDir": "subscriber"
}
}

Denne konfiguration vil blive brugt til cli typeorm.

Lad os se på denne konfiguration mere detaljeret. På linje 3 og 4 får vi brugernavn og adgangskode fra miljøvariablerne. Dette er praktisk, når du har flere miljøer (dev, scene, prod osv.). Som standard er brugernavnet postgres, og adgangskoden er et eksempel. Resten af ​​konfigurationen er triviel, så vi vil kun fokusere på de mest interessante parametre:

  • synchronize - Angiver om databaseskemaet skal oprettes automatisk, når programmet starter. Vær forsigtig med denne mulighed og brug den ikke i produktionen, ellers vil du miste data. Denne mulighed er praktisk ved udvikling og fejlretning af en applikation. Som et alternativ til denne mulighed kan du bruge kommandoen schema:sync fra CLI TypeORM.
  • dropSchema - nulstil skemaet hver gang en forbindelse er etableret. Ligesom den forrige, bør denne mulighed kun bruges under udvikling og fejlretning af applikationen.
  • enheder - hvilke veje man skal lede efter beskrivelser af modeller. Bemærk venligst, at søgning efter maske er understøttet.
  • cli.entitiesDir er den mappe, hvor modeller, der er oprettet fra TypeORM CLI, skal gemmes som standard.

For at vi kan bruge alle funktionerne i TypeORM i vores Nest-applikation, skal vi importere modulet TypeOrmModule в AppModule. De der. din AppModule vil se sådan ud:

app.modul.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import * as process from "process";
const username = process.env.POSTGRES_USER || 'postgres';
const password = process.env.POSTGRES_PASSWORD || 'example';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
host: 'localhost',
port: 5432,
username,
password,
database: 'postgres',
entities: [__dirname + '/**/*.entity{.ts,.js}'],
synchronize: true,
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}

Som du måske har bemærket, metoden forRoot den samme konfiguration til at arbejde med databasen overføres som i filen ormconfig.ts

Den sidste berøring er tilbage - tilføj flere opgaver til at arbejde med TypeORM i package.json. Faktum er, at CLI er skrevet i javascript og kører i nodejs miljøet. Dog vil alle vores modeller og migreringer blive skrevet på maskinskrift. Derfor er det nødvendigt at transpilere vores migrationer og modeller, før du bruger CLI. Til dette har vi brug for ts-node-pakken:

yarn add -D ts-node

Tilføj derefter de nødvendige kommandoer til package.json:

"typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js",
"migration:generate": "yarn run typeorm migration:generate -n",
"migration:create": "yarn run typeorm migration:create -n",
"migration:run": "yarn run typeorm migration:run"

Den første kommando, typeorm, tilføjer en ts-node wrapper for at køre TypeORM cli. De resterende kommandoer er praktiske genveje, som du som udvikler vil bruge næsten hver dag:
migration:generate — oprette migreringer baseret på ændringer i dine modeller.
migration:create — oprettelse af en tom migration.
migration:run — iværksættelse af migrationer.
Nå, det er det nu, vi har tilføjet de nødvendige pakker, konfigureret applikationen til at arbejde med databasen både fra cli og fra selve applikationen, og også lanceret DBMS. Det er tid til at tilføje logik til vores applikation.

Installation af pakker til oprettelse af CRUD

Ved kun at bruge Nest kan du oprette en API, der giver dig mulighed for at oprette, læse, opdatere og slette en enhed. Denne løsning vil være så fleksibel som muligt, men i nogle tilfælde vil den være overflødig. Hvis du for eksempel hurtigt skal lave en prototype, kan du ofte ofre fleksibilitet for hastigheden af ​​udviklingen. Mange rammer giver funktionalitet til at generere CRUD ved at beskrive datamodellen for en bestemt enhed. Og Nest er ingen undtagelse! Denne funktionalitet leveres af pakken @nestjsx/crud. Dens muligheder er meget interessante:

  • nem installation og konfiguration;
  • DBMS uafhængighed;
  • kraftfuldt forespørgselssprog med evnen til at filtrere, paginere, sortere, indlæse relationer og indlejrede entiteter, cache osv.;
  • pakke til generering af anmodninger på front-end;
  • let tilsidesættelse af controller-metoder;
  • lille konfiguration;
  • swagger dokumentationsstøtte.

Funktionaliteten er opdelt i flere pakker:

  • @nestjsx/crud - grundpakken, som dekoratøren leverer () til rutegenerering, konfiguration og validering;
  • @nestjsx/crud-request — en pakke, der giver en forespørgselsbygger/parser til brug på frontend-siden;
  • @nestjsx/crud-typeorm — en pakke til integration med TypeORM, der giver den grundlæggende TypeOrmCrudService-tjeneste med CRUD-metoder til at arbejde med entiteter i databasen.

I denne tutorial skal vi bruge pakker redenjsx/crud og redenjsx/crud-typeorm. Først, lad os sætte dem

yarn add @nestjsx/crud class-transformer class-validator

pakker klasse-transformer и klassevalidator i denne ansøgning kræves for en deklarativ beskrivelse af reglerne for henholdsvis transformering af modelforekomster og validering af indkommende anmodninger. Disse pakker er fra samme forfatter, så grænsefladerne ligner hinanden.

Direkte implementering af CRUD

Vi tager en liste over brugere som en eksempelmodel. Brugere vil have følgende felter: id, username, displayName, email. id - automatisk stigningsfelt, email и username - unikke felter. Det er simpelt! Tilbage er kun at implementere vores idé i form af en Nest-applikation.
Først skal du oprette et modul users, som får ansvaret for at arbejde med brugerne. Lad os bruge cli'en fra NestJS og udføre kommandoen i rodmappen til vores projekt nest g module users.

nest g-modulbrugere

dmitrii@dmitrii-HP-ZBook-17-G3:~/projects/nest-rest git:(master*)$ nest g module users
CREATE /src/users/users.module.ts (82 bytes)
UPDATE /src/app.module.ts (312 bytes)

I dette modul tilføjer vi en enhedsmappe, hvor vi vil have modellerne af dette modul. Lad os især tilføje filen user.entity.ts med en beskrivelse af brugermodellen:

bruger.enhed.ts

import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: string;
@Column({unique: true})
email: string;
@Column({unique: true})
username: string;
@Column({nullable: true})
displayName: string;
}

For at denne model kan "ses" af vores applikation, er den nødvendig i modulet UsersModule importere TypeOrmModule følgende indhold:

brugere.modul.ts

import { Module } from '@nestjs/common';
import { UsersController } from './controllers/users/users.controller';
import { UsersService } from './services/users/users.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './entities/user.entity';
@Module({
controllers: [UsersController],
providers: [UsersService],
imports: [
TypeOrmModule.forFeature([User])
]
})
export class UsersModule {}

Det vil sige, her importerer vi TypeOrmModule, hvor som en metodeparameter forFeature Vi angiver en liste over modeller relateret til dette modul.

Tilbage er blot at oprette den tilsvarende enhed i databasen. Migrationsmekanismen tjener til disse formål. For at oprette en migrering baseret på ændringer i modeller skal du køre kommandoen npm run migration:generate -- CreateUserTable:

spoiler titel

$ npm run migration:generate -- CreateUserTable
Migration /home/dmitrii/projects/nest-rest/migrations/1563346135367-CreateUserTable.ts has been generated successfully.
Done in 1.96s.

Vi behøvede ikke at skrive migreringen manuelt, alt skete på magisk vis. Er dette ikke et mirakel! Det er dog ikke alt. Lad os tage et kig på den oprettede migreringsfil:

1563346135367-CreateUserTable.ts

import {MigrationInterface, QueryRunner} from "typeorm";
export class CreateUserTable1563346816726 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`CREATE TABLE "user" ("id" SERIAL NOT NULL, "email" character varying NOT NULL, "username" character varying NOT NULL, "displayName" character varying, CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE ("email"), CONSTRAINT "UQ_78a916df40e02a9deb1c4b75edb" UNIQUE ("username"), CONSTRAINT "PK_cace4a159ff9f2512dd42373760" PRIMARY KEY ("id"))`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`DROP TABLE "user"`);
}
}

Som du kan se, blev ikke kun metoden til at starte migreringen automatisk genereret, men også metoden til at rulle tilbage. Fantastisk!
Det eneste, der er tilbage, er at udrulle denne migration. Dette gøres med følgende kommando:

npm run migration:run.

Det er det, nu er skemaændringerne migreret til databasen.
Dernæst vil vi oprette en tjeneste, der vil være ansvarlig for at arbejde med brugere og arve den fra TypeOrmCrudService. Opbevaringsstedet for enheden af ​​interesse skal overføres til parameteren for den overordnede konstruktør, i vores tilfælde User depot.

brugere.service.ts

import { Injectable } from '@nestjs/common';
import { TypeOrmCrudService } from '@nestjsx/crud-typeorm';
import { User } from '../../entities/user.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
@Injectable()
export class UsersService extends TypeOrmCrudService<User>{
constructor(@InjectRepository(User) usersRepository: Repository<User>){
super(usersRepository);
}
}

Vi skal bruge denne service i controlleren users. For at oprette en controller skal du indtaste konsollen nest g controller users/controllers/users

nest g controller brugere/controllere/brugere

dmitrii@dmitrii-HP-ZBook-17-G3:~/projects/nest-rest git:(master*)$ nest g controller users/controllers/users
CREATE /src/users/controllers/users/users.controller.spec.ts (486 bytes)
CREATE /src/users/controllers/users/users.controller.ts (99 bytes)
UPDATE /src/users/users.module.ts (188 bytes)

Lad os åbne denne controller og redigere den for at tilføje lidt magi redenjsx/crud. Per klasse UsersController Lad os tilføje en dekoratør som denne:

@Crud({
model: {
type: User
}
})

er en dekoratør, der tilføjer controlleren de nødvendige metoder til at arbejde med modellen. Modeltypen er angivet i feltet model.type dekoratør konfigurationer.
Det andet trin er at implementere grænsefladen CrudController<User>. "Samlet" controller-kode ser sådan ud:

import { Controller } from '@nestjs/common';
import { Crud, CrudController } from '@nestjsx/crud';
import { User } from '../../entities/user.entity';
import { UsersService } from '../../services/users/users.service';
@Crud({
model: {
type: User
}
})
@Controller('users')
export class UsersController implements CrudController<User>{
constructor(public service: UsersService){}
}

Og det er det hele! Nu understøtter controlleren hele sættet af operationer med modellen! Tror du mig ikke? Lad os prøve vores applikation i aktion!

Oprettelse af et forespørgselsscript i TestMace

For at teste vores service vil vi bruge en IDE til at arbejde med API TestMace. Hvorfor TestMace? Sammenlignet med lignende produkter har det følgende fordele:

  • kraftfuldt arbejde med variabler. I øjeblikket er der flere typer variabler, som hver spiller en bestemt rolle: indbyggede variable, dynamiske variable, miljøvariabler. Hver variabel tilhører en node med understøttelse af arvemekanismen;
  • Opret nemt scripts uden programmering. Dette vil blive diskuteret nedenfor;
  • et menneskelæsbart format, der giver dig mulighed for at gemme projektet i versionskontrolsystemer;
  • autofuldførelse, syntaksfremhævning, fremhævning af variabel værdi;
  • API-beskrivelsesunderstøttelse med mulighed for at importere fra Swagger.

Lad os starte vores server med kommandoen npm start og prøv at få adgang til listen over brugere. Listen over brugere, at dømme efter vores controller-konfiguration, kan fås fra url localhost:3000/users. Lad os sende en anmodning til denne url.
Efter at have kørt TestMace kan du se en grænseflade som denne:

Hurtig CRUD-oprettelse med nest, @nestjsx/crud og TestMace

Øverst til venstre er et projekttræ med en rodknude Projekt. Lad os prøve at oprette den første anmodning for at få en liste over brugere. Til dette vil vi skabe RequestStep node Dette gøres i kontekstmenuen i projektnoden Tilføj node -> RequestStep.

Hurtig CRUD-oprettelse med nest, @nestjsx/crud og TestMace

Indsæt localhost:3000/users i URL-feltet og kør anmodningen. Vi modtager kode 200 med et tomt array i svarlegemet. Det er forståeligt, vi har ikke tilføjet nogen endnu.
Lad os oprette et script, der indeholder følgende trin:

  1. oprettelse af en bruger;
  2. anmodning om id'et for den nyoprettede bruger;
  3. sletning efter bruger-id oprettet i trin 1.

Så lad os gå. Lad os for nemheds skyld oprette en node-like Folder. I det væsentlige er dette kun en mappe, hvor vi gemmer hele scriptet. For at oprette en mappeknude skal du vælge Projekt fra genvejsmenuen på noden Tilføj node -> Mappe. Lad os kalde noden check-opret. Inde i en node check-opret Lad os oprette vores første anmodning om at oprette en bruger. Lad os kalde den nyoprettede node oprette-bruger. Det vil sige, i øjeblikket vil nodehierarkiet se sådan ud:

Hurtig CRUD-oprettelse med nest, @nestjsx/crud og TestMace

Lad os gå til den åbne fane oprette-bruger node. Lad os indtaste følgende parametre for anmodningen:

  • Anmodningstype - POST
  • URL - localhost:3000/brugere
  • Body - JSON med værdi {"email": "[email protected]", "displayName": "New user", "username": "user"}

Lad os opfylde denne anmodning. Vores ansøgning siger, at posten er blevet oprettet.

Hurtig CRUD-oprettelse med nest, @nestjsx/crud og TestMace

Nå, lad os tjekke dette faktum. For at kunne arbejde med id'et for den oprettede bruger i de efterfølgende trin, skal denne parameter gemmes. Mekanismen er perfekt til dette. dynamiske variable. Lad os bruge vores eksempel til at se på, hvordan man arbejder med dem. I den analyserede fane i svaret, ud for id-noden i kontekstmenuen, skal du vælge elementet Tildel til variabel. I dialogboksen skal du indstille følgende parametre:

  • Node — i hvilken af ​​forfædrene der skal oprettes en dynamisk variabel. Lad os vælge check-opret
  • Variabelt navn — navnet på denne variabel. Lad os ringe userId.

Sådan ser processen med at oprette en dynamisk variabel ud:

Hurtig CRUD-oprettelse med nest, @nestjsx/crud og TestMace

Nu, hver gang denne forespørgsel udføres, vil værdien af ​​den dynamiske variabel blive opdateret. Og fordi dynamiske variabler understøtter mekanismen for hierarkisk arv, variabel userId vil være tilgængelig i efterkommere check-opret node på ethvert indlejringsniveau.
Denne variabel vil være nyttig for os i den næste anmodning. Vi vil nemlig anmode om den nyoprettede bruger. Som et barn af en knude check-opret vi opretter en anmodning tjek om findes med parameter url lige localhost:3000/users/${$dynamicVar.userId}. Se design ${variable_name} dette er at få værdien af ​​en variabel. Fordi Vi har en dynamisk variabel, så for at få den skal du have adgang til objektet $dynamicVar, dvs. fuldstændig adgang til en dynamisk variabel userId vil se sådan ud ${$dynamicVar.userId}. Lad os udføre anmodningen og sikre os, at dataene er anmodet korrekt.
Det sidste trin tilbage er at anmode om sletning. Vi har brug for det ikke kun for at kontrollere sletningens funktion, men også så at sige for at rydde op efter os selv i databasen, fordi E-mail- og brugernavnfelterne er unikke. Så i check-create noden vil vi oprette en slette-bruger anmodning med følgende parametre

  • Anmodningstype - SLET
  • URL - localhost:3000/users/${$dynamicVar.userId}

Lad os starte. Vi venter. Vi nyder resultatet)

Nå, nu kan vi køre hele dette script til enhver tid. For at køre scriptet skal du vælge fra kontekstmenuen check-opret knudepunkt Kør.

Hurtig CRUD-oprettelse med nest, @nestjsx/crud og TestMace

Noderne i scriptet vil blive udført efter hinanden
Du kan gemme dette script til dit projekt ved at køre Filer -> Gem projekt.

Konklusion

Alle funktionerne i de brugte værktøjer kunne simpelthen ikke passe ind i denne artikels format. Hvad angår hovedsynderen - pakken redenjsx/crud - følgende emner forbliver afdækket:

  • tilpasset validering og transformation af modeller;
  • kraftfuldt forespørgselssprog og dets bekvemme brug ved fronten;
  • redefinering og tilføjelse af nye metoder til crud-controllere;
  • swagger støtte;
  • cachehåndtering.

Men selv det, der er beskrevet i artiklen, er nok til at forstå, at selv en sådan virksomhedsramme som NestJS har værktøjer til hurtig applikationsprototyping. Og sådan en cool IDE-agtig TestMace giver dig mulighed for at holde et givet tempo.

Kildekode til denne artikel sammen med projektet TestMace, tilgængelig i depotet https://github.com/TestMace/nest-rest. For at åbne et projekt TestMace bare gør det i appen Filer -> Åbn projekt.

Kilde: www.habr.com

Tilføj en kommentar