Wednesday, July 14, 2021

how to pass dockerfile argument from docker-compose file?

 It should be very convenient and dynamic, if we can set our environment variable on docker build time.

since I want to turn graphql playground on and off during the production deployment, I already use the 

NODE_ENV to control the playground feature in the .env file.

in .net file

NODE_ENV=dev

GraphQLModule.forRoot({
      playground: process.env.NODE_ENV === 'dev',
      debug: process.env.NODE_ENV === 'dev',
      autoSchemaFile: true,
    }),


we can use ARG to set a variable in the dockerfile that we can pass in during docker build run.

ARG node_env_var
ENV NODE_ENV=$node_env_var
RUN echo $node_env_var

here is the full content of Dockfile

FROM node:14 as production

ARG node_env_var
ENV NODE_ENV=$node_env_var
RUN echo $node_env_var

WORKDIR /usr/src/api

COPY package.json .
COPY yarn.lock .

RUN yarn global add @nestjs/cli

RUN yarn install --production=true

## install NIC s a computer networking utility for reading from and 
# writing to network connections using TCP or UDP.
RUN apt-get -q update && apt-get -qy install netcat

COPY . .

RUN yarn build

CMD ["sh", "-c", "yarn typeorm migration:run && yarn start:prod"]



in the Docker-compose.yml file we can set the args variable. when I run the deployment in the production environment, i can simply change the node_env_var: production

build
            contextserver
            targetproduction
            dockerfileDockerfile
            args:
                node_env_vardev

here is the docker-compse.yml file

version"3.8"

services:
    mysqldb:
        imagemysql
        environment
            - MYSQL_ROOT_PASSWORD=Mys0l@123456
            - MYSQL_DATABASE=hyrecar
        ports
            - 3306:3306
        command--default-authentication-plugin=mysql_native_password
        networks:
            - shared-network
        volumes
            - db-config:/etc/mysql
            - db-data:/var/lib/mysql
            - ./db/backup/files:/data_backup/data
       
    #acting as a proxy

    nginx:
        imagenginx:latest
        container_namenginx-prod
        volumes
            - ./nginx/nginx.conf:/etc/nginx/nginx.conf
        ports
            - 81:80
        command/bin/sh -c "nginx -g 'daemon off;'"    
        depends_on
            api-prod:
                conditionservice_healthy
            app-prod:
                conditionservice_started
        networks
            - shared-network

    api-prod:
        container_namenestjs_api_prod
        imagenestjs_api_prod:1.0.0.0
        build
            contextserver
            targetproduction
            dockerfileDockerfile
            args:
                node_env_vardev
        commandsh -c './bin/wait-for -t 0 mysqldb:3306 -- yarn start:prod'
        depends_on
            - mysqldb
        networks
            - shared-network
        ports
            - 9000:9000
        restartunless-stopped
        healthcheck:
            test: ["CMD""curl""http://api-prod:9000"]
            interval5s
            timeout3s
            retries6     
        
    app-prod:
        container_namerect_app_prod
        imagerect_app_prod:1.0.0
        build:
            contextweb
            targetproduction
            dockerfileDockerfile
        commandyarn run start:prod
        ports
            - 3000:3000
        networks
            - shared-network
        restartunless-stopped

#intialize network
networks
    shared-network:

#Initializing docker compose volumes
volumes
    db-config:
    db-data:


for development and test environment deployment.

set node_env_var: dev in docker-compose.yml 

run docker-compose build to rebuilt the container

execute docker-compose up to run all containers

in the production, we just need to change node_env_var: production

then we can run docker-compose build & docker-compose up to turn off graphql playground feature for security reason.

 Please Note you can not simply update the variable in the docker-compose yaml file and run docker-compose up since the variable is passing in at docker-compose build time, not the run time. so We have to run docker-compose build process to take the effect.



Monday, July 12, 2021

how to disable graphql in Apollo Server?

 It is very convenient to have graphql playground enable on the Apollo Server during the development.

However there will be a security issue if we have this feature enable on the production server. we must 

turn off this feature in the production environment.  we can easily turn on/off this feature on the Apollo

Server configuration setup. I create a environment variable to control this feature.

const apolloServer = new ApolloServer({
        schema: await buildSchema({
          resolvers: [UserResolvers]
        }),
        context: ({ reqres }) => ({ reqres }),
        introspection: process.env.DEV_ENV==="development",
        playground: process.env.DEV_ENV==="development",});

handy timeout function to test for loading functionality?

During the development, we will add a loading indicator to the page to notify the user that data is loading.

however, the local environment might be able to test loading indicator since the speed is too fast.

the alternative way to do so is to add a small time out function to hold the execution of data loading function. then we can check the indicator will be shown or not.

const wait = (timeout: number) => new Promise((rs) => setTimeout(rs, timeout));

then we can use it in the data loading function 

 await wait(6000);

