From 9529e155443c0d3280a22f23adfd58b07d8c561d Mon Sep 17 00:00:00 2001 From: Ajeet Singh Raina Date: Sun, 22 Sep 2024 19:23:39 +0530 Subject: [PATCH 01/56] Added a use case guide for Pre-seeding database --- content/guides/use-case/pre-seeding.md | 451 +++++++++++++++++++++++++ 1 file changed, 451 insertions(+) create mode 100644 content/guides/use-case/pre-seeding.md diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md new file mode 100644 index 000000000000..593a30425740 --- /dev/null +++ b/content/guides/use-case/pre-seeding.md @@ -0,0 +1,451 @@ +--- +description: Pre-seeding database with schema and data at startup for development environment +keywords: Pre-seeding, database, postgres, container-supported development +title: Pre-seeding database with schema and data at startup for development environment +linktitle: Pre-seeding database +--- + +Pre-seeding databases with essential data and schema during local development is a common practice to enhance the development and testing workflow. By simulating real-world scenarios, this practice helps catch frontend issues early, ensures alignment between Database Administrators and Software Engineers, and facilitates smoother collaboration. Pre-seeding offers benefits like confident deployments, consistency across environments, and early issue detection, ultimately improving the overall development process. + +In this guide, you will learn how to: + +- Use Docker to launch up a Postgres container +- Pre-seed Postgres using a SQL script +- Pre-seed Postgres by using volumes to mount SQL files +- Pre-seed Postgres using JavaScript code + +## Using Postgres with Docker + +The [official Docker image for Postgres](https://hub.docker.com/_/postgres) provides a convenient way to run Postgres database on your development machine. A Postgres Docker image is a pre-configured environment that encapsulates the PostgreSQL database system. It's a self-contained unit, ready to run in a Docker container. By using this image, you can quickly and easily set up a Postgres instance without the need for manual configuration. + +## Prerequisites + +The following prerequisites are required to follow along with this how-to guide: + +- [Docker Desktop](https://www.docker.com/products/docker-desktop/) +- [Download](https://www.postgresql.org/download/) and Install PostgreSQL Client (`psql`) + +## Launching Postgres + +Launch a quick demo of Postgres by using the following steps: + +1. Open the terminal and run the following command to start a Postgres container. + + This example will launch a Postgres container, expose port `5432` onto the host to let a native-running application to connect to it with the password `mysecretpassword`. + + ```console + $ docker run --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=mysecretpassword postgres + ``` + +2. Verify that Postgres is up and running by selecting the container and checking the logs on Docker Dashboard. + + ```plaintext + PostgreSQL Database directory appears to contain a database; Skipping initialization + + 2024-09-08 09:09:47.136 UTC [1] LOG: starting PostgreSQL 16.4 (Debian 16.4-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit + 2024-09-08 09:09:47.137 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432 + 2024-09-08 09:09:47.137 UTC [1] LOG: listening on IPv6 address "::", port 5432 + 2024-09-08 09:09:47.139 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" + 2024-09-08 09:09:47.142 UTC [29] LOG: database system was shut down at 2024-09-08 09:07:09 UTC + 2024-09-08 09:09:47.148 UTC [1] LOG: database system is ready to accept connections + ``` + +3. Connect to Postgres from the local system. + + The `psql` is the PostgreSQL interactive shell that is used to connect to a Postgres database and let you start executing SQL commands. Assuming that you already have `psql` utility installed on your local system, it's time to connect to the Postgres database. Run the following command on your local terminal: + + ```console + psql -h localhost -U postgres + ``` + + Enter `mysecretpassword` when prompted for the password. + + ```console + Password for user postgres: + psql (15.8 (Homebrew), server 16.4 (Debian 16.4-1.pgdg120+1)) + WARNING: psql major version 15, server major version 16. + Some psql features might not work. + Type "help" for help. + + postgres=# + ``` + +## Pre-seed the Postgres database using a SQL script + +Now that you've familiarized yourself with Postgres, it's time to see how to pre-seed it with sample data. In this demonstration, you'll first create a script that holds SQL commands. The script defines the database, and table structure and inserts sample data. Then you will connect the database to verify the data. + +Assuming that you have an existing Postgres database instance up and running, follow these steps to seed the database. + +1. Create an empty file named `seed.sql` and add the following content. + + ```plaintext + CREATE DATABASE sampledb; + + \c sampledb + + CREATE TABLE users ( + id SERIAL PRIMARY KEY, + name VARCHAR(50), + email VARCHAR(100) UNIQUE + ); + + INSERT INTO users (name, email) VALUES + ('Alpha', 'alpha@example.com'), + ('Beta', 'beta@example.com'), + ('Gamma', 'gamma@example.com'); + ``` + + The SQL commands create a new database called `sampledb`, connect to it, and define a `users` table. The table includes an auto-incrementing `id` as the primary key, a `name` field with a maximum length of 50 characters, and a unique `email` field with up to 100 characters. + + After creating the table, the commands insert three users into the `users` table with their respective names and emails. This setup forms a basic database structure to store user information with unique email addresses. + +2. Run the following command to seed the database + + It’s time to feed the content of the `seed.sql` directly into the database by using the “<” operator. The command is used to execute a SQL script named `seed.sql` against a Postgres database named `sampledb`. + + ```console + psql -h localhost -U postgres < seed.sql + ``` + + > [!TIP] Running on Windows + > If you're using Windows, the < operator may result in an error. To avoid this, use the -f flag to specify the SQL file like this: + + ```console + psql -h localhost -U postgres -f seed.sql` + ``` + + Enter `mysecretpassword` when prompted for the password and once the query is executed, you will see the following results: + + ```plaintext + CREATE DATABASE + You are now connected to database "sampledb" as user "postgres". + CREATE TABLE + INSERT 0 3 + ``` + +3. Run the following `psql` command to verify if the table named users is populated in the database `sampledb` or not. + + ```console + psql -h localhost -U postgres sampledb + ``` + + Enter `mysecretpassword` when prompted for the password. You can now run `\l` in the `psql` terminal to list all the databases on the Postgres server. + + ```console + sampledb=# \l + List of databases + Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges + -----------+----------+----------+------------+------------+------------+-----------------+----------------------- + postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | + sampledb | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | + template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/postgres + + | | | | | | | postgres=CTc/postgres + template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/postgres + + | | | | | | | postgres=CTc/postgres + (4 rows) + ``` + + To retrieve all the data from the users table, enter the following query: + + ```console + sampledb=# SELECT * from users; + id | name | email + ----+-------+------------------- + 1 | Alpha | alpha@example.com + 2 | Beta | beta@example.com + 3 | Gamma | gamma@example.com + (3 rows) + ``` + + Use `\q` or `\quit` to exit from the Postgres interactive shell. + +## Pre-seeding the database by using Volumes to mount SQL files + +In Docker, mounting refers to making files or directories from the host system accessible within a container. This let you to share data or configuration files between the host and the container, enabling greater flexibility and persistence. + +Now that you have learned how to launch Postgres and pre-seed the database using an SQL script, it’s time to learn how to mount an SQL file directly into the Postgres containers’ initialisation directory (`/docker-entrypoint-initdb.d`). The `/docker-entrypoint-initdb.d` is a special directory in PostgreSQL Docker containers that is used for initializing the database when the container is first started + +### Stop the existing Postgres instance + +Make sure you stop any running Postgres containers(along with volumes) to prevent port conflicts before you follow the steps: + +1. Create a named volume. + + Use the `docker volume create` command to create a named volume. + + ```console + $ docker volume create data_sql + ``` + +2. Create a text file named `Dockerfile` and copy the following content. + + ```plaintext + FROM postgres:latest + VOLUME /docker-entrypoint-initdb.d + ``` + +3. Build the custom Docker image called `mynewpostgres`. + + ```console + $ docker build -t mynewpostgres . + ``` + +4. Run the following command to successfully mount the volume and run the Postgres container. + + Assuming that the existing `seed.sql` (used in previous steps) is placed under the same directory, run the following command: + + ```console + $ docker run --rm \ + -v $(pwd)/seed.sql:/sql-files/seed.sql \ + -v data_sql:/docker-entrypoint-initdb.d \ + mynewpostgres cp /sql-files/seed.sql /docker-entrypoint-initdb.d/ + ``` + + This command mounts your `seed.sql` file from the current directory (`$(pwd)/seed.sql`) into the temporary container at `/sql-files`, and then copies it into the `data_sql` named volume. + + > [!TIP] Running on Windows + > When running this command on Windows, use `${PWD}` (in uppercase and with curly brackets) instead of `$(pwd)`, and make sure to execute the command in PowerShell: + + + ```console + $ docker run --rm \ + -v ${PWD}/seed.sql:/sql-files/seed.sql \ + -v data_sql:/docker-entrypoint-initdb.d \ + mynewpostgres cp /sql-files/seed.sql /docker-entrypoint-initdb.d/ + ``` + + This ensures that the volume is mounted correctly on the Windows systems. + +5. Now that your `seed.sql` file is in the `data_sql` volume, you can run your `mynewpostgres` image and mount the named volume: + + ```console + $ docker run --name mynewpostgres \ + -p 5432:5432 \ + -e POSTGRES_PASSWORD=mysecretpassword \ + -v data_sql:/docker-entrypoint-initdb.d \ + mynewpostgres + ``` + + Open a new terminal and run the following command to verify the database and tables seeded into the database. + ```console + psql -h localhost -U postgres sampledb + ``` + + Enter `mysecretpassword` when prompted for the password. Run the following command to verify if the table named users is populated in the database `sampledb` or not. + + ```console + sampledb=# select * from users; + id | name | email + ----+-------+------------------- + 1 | Alpha | alpha@example.com + 2 | Beta | beta@example.com + 3 | Gamma | gamma@example.com + 3 rows) + ``` + + Now that you’ve been shown how to pre-seed a database by using volumes, let’s see how you can simplify the whole process of seeding by using a single Docker Compose file. + + > [!TIP] + > Make sure you stop any running Postgres containers(along with volumes) to prevent port conflicts before you follow the next steps. + + First, you will need to create the following project directory structure: + + ```console + $ tree + . + ├── compose.yml + └── sql_files + └── seed.sql + ``` + +1. Start by writing the compose file + + This compose.yml file defines a Postgres service named `db` using the latest Postgres image, which sets up a database with the name `sampledb`, along with a user `postgres` and a password `mysecretpassword`. + + ```yaml + services: + db: + image: postgres:latest + container_name: my_postgres_db + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: mysecretpassword + POSTGRES_DB: sampledb + ports: + - "5432:5432" + volumes: + - data_sql:/var/lib/postgresql/data # Persistent data storage + - ./sql_files:/docker-entrypoint-initdb.d # Mount local sql file to seed the database + + volumes: + data_sql: + ``` + + It maps port `5432` on the host to the container's `5432`, let you access to the Postgres database from outside the container. It also defines two volumes: one (`data_sql`) for persisting the database data, ensuring that data is not lost when the container is stopped, and another volume that mounts the local `sql_files` directory into `/docker-entrypoint-initdb.d` within the container. This mounted directory contains a SQL file that is automatically executed when the Postgres container is initialized, allowing pre-seeding of the database. + +2. Create a new directory `sql_files/` and copy the following `seed.sql` to this new directory: + + ```plaintext + -- Ensure the users table is created in the sampledb database + + CREATE TABLE IF NOT EXISTS users ( + id SERIAL PRIMARY KEY, + name VARCHAR(50), + email VARCHAR(100) UNIQUE + ); + + -- Insert sample data into the users table + INSERT INTO users (name, email) VALUES + ('Alpha', 'alpha@example.com'), + ('Beta', 'beta@example.com'), + ('Gamma', 'gamma@example.com') + ON CONFLICT (email) DO NOTHING; + ``` + + This SQL script ensures that the users table is created in the `sampledb` database if it doesn't already exist. The table includes three columns: id, which is a serial primary key, name (a VARCHAR of 50 characters), and email (a VARCHAR of 100 characters that must be unique). The script also inserts three user records into the users table, but if a conflict occurs on the email field (i.e., if the email already exists), the insertion is skipped, ensuring no duplicate emails are added. + +3. Bring up the Compose service. + + ```console + $ docker compose up -d + ``` + +4. It’s time to verify if the table `users` get populated with the data. + + ```console + psql -h localhost -U postgres sampledb + ``` + + Enter `mysecretpassword` when prompted for the password. + + ``` + Password for user postgres: + psql (15.8 (Homebrew), server 16.4 (Debian 16.4-1.pgdg120+1)) + WARNING: psql major version 15, server major version 16. + Some psql features might not work. + Type "help" for help. + + sampledb=# select * from users; + id | name | email + ----+-------+------------------- + 1 | Alpha | alpha@example.com + 2 | Beta | beta@example.com + 3 | Gamma | gamma@example.com + (3 rows) + + sampledb=# + ``` + + > [!TIP] + > If you're encountering the error 'more' is not recognized as an internal or external command when running queries in `psql` on a Windows system, this is likely due to an issue with the pager setting, which uses external programs like more or less to paginate query results. You can resolve this by turning off pagination within `psql` using the following command: + + ```console + \pset pager off + ``` + + To avoid running this command every time, you can permanently disable the pager by adding \pset pager off to your psqlrc.conf file, which is located in the `%APPDATA%\postgresql\` directory on Windows. This will ensure that query results are always displayed without invoking an external pager program. + + +## Pre-seeding the database using JavaScript code + + +Now that you have learned how to seed the database using various methods like SQL script, mounting volumes etc., it's time to try to achieve it using JavaScript code. + +1. Create a .env file with the following: + + ```plaintext + POSTGRES_USER=postgres + POSTGRES_DB_HOST=localhost + POSTGRES_DB=sampledb + POSTGRES_PASSWORD=mysecretpassword + POSTGRES_PORT=5432 + ``` + +2. Create a new JavaScript file called seed.js with the following content: + + The following JavaScript code imports the `dotenv` package which is used to load environment variables from an `.env` file. The `.config()` method reads the `.env` file and sets the environment variables as properties of the `process.env` object. This let you to securely store sensitive information like database credentials outside of your code. + + Then, it creates a new Pool instance from the pg library, which provides a connection pool for efficient database interactions. The `seedData` function is defined to perform the database seeding operations. +It is called at the end of the script to initiate the seeding process. The try...catch...finally block is used for error handling. + + ```plaintext + require('dotenv').config(); // Load environment variables from .env file + const { Pool } = require('pg'); + + // Create a new pool using environment variables + const pool = new Pool({ + user: process.env.POSTGRES_USER, + host: process.env.POSTGRES_DB_HOST, + database: process.env.POSTGRES_DB, + port: process.env.POSTGRES_PORT, + password: process.env.POSTGRES_PASSWORD, + }); + + const seedData = async () => { + try { + // Drop the table if it already exists (optional) + await pool.query(`DROP TABLE IF EXISTS todos;`); + + // Create the table with the correct structure + await pool.query(` + CREATE TABLE todos ( + id SERIAL PRIMARY KEY, + task VARCHAR(255) NOT NULL, + completed BOOLEAN DEFAULT false + ); + ` ); + + // Insert seed data + await pool.query(` + INSERT INTO todos (task, completed) VALUES + ('Watch netflix', false), + ('Finish podcast', false), + ('Pick up kid', false); + `); + console.log('Database seeded successfully!'); + } catch (err) { + console.error('Error seeding the database', err); + } finally { + pool.end(); + } + }; + + // Call the seedData function to run the script + seedData(); + ``` + +3. Kick off the seeding process + + ```console + $ node seed.js + ``` + + You should see the following command: + + ```plaintext + Database seeded successfully! + ``` + +4. Verify if the database is seeded correctly: + + ```console + psql -h localhost -U postgres sampledb + Password for user postgres: + ``` + + Enter `mysecretpassword` when prompted for the password. You should see the list of items added to the table. + + ```console + sampledb=# select * from todos; + id | task | completed + ----+----------------+----------- + 1 | Watch netflix | f + 2 | Finish podcast | f + 3 | Pick up kid | f + (3 rows) + ``` + +## Recap + +Pre-seeding a database with schema and data at startup is essential for creating a consistent and realistic testing environment, which helps in identifying issues early in development and aligning frontend and backend work. This guide has equipped you with the knowledge and practical steps to achieve pre-seeding using various methods, including SQL script, Docker integration, and JavaScript code. + From 1e9ae510974ab3cbb5979482b6d4ef4958e11455 Mon Sep 17 00:00:00 2001 From: Ajeet Singh Raina Date: Sun, 22 Sep 2024 19:30:21 +0530 Subject: [PATCH 02/56] Fixed formatting --- content/guides/use-case/pre-seeding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index 593a30425740..5abf8bad5b03 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -318,7 +318,7 @@ Make sure you stop any running Postgres containers(along with volumes) to preven Enter `mysecretpassword` when prompted for the password. - ``` + ```plaintext Password for user postgres: psql (15.8 (Homebrew), server 16.4 (Debian 16.4-1.pgdg120+1)) WARNING: psql major version 15, server major version 16. From 4dfd9c8e18364afb59609ad31fc7b4d14bef2fc6 Mon Sep 17 00:00:00 2001 From: Ajeet Singh Raina Date: Sun, 22 Sep 2024 22:33:11 +0530 Subject: [PATCH 03/56] Fixed vale linting --- content/guides/use-case/pre-seeding.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index 5abf8bad5b03..3ca5ab986795 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -243,20 +243,20 @@ Make sure you stop any running Postgres containers(along with volumes) to preven 3 rows) ``` - Now that you’ve been shown how to pre-seed a database by using volumes, let’s see how you can simplify the whole process of seeding by using a single Docker Compose file. +Now that you’ve been shown how to pre-seed a database by using volumes, let’s see how you can simplify the whole process of seeding by using a single Docker Compose file. - > [!TIP] - > Make sure you stop any running Postgres containers(along with volumes) to prevent port conflicts before you follow the next steps. +> [!TIP] +> Make sure you stop any running Postgres containers(along with volumes) to prevent port conflicts before you follow the next steps. - First, you will need to create the following project directory structure: +First, you will need to create the following project directory structure: - ```console - $ tree - . - ├── compose.yml - └── sql_files - └── seed.sql - ``` +```console +$ tree +. +├── compose.yml +└── sql_files + └── seed.sql +``` 1. Start by writing the compose file From d29972b5f9dfec6f40b7b00d55ef98fe859ba3c0 Mon Sep 17 00:00:00 2001 From: Ajeet Singh Raina Date: Tue, 24 Sep 2024 19:09:33 +0530 Subject: [PATCH 04/56] Added WireMock use case guide --- .../images/wiremock-accuweatherapi.webp | Bin 0 -> 15368 bytes .../guides/use-case/images/wiremock-arch.webp | Bin 0 -> 22448 bytes .../images/wiremock-logs-docker-desktop.webp | Bin 0 -> 50248 bytes .../images/wiremock-using-docker.webp | Bin 0 -> 19764 bytes content/guides/use-case/wiremock.md | 272 ++++++++++++++++++ 5 files changed, 272 insertions(+) create mode 100644 content/guides/use-case/images/wiremock-accuweatherapi.webp create mode 100644 content/guides/use-case/images/wiremock-arch.webp create mode 100644 content/guides/use-case/images/wiremock-logs-docker-desktop.webp create mode 100644 content/guides/use-case/images/wiremock-using-docker.webp create mode 100644 content/guides/use-case/wiremock.md diff --git a/content/guides/use-case/images/wiremock-accuweatherapi.webp b/content/guides/use-case/images/wiremock-accuweatherapi.webp new file mode 100644 index 0000000000000000000000000000000000000000..3939de602066bf8791e23ed137b5c451b84ba220 GIT binary patch literal 15368 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 O3(TJ1|778RjsFJ$R3_yB literal 0 HcmV?d00001 diff --git a/content/guides/use-case/images/wiremock-arch.webp b/content/guides/use-case/images/wiremock-arch.webp new file mode 100644 index 0000000000000000000000000000000000000000..04503fbe1434d41adfa33882a36943edf2e7eeba GIT binary patch literal 22448 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 zFM>}N(NFY{BKIucjU~}&1nCOpEK>IObbtT=000000000000000000000000000000 F008B@{Luga literal 0 HcmV?d00001 diff --git a/content/guides/use-case/images/wiremock-logs-docker-desktop.webp b/content/guides/use-case/images/wiremock-logs-docker-desktop.webp new file mode 100644 index 0000000000000000000000000000000000000000..4bb87654d97386fc0f0cc42834d9d215e3a09964 GIT binary patch literal 50248 zcmZsBV~{1$)@7lqx@_As)y; zVPW1u000#sepzK%Ry@YP&#_RzS%4IazZ!wKsxY)X0+ z8CIY_%YCxELg#j0d|5p2e3B*&A9|GR?OgbP)!T}IDOMT0H2t=)?DSR@>F~B zeD8dtey2R$_|o3`Eb(Z3-Td_aC|%BcxP0vl+xX%R_q2cSc~t%se)+u+fAK5=f2e%c zDCfNC{CrLIH2v)S{9KcNl78cU?`X#u!(QV)d?o*w@%(%M_&h!VoSU4fJjGn@)cJsR z3%&ci;9m9A@9cDuemWfcbon^`;D0xK>@@j2Xv2QtzV5v5VHf!1|3rLS zyu|FHF79Oc)ct^ed;HkE@i@ge{wRD^eD-|f{$1^l$hXH=$ydp1&4bRz�HL59xQ> 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 z>kge^)2upmhfc8R));z+TgfW*ztIm{SP`PA007dqW&i*H00000000000000000000 s00000000000000000000000000000BdNrqmBYA)1t)!vA000000Mxe;o&W#< literal 0 HcmV?d00001 diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md new file mode 100644 index 000000000000..cdf6a3660926 --- /dev/null +++ b/content/guides/use-case/wiremock.md @@ -0,0 +1,272 @@ +--- +description: Mocking API services in development and testing with WireMock +keywords: WireMock, container-supported development +title: Mocking API services in development and testing with WireMock +linktitle: Mocking API services with WireMock +--- + +During local development and testing, it's quite common to encounter situations where your app is dependent on the remote APIs. Network issues, rate limits, or even downtime of the API provider can halt your progress. This can significantly hinder your productivity and make testing more challenging. This is where WireMock comes into play. + +WireMock is an open-source tool that helps developers to create a mock server that simulates the behavior of real APIs, providing a controlled environment for development and testing. + +Imagine you have both an API and a frontend app, and you want to test how the frontend interacts with the API. Using WireMock, you can set up a mock server to simulate the API's responses, allowing you to test the frontend behavior without relying on the actual API. This can be particularly helpful when the API is still under development or when you want to test different scenarios without affecting the actual API. WireMock supports both HTTP and HTTPS protocols and can simulate various response scenarios, including delays, errors, and different HTTP status codes. + +## Using WireMock with Docker + +The official [Docker image for WireMock](https://hub.docker.com/r/wiremock/wiremock) provides a convenient way to deploy and manage WireMock instances. WireMock is available for various CPU architectures, including x64, armv7, and armv8, ensuring compatibility with different devices and platforms. You can learn more about WireMock standalone on the [WireMock docs site](https://wiremock.org/docs/standalone/docker/). + +### Prerequisites + +The following prerequisites are required to follow along with this how-to guide: + +* [Docker Desktop](https://www.docker.com/products/docker-desktop/) + +### Launching WireMock + +Launch a quick demo of WireMock by using the following steps: + + 1. Clone the [GitHub repository](https://github.com/dockersamples/wiremock-node-docker) locally. + + ```console + $ git clone https://github.com/dockersamples/wiremock-node-docker + ``` + + 2. Navigate to the `wiremock-endpoint` directory + + ```console + $ cd wiremock-node-docker/ + ``` + + WireMock acts as the mock API that your backend will communicate with to retrieve data. The mock API responses have already been created for you in the mappings directory. + + 3. Start the Compose stack by running the following command at the root of the cloned project directory + + ```console + $ docker compose up -d + ``` + + After a moment, the application will be up and running. + + ![Diagram showing the WireMock container running on Docker Desktop ](./images/wiremock-using-docker.webp) + + + You can check the logs by selecting the **WireMock** container: + + ![Diagram showing the logs of WireMock container running on Docker Desktop ](./images/wiremock-logs-docker-desktop.webp) + + 4. Test the Mock API. + + ```console + $ curl http://localhost:8080/api/v1/getWeather\?city\=Bengaluru + ``` + + It will return the following response: + + ```plaintext + {"city":"Bengaluru","temperature":27.1,"conditions":"Mostly cloudy","forecasts":[{"date":"2024-09-02T07:00:00+05:30","temperature":83,"conditions":"Partly sunny w/ t-storms"},{"date":"2024-09-03T07:00:00+05:30","temperature":83,"conditions":"Thunderstorms"},{"date":"2024-09-04T07:00:00+05:30","temperature":83,"conditions":"Intermittent clouds"},{"date":"2024-09-05T07:00:00+05:30","temperature":82,"conditions":"Dreary"},{"date":"2024-09-06T07:00:00+05:30","temperature":82,"conditions":"Dreary"}]} + ``` + + You get this response due to the mapping file in the `wiremock-endpoint/mappings/getWeather/getWeatherBengaluru.json` file. + + +## Using WireMock in development + + Now that you have tried WireMock, let’s use it in development and testing. In this example, you will use a sample application that has a Node.js backend. This app stack has the following configuration: + + * **Local Development Environment**: The context in which the Node.js backend and WireMock are running. + * **Node.js Backend**: Represents the backend application that handles HTTP requests. + * **External AccuWeather API**: The real API from which live weather data is fetched. + * **WireMock**: The mock server that simulates the API responses during testing. It runs as a Docker container. + + ![Diagram showing the architecture of WireMock in development ](./images/wiremock-arch.webp) + + * The API Request is sent from the Node.js backend to the External AccuWeather API, which then returns the API Response. + * Alternatively, when using WireMock, a Mocked API Request is sent to the WireMock server, and a Mocked API Response is returned. + + In this guide, you’ll learn how to: + + * Set up a non-containerized Node app to route requests to the containerized WireMock + * Set up a non-containerized Node app to fetch data from the external AccuWeather API. + + The application can be accessed at [dockersamples/wiremock-node-docker](https://github.com/dockersamples/wiremock-node-docker). + + +## Set up a non-containerized Node app to route requests to a containerized WireMock + +Let’s set up a non-containerized Node app to route requests to the WireMock container instead of the external AccuWeather API. Assuming that Node is already installed on your system, follow the steps: + +1. Navigate to the `accuweather-api` directory + + Make sure you're in the directory where your `package.json` file is located. + +2. Set the environment variable. + + Open `.env` file placed under `accuweather-api/` directory. Remove the old entries and ensure that it just contains the following single line. + + ```plaintext + API_ENDPOINT_BASE=http://localhost:8080 + ``` + + This will tell your Node.js application to use the WireMock server for API calls. + +3. Start the Node server + + Before you start the Node server, ensure that you have already installed the node packages listed in the package.json file by running `npm install`. + + ```console + npm install + npm run start + ``` + + You should see the following output: + + ```plaintext + > express-api-starter@1.2.0 start + > node src/index.js + + API_ENDPOINT_BASE: http://localhost:8080 + .. + Listening: http://localhost:5000 + ``` + + The output indicates that your Node application has successfully started. It highlights the project name and the `index.js` file as the application's entry point. The `index.js` file initiates the `getWeather.js` file located within the `src/api/` directory by utilizing the `require` function to import the `api` module and subsequently invoking the `getWeather` function. + + The `getWeather.js` file plays a pivotal role within your Node.js application. The code commences by incorporating the `dotenv` module, which instructs the application to load environment variables from a `.env` file. Depending on the value of the `API_ENDPOINT_BASE` variable, the application intelligently directs requests either to the WireMock server (if set to `http://localhost:8080`) or the AccuWeather API. In this scenario, the request is being routed to the WireMock server. + + This code snippet ensures that the `ACCUWEATHER_API_KEY` is only required when the application is not using WireMock, preventing errors and improving efficiency. + + ```javascript + require("dotenv").config(); + + const express = require("express"); + const axios = require("axios"); + + const router = express.Router(); + const API_ENDPOINT_BASE = process.env.API_ENDPOINT_BASE; + const API_KEY = process.env.ACCUWEATHER_API_KEY; + + console.log('API_ENDPOINT_BASE:', API_ENDPOINT_BASE); // Log after it's defined + console.log('ACCUWEATHER_API_KEY:', API_KEY); // Log after it's defined + + if (!API_ENDPOINT_BASE) { + throw new Error("API_ENDPOINT_BASE is not defined in environment variables"); + } + + // Only check for API key if not using WireMock + if (API_ENDPOINT_BASE !== 'http://localhost:8080' && !API_KEY) { + throw new Error("ACCUWEATHER_API_KEY is not defined in environment variables"); + } + // Function to fetch the location key for the city + async function fetchLocationKey(townName) { + const { data: locationData } = await + axios.get(`${API_ENDPOINT_BASE}/locations/v1/cities/search`, { + params: { q: townName, details: false, apikey: API_KEY }, + }); + return locationData[0]?.Key; + } + ``` + + Keep this terminal window open. + +4. Test the Mocked API + + Open a new terminal window and run the following command to test the mocked API: + + ```console + $ curl "http://localhost:5000/api/v1/getWeather?city=Bengaluru" + ``` + + You should see the following output: + + ```plaintext + {"city":"Bengaluru","temperature":27.1,"conditions":"Mostly cloudy","forecasts":[{"date":"2024-09-02T07:00:00+05:30","temperature":83,"conditions":"Partly sunny w/ t-storms"},{"date":"2024-09-03T07:00:00+05:30","temperature":83,"conditions":"Thunderstorms"},{"date":"2024-09-04T07:00:00+05:30","temperature":83,"conditions":"Intermittent clouds"},{"date":"2024-09-05T07:00:00+05:30","temperature":82,"conditions":"Dreary"},{"date":"2024-09-06T07:00:00+05:30","temperature":82,"conditions":"Dreary"}]}% + ``` + + This indicates that your Node.js application is now successfully routing requests to the WireMock container and receiving the mocked responses + + You might have noticed that you’re trying to use `http://localhost:5000` as the URL instead of port `8080`. This is because your Node.js application is running on port `5000`, and it's routing requests to the WireMock container that's listening on port `8080`. + + > [!TIP] + > Before you proceed to the next step, ensure that you stop the node application service. + +## Set up a non-containerized Node app to fetch data from the external AccuWeather API + + To enhance your Node.js application with real-time weather data, you can seamlessly integrate the AccuWeather API. This section of the guide will walk you through the steps involved in setting up a non-containerized Node.js application and fetching weather information directly from the AccuWeather API. + + +1. Create an AccuWeather API Key + + Sign up for a free AccuWeather developer account at[https://developer.accuweather.com/](https://developer.accuweather.com/). Within your account, create a new app by selecting `MY APPS` on the top navigation menu to get your unique API key. + + ![Diagram showing the AccuWeather Dashboard](images/wiremock-accuweatherapi.webp) + + [AccuWeather API](https://developer.accuweather.com/) is a web API that provides real-time weather data and forecasts. Developers can use this API to integrate weather information into their applications, websites, or other projects. + +2. Change directory to `accuweather-api` + + ```console + $ cd accuweather-api + ``` + +3. Set your AccuWeather API key using the `.env` file: + + > [!TIP] + > To prevent conflicts, ensure that any existing environment variables named `API_ENDPOINT_BASE` or `ACCUWEATHER_API_KEY` are removed before modifying the `.env` file. + + Run the following command on your terminal: + + ```console + unset API_ENDPOINT_BASE + unset ACCUWEATHER_API_KEY + ``` + + It’s time to set the environment variables in the `.env` file: + +4. Install the dependencies + + Run the following command to install the required packages: + + ```console + $ npm install + ``` + + This will install all the packages listed in your `package.json` file. These packages are essential for the project to function correctly. + + If you encounter any warnings related to deprecated packages, you can ignore them for now for this demonstration. + +5. Assuming that you don’t have a pre-existing Node server running on your system, go ahead and start the Node server by running the following command: + + ```console + $ npm run start + ``` + + You should see the following output: + + ```plaintext + > express-api-starter@1.2.0 start + > node src/index.js + + API_ENDPOINT_BASE: http://dataservice.accuweather.com + ACCUWEATHER_API_KEY: Date: Fri, 4 Oct 2024 14:01:55 +0530 Subject: [PATCH 05/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index 3ca5ab986795..c98d494b42fa 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -167,7 +167,7 @@ Now that you have learned how to launch Postgres and pre-seed the database using ### Stop the existing Postgres instance -Make sure you stop any running Postgres containers(along with volumes) to prevent port conflicts before you follow the steps: +Make sure you stop any running Postgres containers (along with volumes) to prevent port conflicts before you follow the steps: 1. Create a named volume. From 2869e1eb7f4c62422dbaee57b61043602a3956ec Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Sun, 6 Oct 2024 20:32:57 +0200 Subject: [PATCH 06/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index c98d494b42fa..22e08f085273 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -34,7 +34,7 @@ Launch a quick demo of Postgres by using the following steps: This example will launch a Postgres container, expose port `5432` onto the host to let a native-running application to connect to it with the password `mysecretpassword`. ```console - $ docker run --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=mysecretpassword postgres + $ docker run -d --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=mysecretpassword postgres ``` 2. Verify that Postgres is up and running by selecting the container and checking the logs on Docker Dashboard. From c3214153e9cb2544330904042fd6bacd64bbf98e Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Sun, 6 Oct 2024 20:33:12 +0200 Subject: [PATCH 07/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index 22e08f085273..d165e2acca49 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -78,7 +78,7 @@ Assuming that you have an existing Postgres database instance up and running, fo 1. Create an empty file named `seed.sql` and add the following content. - ```plaintext + ```sql CREATE DATABASE sampledb; \c sampledb From 5e4b5173c2ceba21e96fbd3f09248a94ccb6b98e Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Sun, 6 Oct 2024 20:48:54 +0200 Subject: [PATCH 08/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index d165e2acca49..07de37559f94 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -95,7 +95,7 @@ Assuming that you have an existing Postgres database instance up and running, fo ('Gamma', 'gamma@example.com'); ``` - The SQL commands create a new database called `sampledb`, connect to it, and define a `users` table. The table includes an auto-incrementing `id` as the primary key, a `name` field with a maximum length of 50 characters, and a unique `email` field with up to 100 characters. + The SQL script creates a new database called `sampledb`, connects to it, and creates a `users` table. The table includes an auto-incrementing `id` as the primary key, a `name` field with a maximum length of 50 characters, and a unique `email` field with up to 100 characters. After creating the table, the commands insert three users into the `users` table with their respective names and emails. This setup forms a basic database structure to store user information with unique email addresses. From 70c4efe0ddf136abbd6a3bf584a8cd841f61b70d Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Sun, 6 Oct 2024 20:49:21 +0200 Subject: [PATCH 09/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index 07de37559f94..de0359ba5e77 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -55,7 +55,7 @@ Launch a quick demo of Postgres by using the following steps: The `psql` is the PostgreSQL interactive shell that is used to connect to a Postgres database and let you start executing SQL commands. Assuming that you already have `psql` utility installed on your local system, it's time to connect to the Postgres database. Run the following command on your local terminal: ```console - psql -h localhost -U postgres + $ docker exec -it postgres psql -h localhost -U postgres ``` Enter `mysecretpassword` when prompted for the password. From 6914caefe2c6ca4174d633444cd46c3ded778b41 Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Sun, 6 Oct 2024 20:49:33 +0200 Subject: [PATCH 10/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index de0359ba5e77..308c5bade71d 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -97,7 +97,7 @@ Assuming that you have an existing Postgres database instance up and running, fo The SQL script creates a new database called `sampledb`, connects to it, and creates a `users` table. The table includes an auto-incrementing `id` as the primary key, a `name` field with a maximum length of 50 characters, and a unique `email` field with up to 100 characters. - After creating the table, the commands insert three users into the `users` table with their respective names and emails. This setup forms a basic database structure to store user information with unique email addresses. + After creating the table, the `INSERT` command inserts three users into the `users` table with their respective names and emails. This setup forms a basic database structure to store user information with unique email addresses. 2. Run the following command to seed the database From fda112f795041b7024a94e8311bb9d7fd5ba3f56 Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Sun, 6 Oct 2024 20:49:38 +0200 Subject: [PATCH 11/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index 308c5bade71d..2faa026b72a1 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -126,7 +126,7 @@ Assuming that you have an existing Postgres database instance up and running, fo 3. Run the following `psql` command to verify if the table named users is populated in the database `sampledb` or not. ```console - psql -h localhost -U postgres sampledb + $ docker exec -it postgres psql -h localhost -U postgres sampledb ``` Enter `mysecretpassword` when prompted for the password. You can now run `\l` in the `psql` terminal to list all the databases on the Postgres server. From 2987bb5463a1a35509cc287d27d8f11051ac95c8 Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Sun, 6 Oct 2024 20:49:44 +0200 Subject: [PATCH 12/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index 2faa026b72a1..d6ff525abb54 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -129,7 +129,7 @@ Assuming that you have an existing Postgres database instance up and running, fo $ docker exec -it postgres psql -h localhost -U postgres sampledb ``` - Enter `mysecretpassword` when prompted for the password. You can now run `\l` in the `psql` terminal to list all the databases on the Postgres server. + You can now run `\l` in the `psql` shell to list all the databases on the Postgres server. ```console sampledb=# \l From f8435cabaaa9eb9f40ca976c123732e6a2b26712 Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Sun, 6 Oct 2024 20:49:53 +0200 Subject: [PATCH 13/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index d6ff525abb54..90554ed12932 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -99,7 +99,7 @@ Assuming that you have an existing Postgres database instance up and running, fo After creating the table, the `INSERT` command inserts three users into the `users` table with their respective names and emails. This setup forms a basic database structure to store user information with unique email addresses. -2. Run the following command to seed the database +2. Seed the database. It’s time to feed the content of the `seed.sql` directly into the database by using the “<” operator. The command is used to execute a SQL script named `seed.sql` against a Postgres database named `sampledb`. From 4ff3dfabe5cfc9c1ea5c470c989b00ce9d7a8760 Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Sun, 6 Oct 2024 20:50:27 +0200 Subject: [PATCH 14/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index 90554ed12932..cbf64b18fb90 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -101,7 +101,7 @@ Assuming that you have an existing Postgres database instance up and running, fo 2. Seed the database. - It’s time to feed the content of the `seed.sql` directly into the database by using the “<” operator. The command is used to execute a SQL script named `seed.sql` against a Postgres database named `sampledb`. + It’s time to feed the content of the `seed.sql` directly into the database by using the `<` operator. The command is used to execute a SQL script named `seed.sql` against a Postgres database named `sampledb`. ```console psql -h localhost -U postgres < seed.sql From 57452323fda81fd896c90f2573463360ddc4f7cf Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Sun, 6 Oct 2024 20:50:38 +0200 Subject: [PATCH 15/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index cbf64b18fb90..25c5f8d24dda 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -104,7 +104,7 @@ Assuming that you have an existing Postgres database instance up and running, fo It’s time to feed the content of the `seed.sql` directly into the database by using the `<` operator. The command is used to execute a SQL script named `seed.sql` against a Postgres database named `sampledb`. ```console - psql -h localhost -U postgres < seed.sql + $ cat seed.sql | docker exec -i postgres psql -h localhost -U postgres -f- ``` > [!TIP] Running on Windows From ee0eba7f9b47c6b7b914d93155cb709b691e8fa8 Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Sun, 6 Oct 2024 20:51:49 +0200 Subject: [PATCH 16/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index 25c5f8d24dda..d5dceb5970cf 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -114,7 +114,7 @@ Assuming that you have an existing Postgres database instance up and running, fo psql -h localhost -U postgres -f seed.sql` ``` - Enter `mysecretpassword` when prompted for the password and once the query is executed, you will see the following results: + Once the query is executed, you will see the following results: ```plaintext CREATE DATABASE From b6fa7a18d6d806a86f91dda114fb5bf348539ca2 Mon Sep 17 00:00:00 2001 From: Ajeet Singh Raina Date: Sun, 6 Oct 2024 22:14:23 +0200 Subject: [PATCH 17/56] Removed psql instructions under the prerequisite --- content/guides/use-case/pre-seeding.md | 1 - 1 file changed, 1 deletion(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index d5dceb5970cf..54c33eb8ef27 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -23,7 +23,6 @@ The [official Docker image for Postgres](https://hub.docker.com/_/postgres) prov The following prerequisites are required to follow along with this how-to guide: - [Docker Desktop](https://www.docker.com/products/docker-desktop/) -- [Download](https://www.postgresql.org/download/) and Install PostgreSQL Client (`psql`) ## Launching Postgres From fe3512deda8c8298c24308dfe599f14ce34a044d Mon Sep 17 00:00:00 2001 From: Ajeet Singh Raina Date: Sun, 6 Oct 2024 23:04:10 +0200 Subject: [PATCH 18/56] Removed the statement that ask user to enter password --- content/guides/use-case/pre-seeding.md | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index 54c33eb8ef27..960ba8d3ce14 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -57,17 +57,7 @@ Launch a quick demo of Postgres by using the following steps: $ docker exec -it postgres psql -h localhost -U postgres ``` - Enter `mysecretpassword` when prompted for the password. - - ```console - Password for user postgres: - psql (15.8 (Homebrew), server 16.4 (Debian 16.4-1.pgdg120+1)) - WARNING: psql major version 15, server major version 16. - Some psql features might not work. - Type "help" for help. - - postgres=# - ``` + You can now execute any SQL queries or commands you need within the `psql` prompt. ## Pre-seed the Postgres database using a SQL script From e4e4555f14d518dabd69e8a956ffcf2e7f46ac6b Mon Sep 17 00:00:00 2001 From: Ajeet Singh Raina Date: Sun, 6 Oct 2024 23:08:58 +0200 Subject: [PATCH 19/56] Removed Windows Tips as we're using command --- content/guides/use-case/pre-seeding.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index 960ba8d3ce14..c191ebc21883 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -96,13 +96,6 @@ Assuming that you have an existing Postgres database instance up and running, fo $ cat seed.sql | docker exec -i postgres psql -h localhost -U postgres -f- ``` - > [!TIP] Running on Windows - > If you're using Windows, the < operator may result in an error. To avoid this, use the -f flag to specify the SQL file like this: - - ```console - psql -h localhost -U postgres -f seed.sql` - ``` - Once the query is executed, you will see the following results: ```plaintext From 7fd085204d85cc9bf19a4f56b1384f8ee2a439af Mon Sep 17 00:00:00 2001 From: Ajeet Singh Raina Date: Mon, 7 Oct 2024 00:33:33 +0200 Subject: [PATCH 20/56] Modified the volume section --- content/guides/use-case/pre-seeding.md | 173 ++++++------------------- 1 file changed, 39 insertions(+), 134 deletions(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index c191ebc21883..f1229458c0f3 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -11,7 +11,7 @@ In this guide, you will learn how to: - Use Docker to launch up a Postgres container - Pre-seed Postgres using a SQL script -- Pre-seed Postgres by using volumes to mount SQL files +- Pre-seed Postgres by copying SQL files into Docker image - Pre-seed Postgres using JavaScript code ## Using Postgres with Docker @@ -81,7 +81,7 @@ Assuming that you have an existing Postgres database instance up and running, fo INSERT INTO users (name, email) VALUES ('Alpha', 'alpha@example.com'), ('Beta', 'beta@example.com'), - ('Gamma', 'gamma@example.com'); + ('Gamma', 'gamma@example.com'); ``` The SQL script creates a new database called `sampledb`, connects to it, and creates a `users` table. The table includes an auto-incrementing `id` as the primary key, a `name` field with a maximum length of 50 characters, and a unique `email` field with up to 100 characters. @@ -151,162 +151,76 @@ Now that you have learned how to launch Postgres and pre-seed the database using Make sure you stop any running Postgres containers (along with volumes) to prevent port conflicts before you follow the steps: -1. Create a named volume. +1. Modify the `seed.sql` with the following entries: - Use the `docker volume create` command to create a named volume. - - ```console - $ docker volume create data_sql - ``` + ```sql + CREATE TABLE IF NOT EXISTS users ( + id SERIAL PRIMARY KEY, + name VARCHAR(50), + email VARCHAR(100) UNIQUE + ); + INSERT INTO users (name, email) VALUES + ('Alpha', 'alpha@example.com'), + ('Beta', 'beta@example.com'), + ('Gamma', 'gamma@example.com') + ON CONFLICT (email) DO NOTHING; + ``` + 2. Create a text file named `Dockerfile` and copy the following content. ```plaintext + # syntax=docker/dockerfile:1 FROM postgres:latest - VOLUME /docker-entrypoint-initdb.d + COPY seed.sql /docker-entrypoint-initdb.d/ ``` -3. Build the custom Docker image called `mynewpostgres`. - - ```console - $ docker build -t mynewpostgres . - ``` - -4. Run the following command to successfully mount the volume and run the Postgres container. - - Assuming that the existing `seed.sql` (used in previous steps) is placed under the same directory, run the following command: - - ```console - $ docker run --rm \ - -v $(pwd)/seed.sql:/sql-files/seed.sql \ - -v data_sql:/docker-entrypoint-initdb.d \ - mynewpostgres cp /sql-files/seed.sql /docker-entrypoint-initdb.d/ - ``` - - This command mounts your `seed.sql` file from the current directory (`$(pwd)/seed.sql`) into the temporary container at `/sql-files`, and then copies it into the `data_sql` named volume. - - > [!TIP] Running on Windows - > When running this command on Windows, use `${PWD}` (in uppercase and with curly brackets) instead of `$(pwd)`, and make sure to execute the command in PowerShell: + This Dockerfile copies the `seed.sql` script directly into the PostgreSQL container's initialization directory. - - ```console - $ docker run --rm \ - -v ${PWD}/seed.sql:/sql-files/seed.sql \ - -v data_sql:/docker-entrypoint-initdb.d \ - mynewpostgres cp /sql-files/seed.sql /docker-entrypoint-initdb.d/ - ``` - - This ensures that the volume is mounted correctly on the Windows systems. - -5. Now that your `seed.sql` file is in the `data_sql` volume, you can run your `mynewpostgres` image and mount the named volume: - - ```console - $ docker run --name mynewpostgres \ - -p 5432:5432 \ - -e POSTGRES_PASSWORD=mysecretpassword \ - -v data_sql:/docker-entrypoint-initdb.d \ - mynewpostgres - ``` - - Open a new terminal and run the following command to verify the database and tables seeded into the database. - ```console - psql -h localhost -U postgres sampledb - ``` - - Enter `mysecretpassword` when prompted for the password. Run the following command to verify if the table named users is populated in the database `sampledb` or not. - - ```console - sampledb=# select * from users; - id | name | email - ----+-------+------------------- - 1 | Alpha | alpha@example.com - 2 | Beta | beta@example.com - 3 | Gamma | gamma@example.com - 3 rows) - ``` - -Now that you’ve been shown how to pre-seed a database by using volumes, let’s see how you can simplify the whole process of seeding by using a single Docker Compose file. - -> [!TIP] -> Make sure you stop any running Postgres containers(along with volumes) to prevent port conflicts before you follow the next steps. - -First, you will need to create the following project directory structure: - -```console -$ tree -. -├── compose.yml -└── sql_files - └── seed.sql -``` -1. Start by writing the compose file - - This compose.yml file defines a Postgres service named `db` using the latest Postgres image, which sets up a database with the name `sampledb`, along with a user `postgres` and a password `mysecretpassword`. +3. Use Docker Compose. + + Using Docker Compose makes it even easier to manage and deploy the PostgreSQL container with the seeded database. This compose.yml file defines a Postgres service named `db` using the latest Postgres image, which sets up a database with the name `sampledb`, along with a user `postgres` and a password `mysecretpassword`. ```yaml services: - db: - image: postgres:latest - container_name: my_postgres_db - environment: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: mysecretpassword - POSTGRES_DB: sampledb + db: + build: + context: . + dockerfile: Dockerfile + container_name: my_postgres_db + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: mysecretpassword + POSTGRES_DB: sampledb ports: - "5432:5432" volumes: - data_sql:/var/lib/postgresql/data # Persistent data storage - - ./sql_files:/docker-entrypoint-initdb.d # Mount local sql file to seed the database - volumes: - data_sql: + volumes: + data_sql: ``` - It maps port `5432` on the host to the container's `5432`, let you access to the Postgres database from outside the container. It also defines two volumes: one (`data_sql`) for persisting the database data, ensuring that data is not lost when the container is stopped, and another volume that mounts the local `sql_files` directory into `/docker-entrypoint-initdb.d` within the container. This mounted directory contains a SQL file that is automatically executed when the Postgres container is initialized, allowing pre-seeding of the database. + It maps port `5432` on the host to the container's `5432`, let you access to the Postgres database from outside the container. It also define `data_sql` for persisting the database data, ensuring that data is not lost when the container is stopped. -2. Create a new directory `sql_files/` and copy the following `seed.sql` to this new directory: - ```plaintext - -- Ensure the users table is created in the sampledb database - - CREATE TABLE IF NOT EXISTS users ( - id SERIAL PRIMARY KEY, - name VARCHAR(50), - email VARCHAR(100) UNIQUE - ); - - -- Insert sample data into the users table - INSERT INTO users (name, email) VALUES - ('Alpha', 'alpha@example.com'), - ('Beta', 'beta@example.com'), - ('Gamma', 'gamma@example.com') - ON CONFLICT (email) DO NOTHING; - ``` - - This SQL script ensures that the users table is created in the `sampledb` database if it doesn't already exist. The table includes three columns: id, which is a serial primary key, name (a VARCHAR of 50 characters), and email (a VARCHAR of 100 characters that must be unique). The script also inserts three user records into the users table, but if a conflict occurs on the email field (i.e., if the email already exists), the insertion is skipped, ensuring no duplicate emails are added. 3. Bring up the Compose service. + Assuming that you've placed the `seed.sql` file in the same directory as the Dockerfile, execute the following command: + ```console - $ docker compose up -d + $ docker compose up -d --build ``` 4. It’s time to verify if the table `users` get populated with the data. ```console - psql -h localhost -U postgres sampledb + $ docker exec -it my_postgres_db psql -h localhost -U postgres sampledb ``` - Enter `mysecretpassword` when prompted for the password. - - ```plaintext - Password for user postgres: - psql (15.8 (Homebrew), server 16.4 (Debian 16.4-1.pgdg120+1)) - WARNING: psql major version 15, server major version 16. - Some psql features might not work. - Type "help" for help. - + ``` sampledb=# select * from users; id | name | email ----+-------+------------------- @@ -318,15 +232,6 @@ $ tree sampledb=# ``` - > [!TIP] - > If you're encountering the error 'more' is not recognized as an internal or external command when running queries in `psql` on a Windows system, this is likely due to an issue with the pager setting, which uses external programs like more or less to paginate query results. You can resolve this by turning off pagination within `psql` using the following command: - - ```console - \pset pager off - ``` - - To avoid running this command every time, you can permanently disable the pager by adding \pset pager off to your psqlrc.conf file, which is located in the `%APPDATA%\postgresql\` directory on Windows. This will ensure that query results are always displayed without invoking an external pager program. - ## Pre-seeding the database using JavaScript code From 94cbd0cd581440b61cd08b862feaf1ccd529d595 Mon Sep 17 00:00:00 2001 From: Ajeet Singh Raina Date: Mon, 7 Oct 2024 00:37:28 +0200 Subject: [PATCH 21/56] added a note for port mapping --- content/guides/use-case/pre-seeding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index f1229458c0f3..e52767faae55 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -204,7 +204,7 @@ Make sure you stop any running Postgres containers (along with volumes) to preve It maps port `5432` on the host to the container's `5432`, let you access to the Postgres database from outside the container. It also define `data_sql` for persisting the database data, ensuring that data is not lost when the container is stopped. - + It is important to note that the port mapping to the host is only necessary if you want to connect to the database from non-containerized programs. If you containerize the service that connects to the DB, you should connect to the database over a custom bridge network. 3. Bring up the Compose service. From 934ce4ce7aca0a8f99ccc3072ae39a19e93ff9a8 Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Mon, 7 Oct 2024 18:24:39 +0200 Subject: [PATCH 22/56] Update content/guides/use-case/wiremock.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/wiremock.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index cdf6a3660926..e95773a4f4ec 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -13,7 +13,7 @@ Imagine you have both an API and a frontend app, and you want to test how the fr ## Using WireMock with Docker -The official [Docker image for WireMock](https://hub.docker.com/r/wiremock/wiremock) provides a convenient way to deploy and manage WireMock instances. WireMock is available for various CPU architectures, including x64, armv7, and armv8, ensuring compatibility with different devices and platforms. You can learn more about WireMock standalone on the [WireMock docs site](https://wiremock.org/docs/standalone/docker/). +The official [Docker image for WireMock](https://hub.docker.com/r/wiremock/wiremock) provides a convenient way to deploy and manage WireMock instances. WireMock is available for various CPU architectures, including amd64, armv7, and armv8, ensuring compatibility with different devices and platforms. You can learn more about WireMock standalone on the [WireMock docs site](https://wiremock.org/docs/standalone/docker/). ### Prerequisites From 7da383d1824e8fe40c5ea3b0b37cf9b1e994de8d Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Mon, 7 Oct 2024 18:24:47 +0200 Subject: [PATCH 23/56] Update content/guides/use-case/wiremock.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/wiremock.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index e95773a4f4ec..76e0cff8b020 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -60,7 +60,7 @@ Launch a quick demo of WireMock by using the following steps: $ curl http://localhost:8080/api/v1/getWeather\?city\=Bengaluru ``` - It will return the following response: + It will return the following canned response with mock data: ```plaintext {"city":"Bengaluru","temperature":27.1,"conditions":"Mostly cloudy","forecasts":[{"date":"2024-09-02T07:00:00+05:30","temperature":83,"conditions":"Partly sunny w/ t-storms"},{"date":"2024-09-03T07:00:00+05:30","temperature":83,"conditions":"Thunderstorms"},{"date":"2024-09-04T07:00:00+05:30","temperature":83,"conditions":"Intermittent clouds"},{"date":"2024-09-05T07:00:00+05:30","temperature":82,"conditions":"Dreary"},{"date":"2024-09-06T07:00:00+05:30","temperature":82,"conditions":"Dreary"}]} From 88ecb1e81c1ec522423edd5c31cc3397ff960c5b Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Mon, 7 Oct 2024 18:24:57 +0200 Subject: [PATCH 24/56] Update content/guides/use-case/wiremock.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/wiremock.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index 76e0cff8b020..2b03e621ddf1 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -66,7 +66,12 @@ Launch a quick demo of WireMock by using the following steps: {"city":"Bengaluru","temperature":27.1,"conditions":"Mostly cloudy","forecasts":[{"date":"2024-09-02T07:00:00+05:30","temperature":83,"conditions":"Partly sunny w/ t-storms"},{"date":"2024-09-03T07:00:00+05:30","temperature":83,"conditions":"Thunderstorms"},{"date":"2024-09-04T07:00:00+05:30","temperature":83,"conditions":"Intermittent clouds"},{"date":"2024-09-05T07:00:00+05:30","temperature":82,"conditions":"Dreary"},{"date":"2024-09-06T07:00:00+05:30","temperature":82,"conditions":"Dreary"}]} ``` - You get this response due to the mapping file in the `wiremock-endpoint/mappings/getWeather/getWeatherBengaluru.json` file. + With WireMock, you define canned responses using mapping files. + For this request, the mock data is defined in the JSON file at + `wiremock-endpoint/mappings/getWeather/getWeatherBengaluru.json`. + + For more information about stubbing canned responses, refer to the + [WireMock documentation](https://wiremock.org/docs/stubbing/). ## Using WireMock in development From b90e6c43cbbbbd3292029a338bb51c89d858f131 Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Mon, 7 Oct 2024 18:25:03 +0200 Subject: [PATCH 25/56] Update content/guides/use-case/wiremock.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/wiremock.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index 2b03e621ddf1..3ea8fcb6e7d5 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -76,7 +76,7 @@ Launch a quick demo of WireMock by using the following steps: ## Using WireMock in development - Now that you have tried WireMock, let’s use it in development and testing. In this example, you will use a sample application that has a Node.js backend. This app stack has the following configuration: +Now that you have tried WireMock, let’s use it in development and testing. In this example, you will use a sample application that has a Node.js backend. This app stack has the following configuration: * **Local Development Environment**: The context in which the Node.js backend and WireMock are running. * **Node.js Backend**: Represents the backend application that handles HTTP requests. From 2661b7686727a18ec7313b84de82645fcd66c58d Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Mon, 7 Oct 2024 18:26:12 +0200 Subject: [PATCH 26/56] Update content/guides/use-case/wiremock.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/wiremock.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index 3ea8fcb6e7d5..d772f27ff04b 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -50,7 +50,7 @@ Launch a quick demo of WireMock by using the following steps: ![Diagram showing the WireMock container running on Docker Desktop ](./images/wiremock-using-docker.webp) - You can check the logs by selecting the **WireMock** container: + You can check the logs by selecting the `wiremock-node-docker` container: ![Diagram showing the logs of WireMock container running on Docker Desktop ](./images/wiremock-logs-docker-desktop.webp) From 61cf3c35e18a83a5dd7a8bf46a58fb209373a7b9 Mon Sep 17 00:00:00 2001 From: Ajeet Singh Raina Date: Mon, 7 Oct 2024 18:40:08 +0200 Subject: [PATCH 27/56] Removed bold cases --- content/guides/use-case/wiremock.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index d772f27ff04b..e84a73237e70 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -19,7 +19,7 @@ The official [Docker image for WireMock](https://hub.docker.com/r/wiremock/wirem The following prerequisites are required to follow along with this how-to guide: -* [Docker Desktop](https://www.docker.com/products/docker-desktop/) +- [Docker Desktop](https://www.docker.com/products/docker-desktop/) ### Launching WireMock @@ -78,10 +78,10 @@ Launch a quick demo of WireMock by using the following steps: Now that you have tried WireMock, let’s use it in development and testing. In this example, you will use a sample application that has a Node.js backend. This app stack has the following configuration: - * **Local Development Environment**: The context in which the Node.js backend and WireMock are running. - * **Node.js Backend**: Represents the backend application that handles HTTP requests. - * **External AccuWeather API**: The real API from which live weather data is fetched. - * **WireMock**: The mock server that simulates the API responses during testing. It runs as a Docker container. + - Local Development Environment: The context in which the Node.js backend and WireMock are running. + - Node.js Backend: Represents the backend application that handles HTTP requests. + - External AccuWeather API: The real API from which live weather data is fetched. + - WireMock: The mock server that simulates the API responses during testing. It runs as a Docker container. ![Diagram showing the architecture of WireMock in development ](./images/wiremock-arch.webp) From 9d3a9511a65f9403beacaf224b6873f37b214d6b Mon Sep 17 00:00:00 2001 From: Ajeet Singh Raina Date: Mon, 7 Oct 2024 18:46:18 +0200 Subject: [PATCH 28/56] Added instructions for Node and NPM --- content/guides/use-case/wiremock.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index e84a73237e70..072a23467b23 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -98,7 +98,13 @@ Now that you have tried WireMock, let’s use it in development and testing. In ## Set up a non-containerized Node app to route requests to a containerized WireMock -Let’s set up a non-containerized Node app to route requests to the WireMock container instead of the external AccuWeather API. Assuming that Node is already installed on your system, follow the steps: +Let’s set up a non-containerized Node app to route requests to the WireMock container instead of the external AccuWeather API. + +### Prerequisite + +- Install [Node and NPM](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) + +Follow the steps to setup a non-containerized Node application: 1. Navigate to the `accuweather-api` directory From 3880d2e9267ea350106af4d1882b008f37163b10 Mon Sep 17 00:00:00 2001 From: Ajeet Singh Raina Date: Mon, 7 Oct 2024 19:26:40 +0200 Subject: [PATCH 29/56] Moved the index.js file explanation up in step 3 --- content/guides/use-case/wiremock.md | 62 ++++++++++++++++------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index 072a23467b23..f700483a60c5 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -120,31 +120,13 @@ Follow the steps to setup a non-containerized Node application: This will tell your Node.js application to use the WireMock server for API calls. -3. Start the Node server - - Before you start the Node server, ensure that you have already installed the node packages listed in the package.json file by running `npm install`. - - ```console - npm install - npm run start - ``` - - You should see the following output: - - ```plaintext - > express-api-starter@1.2.0 start - > node src/index.js - - API_ENDPOINT_BASE: http://localhost:8080 - .. - Listening: http://localhost:5000 - ``` - - The output indicates that your Node application has successfully started. It highlights the project name and the `index.js` file as the application's entry point. The `index.js` file initiates the `getWeather.js` file located within the `src/api/` directory by utilizing the `require` function to import the `api` module and subsequently invoking the `getWeather` function. +3. Examine the Application Entry Point - The `getWeather.js` file plays a pivotal role within your Node.js application. The code commences by incorporating the `dotenv` module, which instructs the application to load environment variables from a `.env` file. Depending on the value of the `API_ENDPOINT_BASE` variable, the application intelligently directs requests either to the WireMock server (if set to `http://localhost:8080`) or the AccuWeather API. In this scenario, the request is being routed to the WireMock server. + - The main file for the application is `index.js`, located in the `accuweather-api/src/api` directory. + - This file starts the `getWeather.js` module, which is essential for your Node.js application. It uses the `dotenv` package to load environment variables from the`.env` file. + - Based on the value of `API_ENDPOINT_BASE`, the application routes requests either to the WireMock server (`http://localhost:8080`) or the AccuWeather API. In this setup, it uses the WireMock server. + - The code ensures that the `ACCUWEATHER_API_KEY` is required only if the application is not using WireMock, enhancing efficiency and avoiding errors. - This code snippet ensures that the `ACCUWEATHER_API_KEY` is only required when the application is not using WireMock, preventing errors and improving efficiency. ```javascript require("dotenv").config(); @@ -166,18 +148,44 @@ Follow the steps to setup a non-containerized Node application: // Only check for API key if not using WireMock if (API_ENDPOINT_BASE !== 'http://localhost:8080' && !API_KEY) { throw new Error("ACCUWEATHER_API_KEY is not defined in environment variables"); - } + } // Function to fetch the location key for the city async function fetchLocationKey(townName) { - const { data: locationData } = await + const { data: locationData } = await axios.get(`${API_ENDPOINT_BASE}/locations/v1/cities/search`, { params: { q: townName, details: false, apikey: API_KEY }, }); return locationData[0]?.Key; } + ``` + + +3. Start the Node server + + Before you start the Node server, ensure that you have already installed the node packages listed in the package.json file by running `npm install`. + + ```console + npm install + npm run start + ``` + + You should see the following output: + + ```plaintext + > express-api-starter@1.2.0 start + > node src/index.js + + API_ENDPOINT_BASE: http://localhost:8080 + .. + Listening: http://localhost:5000 ``` - - Keep this terminal window open. + + The output indicates that your Node application has successfully started. + Keep this terminal window open. + + + + 4. Test the Mocked API From 8fde962cda360024db686e4497523638838fa68c Mon Sep 17 00:00:00 2001 From: Ajeet Singh Raina Date: Mon, 7 Oct 2024 19:33:17 +0200 Subject: [PATCH 30/56] Added a prerequisite for WireMock --- content/guides/use-case/wiremock.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index f700483a60c5..3fc6d93a3863 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -103,6 +103,8 @@ Let’s set up a non-containerized Node app to route requests to the WireMock co ### Prerequisite - Install [Node and NPM](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) +- Ensure that WireMock container is up and running. (created in the previous step). + Follow the steps to setup a non-containerized Node application: @@ -183,10 +185,6 @@ Follow the steps to setup a non-containerized Node application: The output indicates that your Node application has successfully started. Keep this terminal window open. - - - - 4. Test the Mocked API Open a new terminal window and run the following command to test the mocked API: From c4a13675a2b1de7bb95cd4e062a2d4580a8bafc7 Mon Sep 17 00:00:00 2001 From: Ajeet Singh Raina Date: Mon, 7 Oct 2024 23:55:45 +0200 Subject: [PATCH 31/56] Added list of sections in the inital para --- content/guides/use-case/wiremock.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index 3fc6d93a3863..f44aa8b622cc 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -11,6 +11,12 @@ WireMock is an open-source tool that helps developers to create a mock server th Imagine you have both an API and a frontend app, and you want to test how the frontend interacts with the API. Using WireMock, you can set up a mock server to simulate the API's responses, allowing you to test the frontend behavior without relying on the actual API. This can be particularly helpful when the API is still under development or when you want to test different scenarios without affecting the actual API. WireMock supports both HTTP and HTTPS protocols and can simulate various response scenarios, including delays, errors, and different HTTP status codes. +In this guide, you'll learn how to: + +- Use Docker to launch up a WireMock container. +- Set up a non-containerized Node app to route requests to the containerized WireMock. +- Set up a non-containerized Node app to fetch data from the external AccuWeather API. + ## Using WireMock with Docker The official [Docker image for WireMock](https://hub.docker.com/r/wiremock/wiremock) provides a convenient way to deploy and manage WireMock instances. WireMock is available for various CPU architectures, including amd64, armv7, and armv8, ensuring compatibility with different devices and platforms. You can learn more about WireMock standalone on the [WireMock docs site](https://wiremock.org/docs/standalone/docker/). @@ -85,15 +91,8 @@ Now that you have tried WireMock, let’s use it in development and testing. In ![Diagram showing the architecture of WireMock in development ](./images/wiremock-arch.webp) - * The API Request is sent from the Node.js backend to the External AccuWeather API, which then returns the API Response. - * Alternatively, when using WireMock, a Mocked API Request is sent to the WireMock server, and a Mocked API Response is returned. - - In this guide, you’ll learn how to: - - * Set up a non-containerized Node app to route requests to the containerized WireMock - * Set up a non-containerized Node app to fetch data from the external AccuWeather API. - - The application can be accessed at [dockersamples/wiremock-node-docker](https://github.com/dockersamples/wiremock-node-docker). + - The API Request is sent from the Node.js backend to the External AccuWeather API, which then returns the API Response. + - Alternatively, when using WireMock, a Mocked API Request is sent to the WireMock server, and a Mocked API Response is returned. ## Set up a non-containerized Node app to route requests to a containerized WireMock From 22ab1688d84dfd32676e27dba4abe8d35aed915f Mon Sep 17 00:00:00 2001 From: Ajeet Singh Raina Date: Tue, 8 Oct 2024 00:08:19 +0200 Subject: [PATCH 32/56] Added missing instructions --- content/guides/use-case/wiremock.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index f44aa8b622cc..f9492c3e8bad 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -238,6 +238,13 @@ Follow the steps to setup a non-containerized Node application: It’s time to set the environment variables in the `.env` file: + ```plaintext + ACCUWEATHER_API_KEY=XXXXXX + API_ENDPOINT_BASE=http://dataservice.accuweather.com + ``` + + Make sure to populate `ACCUWEATHER_API_KEY` with the correct value. + 4. Install the dependencies Run the following command to install the required packages: @@ -263,7 +270,7 @@ Follow the steps to setup a non-containerized Node application: > node src/index.js API_ENDPOINT_BASE: http://dataservice.accuweather.com - ACCUWEATHER_API_KEY: Date: Thu, 17 Oct 2024 23:27:40 +0530 Subject: [PATCH 33/56] Modified wiremock guide --- content/guides/use-case/wiremock.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index f9492c3e8bad..e77f7b422bcf 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -14,8 +14,8 @@ Imagine you have both an API and a frontend app, and you want to test how the fr In this guide, you'll learn how to: - Use Docker to launch up a WireMock container. -- Set up a non-containerized Node app to route requests to the containerized WireMock. -- Set up a non-containerized Node app to fetch data from the external AccuWeather API. +- Use mock data in the local development without relying on an external API +- Use a Live API in production to fetch real-time weather data from AccuWeather. ## Using WireMock with Docker @@ -91,18 +91,17 @@ Now that you have tried WireMock, let’s use it in development and testing. In ![Diagram showing the architecture of WireMock in development ](./images/wiremock-arch.webp) - - The API Request is sent from the Node.js backend to the External AccuWeather API, which then returns the API Response. - - Alternatively, when using WireMock, a Mocked API Request is sent to the WireMock server, and a Mocked API Response is returned. + - In development, the Node.js backend sends a request to WireMock instead of the actual AccuWeather API. + - In production, it connects directly to the live AccuWeather API for real data. +## Use mock data in local development -## Set up a non-containerized Node app to route requests to a containerized WireMock - -Let’s set up a non-containerized Node app to route requests to the WireMock container instead of the external AccuWeather API. +Let’s set up a Node app to send requests to the WireMock container instead of the actual AccuWeather API. ### Prerequisite - Install [Node and NPM](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) -- Ensure that WireMock container is up and running. (created in the previous step). +- Ensure that WireMock container is up and running. (as setup earlier). Follow the steps to setup a non-containerized Node application: @@ -205,7 +204,7 @@ Follow the steps to setup a non-containerized Node application: > [!TIP] > Before you proceed to the next step, ensure that you stop the node application service. -## Set up a non-containerized Node app to fetch data from the external AccuWeather API +## Use a Live API in production to fetch real-time weather data from AccuWeather. To enhance your Node.js application with real-time weather data, you can seamlessly integrate the AccuWeather API. This section of the guide will walk you through the steps involved in setting up a non-containerized Node.js application and fetching weather information directly from the AccuWeather API. From b810a76626df8d5491ddeabd185adf01e6ccc7d5 Mon Sep 17 00:00:00 2001 From: Ajeet Singh Raina Date: Thu, 17 Oct 2024 23:50:05 +0530 Subject: [PATCH 34/56] linting and fixes --- content/guides/use-case/pre-seeding.md | 10 +++++----- content/guides/use-case/wiremock.md | 7 +++---- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index e52767faae55..5bea2580ada3 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -206,7 +206,7 @@ Make sure you stop any running Postgres containers (along with volumes) to preve It is important to note that the port mapping to the host is only necessary if you want to connect to the database from non-containerized programs. If you containerize the service that connects to the DB, you should connect to the database over a custom bridge network. -3. Bring up the Compose service. +4. Bring up the Compose service. Assuming that you've placed the `seed.sql` file in the same directory as the Dockerfile, execute the following command: @@ -214,13 +214,13 @@ Make sure you stop any running Postgres containers (along with volumes) to preve $ docker compose up -d --build ``` -4. It’s time to verify if the table `users` get populated with the data. +5. It’s time to verify if the table `users` get populated with the data. ```console $ docker exec -it my_postgres_db psql -h localhost -U postgres sampledb ``` - ``` + ```sql sampledb=# select * from users; id | name | email ----+-------+------------------- @@ -229,8 +229,8 @@ Make sure you stop any running Postgres containers (along with volumes) to preve 3 | Gamma | gamma@example.com (3 rows) - sampledb=# - ``` + sampledb=# + ``` ## Pre-seeding the database using JavaScript code diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index e77f7b422bcf..3f3e3c1975c4 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -160,7 +160,7 @@ Follow the steps to setup a non-containerized Node application: ``` -3. Start the Node server +4. Start the Node server Before you start the Node server, ensure that you have already installed the node packages listed in the package.json file by running `npm install`. @@ -183,7 +183,7 @@ Follow the steps to setup a non-containerized Node application: The output indicates that your Node application has successfully started. Keep this terminal window open. -4. Test the Mocked API +5. Test the Mocked API Open a new terminal window and run the following command to test the mocked API: @@ -204,11 +204,10 @@ Follow the steps to setup a non-containerized Node application: > [!TIP] > Before you proceed to the next step, ensure that you stop the node application service. -## Use a Live API in production to fetch real-time weather data from AccuWeather. +## Use a Live API in production to fetch real-time weather data from AccuWeather To enhance your Node.js application with real-time weather data, you can seamlessly integrate the AccuWeather API. This section of the guide will walk you through the steps involved in setting up a non-containerized Node.js application and fetching weather information directly from the AccuWeather API. - 1. Create an AccuWeather API Key Sign up for a free AccuWeather developer account at[https://developer.accuweather.com/](https://developer.accuweather.com/). Within your account, create a new app by selecting `MY APPS` on the top navigation menu to get your unique API key. From a2cf8af6b0bcdccbf11374e7cc932021cabd95c6 Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Fri, 18 Oct 2024 13:26:17 +0530 Subject: [PATCH 35/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index 5bea2580ada3..c0887985c4a5 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -316,8 +316,7 @@ It is called at the end of the script to initiate the seeding process. The try.. 4. Verify if the database is seeded correctly: ```console - psql -h localhost -U postgres sampledb - Password for user postgres: + $ docker exec -it postgres psql -h localhost -U postgres sampledb ``` Enter `mysecretpassword` when prompted for the password. You should see the list of items added to the table. From adb77c4c163c86ae385b9cf6e5aaa474100edb21 Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Fri, 18 Oct 2024 13:26:31 +0530 Subject: [PATCH 36/56] Update content/guides/use-case/wiremock.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/wiremock.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index 3f3e3c1975c4..20725ef91721 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -100,7 +100,7 @@ Let’s set up a Node app to send requests to the WireMock container instead of ### Prerequisite -- Install [Node and NPM](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) +- Install [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) - Ensure that WireMock container is up and running. (as setup earlier). From 092a8b6fd170cee397d735b2b21d6bf42396a765 Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Fri, 18 Oct 2024 13:26:40 +0530 Subject: [PATCH 37/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index c0887985c4a5..6d56eee247b3 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -319,8 +319,6 @@ It is called at the end of the script to initiate the seeding process. The try.. $ docker exec -it postgres psql -h localhost -U postgres sampledb ``` - Enter `mysecretpassword` when prompted for the password. You should see the list of items added to the table. - ```console sampledb=# select * from todos; id | task | completed From ded441529d202d9442b72ee281fa64cb26c2dc27 Mon Sep 17 00:00:00 2001 From: Ajeet Singh Raina Date: Fri, 18 Oct 2024 14:44:39 +0530 Subject: [PATCH 38/56] avoid exposing API keys in logs --- content/guides/use-case/wiremock.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index 20725ef91721..89b562af042b 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -159,6 +159,26 @@ Follow the steps to setup a non-containerized Node application: } ``` + > [!TIP] + > For the production environment, it's recommended not to expose API keys details in logs. Instead, you can log a placeholder message to indicate whether the API key is loaded: + + ``` + const API_KEY = process.env.ACCUWEATHER_API_KEY; + + console.log('API_ENDPOINT_BASE:', API_ENDPOINT_BASE); // Log after it's defined + console.log('ACCUWEATHER_API_KEY is set:', !!API_KEY); // Log a boolean value instead of the actual key + + if (!API_ENDPOINT_BASE) { + throw new Error("API_ENDPOINT_BASE is not defined in environment variables"); + } + + // Only check for API key if not using WireMock + if (API_ENDPOINT_BASE !== 'http://localhost:8080' && !API_KEY) { + throw new Error("ACCUWEATHER_API_KEY is not defined in environment variables"); + } + ``` + + > This approach ensures that you only log whether the key is set without revealing its value. 4. Start the Node server From d67d37019062811ad1f85bacf30a116f60090ac1 Mon Sep 17 00:00:00 2001 From: Ajeet Singh Raina Date: Fri, 18 Oct 2024 14:54:29 +0530 Subject: [PATCH 39/56] Fixed formatting --- content/guides/use-case/wiremock.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index 89b562af042b..552af342551a 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -159,14 +159,14 @@ Follow the steps to setup a non-containerized Node application: } ``` - > [!TIP] - > For the production environment, it's recommended not to expose API keys details in logs. Instead, you can log a placeholder message to indicate whether the API key is loaded: + > [!TIP] + > For the production environment, it's recommended not to expose API keys details in logs. Instead, you can log a placeholder message to indicate whether the API key is loaded: - ``` - const API_KEY = process.env.ACCUWEATHER_API_KEY; + ```javascript + const API_KEY = process.env.ACCUWEATHER_API_KEY; - console.log('API_ENDPOINT_BASE:', API_ENDPOINT_BASE); // Log after it's defined - console.log('ACCUWEATHER_API_KEY is set:', !!API_KEY); // Log a boolean value instead of the actual key + console.log('API_ENDPOINT_BASE:', API_ENDPOINT_BASE); // Log after it's defined + console.log('ACCUWEATHER_API_KEY is set:', !!API_KEY); // Log a boolean value instead of the actual key if (!API_ENDPOINT_BASE) { throw new Error("API_ENDPOINT_BASE is not defined in environment variables"); @@ -176,9 +176,9 @@ Follow the steps to setup a non-containerized Node application: if (API_ENDPOINT_BASE !== 'http://localhost:8080' && !API_KEY) { throw new Error("ACCUWEATHER_API_KEY is not defined in environment variables"); } - ``` + ``` - > This approach ensures that you only log whether the key is set without revealing its value. + > This approach ensures that you only log whether the key is set without revealing its value. 4. Start the Node server From 08aa824f96687f261938bbdb8e5b6231734dbd4d Mon Sep 17 00:00:00 2001 From: Ajeet Singh Raina Date: Mon, 21 Oct 2024 18:08:07 +0530 Subject: [PATCH 40/56] Fixed the result for Wiremock --- content/guides/use-case/wiremock.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index 552af342551a..4d9f0d5f9f61 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -288,7 +288,7 @@ Follow the steps to setup a non-containerized Node application: > node src/index.js API_ENDPOINT_BASE: http://dataservice.accuweather.com - ACCUWEATHER_API_KEY: Date: Mon, 21 Oct 2024 19:04:15 +0530 Subject: [PATCH 41/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 1 + 1 file changed, 1 insertion(+) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index 6d56eee247b3..c4e3aa16f8e9 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -59,6 +59,7 @@ Launch a quick demo of Postgres by using the following steps: You can now execute any SQL queries or commands you need within the `psql` prompt. + Use `\q` or `\quit` to exit from the Postgres interactive shell. ## Pre-seed the Postgres database using a SQL script Now that you've familiarized yourself with Postgres, it's time to see how to pre-seed it with sample data. In this demonstration, you'll first create a script that holds SQL commands. The script defines the database, and table structure and inserts sample data. Then you will connect the database to verify the data. From 11621c42b6dfc57a7bb083c321f5286bf53a993c Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Mon, 21 Oct 2024 19:04:28 +0530 Subject: [PATCH 42/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index c4e3aa16f8e9..fc284fe62a31 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -152,6 +152,10 @@ Now that you have learned how to launch Postgres and pre-seed the database using Make sure you stop any running Postgres containers (along with volumes) to prevent port conflicts before you follow the steps: +```console +$ docker container stop postgres +``` + 1. Modify the `seed.sql` with the following entries: ```sql From 18df690be51745699ec1af2aae0ff357859b7436 Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Mon, 21 Oct 2024 19:04:35 +0530 Subject: [PATCH 43/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index fc284fe62a31..fa6303a866af 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -148,8 +148,6 @@ In Docker, mounting refers to making files or directories from the host system a Now that you have learned how to launch Postgres and pre-seed the database using an SQL script, it’s time to learn how to mount an SQL file directly into the Postgres containers’ initialisation directory (`/docker-entrypoint-initdb.d`). The `/docker-entrypoint-initdb.d` is a special directory in PostgreSQL Docker containers that is used for initializing the database when the container is first started -### Stop the existing Postgres instance - Make sure you stop any running Postgres containers (along with volumes) to prevent port conflicts before you follow the steps: ```console From 6c50e2acf39994fe338f2832e7abe6dd7708b87c Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Mon, 21 Oct 2024 19:04:49 +0530 Subject: [PATCH 44/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index fa6303a866af..276477a53e7a 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -142,7 +142,7 @@ Assuming that you have an existing Postgres database instance up and running, fo Use `\q` or `\quit` to exit from the Postgres interactive shell. -## Pre-seeding the database by using Volumes to mount SQL files +## Pre-seed the database by bind-mounting a SQL script In Docker, mounting refers to making files or directories from the host system accessible within a container. This let you to share data or configuration files between the host and the container, enabling greater flexibility and persistence. From 542105e4c1e00042e540df35e1034753aa8e7e18 Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Mon, 21 Oct 2024 19:04:58 +0530 Subject: [PATCH 45/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index 276477a53e7a..2a4fafbbd96b 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -131,7 +131,7 @@ Assuming that you have an existing Postgres database instance up and running, fo To retrieve all the data from the users table, enter the following query: ```console - sampledb=# SELECT * from users; + sampledb=# SELECT * FROM users; id | name | email ----+-------+------------------- 1 | Alpha | alpha@example.com From 4ea1b7b1e5ee43bea4cabc0c3ef433a8d2d1c127 Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Mon, 21 Oct 2024 19:10:39 +0530 Subject: [PATCH 46/56] Update content/guides/use-case/wiremock.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/wiremock.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index 4d9f0d5f9f61..e1031013dfb6 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -197,7 +197,7 @@ Follow the steps to setup a non-containerized Node application: API_ENDPOINT_BASE: http://localhost:8080 .. - Listening: http://localhost:5000 + Listening: http://localhost:5001 ``` The output indicates that your Node application has successfully started. From d3e870e433200be08ac86e1191ad592ee6469f8b Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Mon, 21 Oct 2024 19:10:47 +0530 Subject: [PATCH 47/56] Update content/guides/use-case/wiremock.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/wiremock.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index e1031013dfb6..d493b55c5e60 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -208,7 +208,7 @@ Follow the steps to setup a non-containerized Node application: Open a new terminal window and run the following command to test the mocked API: ```console - $ curl "http://localhost:5000/api/v1/getWeather?city=Bengaluru" + $ curl "http://localhost:5001/api/v1/getWeather?city=Bengaluru" ``` You should see the following output: From e6daae7d6a667d590f7e622da937416e973b397b Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Mon, 21 Oct 2024 19:10:55 +0530 Subject: [PATCH 48/56] Update content/guides/use-case/wiremock.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/wiremock.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index d493b55c5e60..4ba00a3dd043 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -219,7 +219,7 @@ Follow the steps to setup a non-containerized Node application: This indicates that your Node.js application is now successfully routing requests to the WireMock container and receiving the mocked responses - You might have noticed that you’re trying to use `http://localhost:5000` as the URL instead of port `8080`. This is because your Node.js application is running on port `5000`, and it's routing requests to the WireMock container that's listening on port `8080`. + You might have noticed that you’re trying to use `http://localhost:5001` as the URL instead of port `8080`. This is because your Node.js application is running on port `5001`, and it's routing requests to the WireMock container that's listening on port `8080`. > [!TIP] > Before you proceed to the next step, ensure that you stop the node application service. From 91b4aa270675fbe37841c0e5be0c6df48e4aa16d Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Mon, 21 Oct 2024 19:11:02 +0530 Subject: [PATCH 49/56] Update content/guides/use-case/wiremock.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/wiremock.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index 4ba00a3dd043..bf93406ab45e 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -289,7 +289,7 @@ Follow the steps to setup a non-containerized Node application: API_ENDPOINT_BASE: http://dataservice.accuweather.com ACCUWEATHER_API_KEY is set: true - Listening: http://localhost:5000 + Listening: http://localhost:5001 ``` Keep this terminal window open. From 8ca3301bd4cb7e68fbcda83576f5eb7033660f26 Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Mon, 21 Oct 2024 19:11:14 +0530 Subject: [PATCH 50/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index 2a4fafbbd96b..5969a0127195 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -224,7 +224,7 @@ $ docker container stop postgres ``` ```sql - sampledb=# select * from users; + sampledb=# SELECT * FROM users; id | name | email ----+-------+------------------- 1 | Alpha | alpha@example.com From dd6d98ce4d652ffe8a304883f15b4a4e1d9a3870 Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Mon, 21 Oct 2024 19:11:31 +0530 Subject: [PATCH 51/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index 5969a0127195..5ce73c5ff559 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -236,7 +236,7 @@ $ docker container stop postgres ``` -## Pre-seeding the database using JavaScript code +## Pre-seed the database using JavaScript code Now that you have learned how to seed the database using various methods like SQL script, mounting volumes etc., it's time to try to achieve it using JavaScript code. From 8c0a9e01b7b8dfd4e646dd4e75f65ccffb3d2680 Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Mon, 21 Oct 2024 19:11:40 +0530 Subject: [PATCH 52/56] Update content/guides/use-case/pre-seeding.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/pre-seeding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index 5ce73c5ff559..1a81fe9ef05a 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -323,7 +323,7 @@ It is called at the end of the script to initiate the seeding process. The try.. ``` ```console - sampledb=# select * from todos; + sampledb=# SELECT * FROM todos; id | task | completed ----+----------------+----------- 1 | Watch netflix | f From a9a1d187f09de5205880fb6cb5fa5e38a4b579eb Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Mon, 21 Oct 2024 19:11:51 +0530 Subject: [PATCH 53/56] Update content/guides/use-case/wiremock.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/wiremock.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index bf93406ab45e..aa5801f9fc2f 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -101,7 +101,7 @@ Let’s set up a Node app to send requests to the WireMock container instead of ### Prerequisite - Install [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) -- Ensure that WireMock container is up and running. (as setup earlier). +- Ensure that WireMock container is up and running (see [Launching Wiremock](#launching-wiremock) Follow the steps to setup a non-containerized Node application: From b43b739efaa7485929126396631bb9a81369ac11 Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Mon, 21 Oct 2024 19:12:02 +0530 Subject: [PATCH 54/56] Update content/guides/use-case/wiremock.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/wiremock.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index aa5801f9fc2f..d206b5244d7f 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -139,7 +139,7 @@ Follow the steps to setup a non-containerized Node application: const API_KEY = process.env.ACCUWEATHER_API_KEY; console.log('API_ENDPOINT_BASE:', API_ENDPOINT_BASE); // Log after it's defined - console.log('ACCUWEATHER_API_KEY:', API_KEY); // Log after it's defined + console.log('ACCUWEATHER_API_KEY is set:', !!API_KEY); // Log boolean instead of actual key if (!API_ENDPOINT_BASE) { throw new Error("API_ENDPOINT_BASE is not defined in environment variables"); From 4e95a4629547398b80e467282298edc9715e89c6 Mon Sep 17 00:00:00 2001 From: "Ajeet Singh Raina, Docker Captain, ARM Innovator" Date: Mon, 21 Oct 2024 19:12:19 +0530 Subject: [PATCH 55/56] Update content/guides/use-case/wiremock.md Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/guides/use-case/wiremock.md | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/content/guides/use-case/wiremock.md b/content/guides/use-case/wiremock.md index d206b5244d7f..78e61f9d92b0 100644 --- a/content/guides/use-case/wiremock.md +++ b/content/guides/use-case/wiremock.md @@ -159,27 +159,6 @@ Follow the steps to setup a non-containerized Node application: } ``` - > [!TIP] - > For the production environment, it's recommended not to expose API keys details in logs. Instead, you can log a placeholder message to indicate whether the API key is loaded: - - ```javascript - const API_KEY = process.env.ACCUWEATHER_API_KEY; - - console.log('API_ENDPOINT_BASE:', API_ENDPOINT_BASE); // Log after it's defined - console.log('ACCUWEATHER_API_KEY is set:', !!API_KEY); // Log a boolean value instead of the actual key - - if (!API_ENDPOINT_BASE) { - throw new Error("API_ENDPOINT_BASE is not defined in environment variables"); - } - - // Only check for API key if not using WireMock - if (API_ENDPOINT_BASE !== 'http://localhost:8080' && !API_KEY) { - throw new Error("ACCUWEATHER_API_KEY is not defined in environment variables"); - } - ``` - - > This approach ensures that you only log whether the key is set without revealing its value. - 4. Start the Node server Before you start the Node server, ensure that you have already installed the node packages listed in the package.json file by running `npm install`. From 2f859f2352ec329d27631ae8add004486035ee06 Mon Sep 17 00:00:00 2001 From: Ajeet Singh Raina Date: Mon, 21 Oct 2024 19:22:28 +0530 Subject: [PATCH 56/56] Fixing linting issues --- content/guides/use-case/pre-seeding.md | 1 + 1 file changed, 1 insertion(+) diff --git a/content/guides/use-case/pre-seeding.md b/content/guides/use-case/pre-seeding.md index 1a81fe9ef05a..ecad45f02ac7 100644 --- a/content/guides/use-case/pre-seeding.md +++ b/content/guides/use-case/pre-seeding.md @@ -60,6 +60,7 @@ Launch a quick demo of Postgres by using the following steps: You can now execute any SQL queries or commands you need within the `psql` prompt. Use `\q` or `\quit` to exit from the Postgres interactive shell. + ## Pre-seed the Postgres database using a SQL script Now that you've familiarized yourself with Postgres, it's time to see how to pre-seed it with sample data. In this demonstration, you'll first create a script that holds SQL commands. The script defines the database, and table structure and inserts sample data. Then you will connect the database to verify the data.