The data loading function will be paused for 6 second. That is enough for us to see the loading indicator spinning in the page.

I recommand to add this package to your project for loading indicator.

yarn add react-spinners

import MoonLoader from "react-spinners/MoonLoader";

add this to the render section

 <MoonLoader loading size={20} />






how to fix the a component or section is not show in React on launch or refreshing the browser?

 I use React-Carousel to implement a carousel for my app. however i found something is weird. the carousel is functiong well during the run. However I refresh the browser with F5 key, the carousel disappear. here is the snippet of code for the carousel.

 return <CarContainer>

             <Carousel value={current} onChange={setCurrent} slides={
cars.map(item=><Car {...item} />)}
            plugins={[
                "clickToChange",
                {
                  resolve: slidesToShowPlugin,
                  options: {
                    numberOfSlides: 3,
                  },
                },
              ]}
              
              breakpoints={{
                640: {
                  plugins: [
                    "clickToChange",
                    {
                      resolve: slidesToShowPlugin,
                      options: {
                        numberOfSlides: 1,
                      },
                    },
                  ],
                },
                900: {
                  plugins: [
                    {
                      resolve: slidesToShowPlugin,
                      options: {
                        numberOfSlides: 2,
                      },
                    },
                  ],
                },
              }}
            /><Dots value={current} onChange={setCurrent} number={numberOfDots}/>
        </CarContainer>
the root cause of this issue is that the cars object is still null, whenn it 
render during the refresh.
slides={cars.map(item=><Car {...item} />)}
the safe way and best practice is to make sure the data is ready before the 
component rendering. since the component will not render after the data 
is ready, unless we update the cars object in the useEffect hook. 
We can either check if cars object is null return null to prevent the 
carousel render. if(!cars) return null;
or we can use the inline conditional expression wiht logical && operator.

 return cars && <CarContainer>

             <Carousel value={current} onChange={setCurrent} slides={
cars.map(item=><Car {...item} />)}
            plugins={[
                "clickToChange",
                {
                  resolve: slidesToShowPlugin,
                  options: {
                    numberOfSlides: 3,
                  },
                },
              ]}
              
              breakpoints={{
                640: {
                  plugins: [
                    "clickToChange",
                    {
                      resolve: slidesToShowPlugin,
                      options: {
                        numberOfSlides: 1,
                      },
                    },
                  ],
                },
                900: {
                  plugins: [
                    {
                      resolve: slidesToShowPlugin,
                      options: {
                        numberOfSlides: 2,
                      },
                    },
                  ],
                },
              }}
        /><Dots value={current} onChange={setCurrent} number={numberOfDots}/>
        </CarContainer>

Saturday, July 10, 2021

the guide to setup NestJS, TypeORM, MySQL,GraphQL for Backend Development

 here is a step to follow in order to setup a backend development with TypeORM, MySQL

1. install NestJS CLI

    yarn add -g @nestjs/cli

2. create a nestjs app

    nest new my-project

3. install @nestjs/typerom typreorm mysql2 (mysql 2 is much typescript friendly than mysql)

    yarn add @nestjs/typeorm typeorm mysql2 

4. create a TypeORM config JSON file to store typeorm configuation.

    touch ormconfig.json

5. paste the following into the ormconfig.json file

    {

   "type": "mysql",
   "host": "localhost",
   "port": 3306,
   "username": "test",
   "password": "test",
   "database": "test",
   "synchronize": true,
   "logging": false,
   "entities": [
      "src/entity/**/*.ts"
   ],
   "migrations": [
      "src/migration/**/*.ts"
   ],
   "subscribers": [
      "src/subscriber/**/*.ts"
   ]
}

6. add @nestjs/config package to the project so that we can use ConfigureModule module to access the configuration file.

    yarn add @nestjs/config 

7.  add a database module to the project

    touch database.module.ts

8. add the following code the database.module.ts to setup the database connection.

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Connection } from 'typeorm';

@Module({
  imports: [TypeOrmModule.forRoot()],
  exports: [TypeOrmModule],
})
export class DatabaseModule {
  constructor(connectionConnection) {
    if (connection.isConnected) {
      console.log('DB connected Successfully');
    }
  }
}

9. add DatabaseModule to the app.module.ts file    

import { Module } from '@nestjs/common';

import { ConfigModule } from '@nestjs/config';

import { AppController } from './app.controller';
import { AppService } from './app.service';
import { DatabaseModule } from './database/database.module';

@Module({
  imports: [ConfigModule.forRoot(), DatabaseModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}


10. execute yarn start to launch the project and you will see the DB connection had been established.

DB connected Successfully

[Nest] 16320  - 2021-07-10, 9:02:02 p.m.     LOG [InstanceLoader] TypeOrmCoreModule dependencies initialized +26ms

[Nest] 16320  - 2021-07-10, 9:02:02 p.m.     LOG [InstanceLoader] DatabaseModule dependencies initialized +1ms

[Nest] 16320  - 2021-07-10, 9:02:02 p.m.     LOG [RoutesResolver] AppController {/}: +5ms

[Nest] 16320  - 2021-07-10, 9:02:02 p.m.     LOG [RouterExplorer] Mapped {/, GET} route +3ms

[Nest] 16320  - 2021-07-10, 9:02:02 p.m.     LOG [NestApplication] Nest application successfully started +2ms

11. add Graphql to the project

yarn add @nestjs/graphql graphql-tools graphql apollo-server-express

you might encounter  missing package errors here, you can manually add them as following

yarn add ts-morph @apollo/gateway


12. add GraphQLModule to the app.module.ts to initialze GraphQL Module

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { GraphQLModule } from '@nestjs/graphql';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ComponentModule } from './components/comonents.module';
import { DatabaseModule } from './database/database.module';

@Module({
  imports: [
    ConfigModule.forRoot(),
    DatabaseModule,
    GraphQLModule.forRoot({
      playground: process.env.NODE_DEV === 'dev',
      debug: process.env.NODE_DEV === 'dev',
      autoSchemaFile: true,
    }),
    ComponentModule,
  ],
  controllers: [AppController],
  providers: [AppService],

})
export class AppModule {}


Further reading

NestJS Dccument

TypeORM - Amazing ORM for TypeScript and JavaScript ES7



 


How to fix typescript error in react-carousel Breakpoints section configuration?

i try to use react-carousel to implement a carousel for a component rotation.

here is my snippet of code

 <Carousel value={current} onChange={setCurrent} slides={cars}
            plugins={[
                "clickToChange",
                {
                  resolve: slidesToShowPlugin,
                  options: {
                    numberOfSlides: 3,
                  },
                },
              ]}
              
              breakpoints={{
                640: {
                  plugins: [
                    "clickToChange",
                    {
                      resolve: slidesToShowPlugin,
                      options: {
                        numberOfSlides: 1,
                      },
                    },
                  ],
                },
                900: {
                  plugins: [
                    {
                      resolve: slidesToShowPlugin,
                      options: {
                        numberOfSlides: 2,
                      },
                    },
                  ],
                },
              }}
            /><Dots value={current} onChange={setCurrent} number={numberOfDots}/>

however, there is an error indicator to show that there is a problem with No overload matches for this call. 


TypeScript error in /home/yang/pfc_frontend/src/components/YACarousel/index.tsx(23,11):

No overload matches this call.
  Overload 1 of 2, '(props: Readonly<CarouselProps>): default', gave the 
following error.Type '{ 640: { plugins: { resolve: CarouselPluginFunc; options: { 
numberOfSlides: number; }; }[]; }; 900: { plugins: { resolve: CarouselPluginFunc; 
options: { numberOfSlides:number; }; }[]; }; }' is not assignable to type  
'Pick<CarouselProps, "className" | "offset" | "onChange" | "draggable" | "value" | 
"plugins" | "itemWidth" | "slides" | "animationSpeed">'.
      Object literal may only specify known properties, and '640' does not exist in type 
'Pick<CarouselProps, "className" | "offset" | "onChange" | "draggable" | "value" | 
"plugins" | "itemWidth" | "slides" | "animationSpeed">'.
  Overload 2 of 2, '(props: CarouselProps, context?: any): default', gave the following 
error.
    Type '{ 640: { plugins: { resolve: CarouselPluginFunc; options: { numberOfSlides
number; }; }[]; }; 900: { plugins: { resolve: CarouselPluginFunc; options: { 
numberOfSlides: number; }; }[]; }; }' is not assignable to type 'Pick<CarouselProps, 
"className" | "offset" | "onChange" | "draggable" | "value" | "plugins" | "itemWidth" | 
"slides" | "animationSpeed">'.
      Object literal may only specify known properties, and '640' does not exist in type 
'Pick<CarouselProps, "className" | "offset" | "onChange" | "draggable" | "value" | 
"plugins" | "itemWidth" | "slides" | "animationSpeed">'.  TS2769

    21 |         itemWidth={400}
    22 |         breakpoints={{
  > 23 |           640: {
       |           ^
    24 |             plugins: [
    25 |               {
    26 |                 resolve: slidesToShowPlugin,

this error stems from the typescript configuration. it did not properly get the type for 
react-carousel.as a result, the visual studio cannot recognize the syntax.
we have to import the module manually by creating a react-carousel.d.ts file and put the 
following line into the file. so that the typescript can proper understand it.

declare module "@brainhubeu/react-carousel";




Sunday, July 4, 2021

How to access the table from Postgres Admin pgAdmin?

 It is straight forward to access the SQL table in SQL Server from SQL management studio.

after we connect to the SQL DB, then we can expand the selected DB. the table is right under it

Database---->tables


however it is a little different to access the table for Postgres DB.

you need to go the Database ----> Schema --->Public ---->Tables