Skip to main content

Quick Start Guide

✨ The following step-by-step tutorial will guide you on how to create a new service repository implemented using Nodeblocks.

By the end of this tutorial you should have:

  • A local git repository with both the Auth and User Blocks packages installed, ready to be customized to fit your needs
  • A MongoDB installation with the data for both of these Blocks
  • Both the Auth and User services running locally, responding to requests made via Postman
caution

This guide does not cover deployment, and is focused solely on local development. For deployment guides (either manually or using Nodeblocks Cloud), see below.

Prerequisites

  • Local nodeblocks development can be performed on any OS, but is most ideal on a macOS or linux environment.
  • We recommend VSCode as an IDE.
DependencyVersion
node>=16
npm>=9
git>=2

Basal Nodeblocks NPM Token

Before you can get started, obtain a NPM token from Basal to grant you access to each of the nodeblocks. This token is prefixed with npm_, and will give you access to packages supplied by Basal including the Back-End SDK and each of the Nodeblocks Blocks.

Docker or MongoDB

MongoDB is the default database used for each of the Nodeblocks Blocks. It is required for initial service setup, and for running the Blocks locally. For local development, you have two options: Running your MongoDB database inside of a docker (or podman) container, or running your own installation on your host machine.

tip

Alternatively, you could connect to a pre-existing MongoDB deployed to the cloud.

Using Docker

  1. Install Docker or Podman
  2. Verify your installation works
Docker
docker run hello-world
Podman
podman machine init # For macOS/Windows users
podman machine start
podman run hello-world

Installing MongoDB

  1. Install MongoDB
  2. Verify you can connect to your running DB via mongosh

Creating your Repository

  1. Make a new git repository for your service and initialize with a blank repo
mkdir my-project
cd my-project
git init
npx gts init
git add . && git commit
tip

npx gts init creates a new typescript project following Google's linting and formatting guidelines. Feel free to modify any of the settings if different for your requirements.

  1. Open this repository in your IDE of choice
code .
  1. Create a .gitignore file with commonly ignored folders and files
*.log
.DS_Store
.docusaurus
.cache-loader
.env
node_modules
build
dist
scratch.js
coverage
.vscode/settings.json
  1. Create a .npmrc file with containing the Basal Nodeblocks NPM Token
engine-strict=true
@basaldev:registry=https://registry.npmjs.org
//registry.npmjs.org/:_authToken=${NODEBLOCKS_DEV_TOKEN}
caution

Either replace ${NODEBLOCKS_DEV_TOKEN} with your token, or add a new environment variable by adding export NODEBLOCKS_DEV_TOKEN=<token> to your .bashrc or .zshrc

  1. Create an .env file and add some default environment variables. Copy this to .env.default so that it can be committed for other contributors. Remember to change envs such as DATABASE_URL to match your situation.
PORT=8080
DATABASE_URL=mongodb://dev:dev@localhost:27017
USER_SERVICE_ENDPOINT=http://localhost:8081
AUTH_SERVICE_ENDPOINT=http://localhost:8080
AUTH_ENC_SECRET=<write a secret over 20 characters>
AUTH_SIGN_SECRET=<write a secret over 20 characters>
  1. Add dotenv and update your package.json to add commands for running your application
npm install --save dotenv
package.json
{
...
"scripts": {
...
"start": "node -r dotenv/config dist/index.js"
},
}
  1. Update tsconfig.json to specify settings for this repository
{
"extends": "./node_modules/gts/tsconfig-google.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist",
"esModuleInterop": true
},
"include": [
"src/**/*.ts",
"test/**/*.ts"
]
}

Configure MongoDB

If using MongoDB installed on your machine or the cloud, then there is nothing else to do here. If using MongoDB in Docker or Podman though, it may be useful to set up a standard set of containers for local development.

  1. Create a docker-compose.yml file
version: '3.1'
services:
mongo:
image: mongo
restart: always
environment:
MONGO_INITDB_ROOT_USERNAME: dev
MONGO_INITDB_ROOT_PASSWORD: dev
ports:
- 27017:27017
  1. Start up database by running docker-compose up or podman compose up
  2. It may be helpful to add some of the following other services if focusing on local development. Feel free to skip this step if using real world services instead
services:
# A fake google cloud storage server
# (Similar options exist for AWS buckets as well)
gcs:
image: fsouza/fake-gcs-server
volumes:
- ./test/data/gcs/data:/data
- ./test/data/gcs/storage:/storage
command: -scheme http -public-host ${URL:-localhost}:4443
ports:
- 4443:4443
# Web UI for modifying your local mongo database
mongo-express:
image: mongo-express
restart: always
ports:
- 8081:8081
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: dev
ME_CONFIG_MONGODB_ADMINPASSWORD: dev
ME_CONFIG_MONGODB_URL: mongodb://dev:dev@mongo:27017/
# Fake mail provider
sendgrid:
image: ghashange/sendgrid-mock:1.9.0
environment:
API_KEY: sendgrid-api-key
ports:
- 7000:3000

Installing the Auth Block package

  1. Install NPM Package
npm install --save @basaldev/blocks-auth-service
  1. Replace index.ts with the following implementation code
import {
createNodeblocksAuthApp,
defaultAdapter,
} from '@basaldev/blocks-auth-service';

function getEnvironmentVariable(name: string, defaultValue: string) {
const value = process.env[name] || defaultValue;
if (value === undefined) {
throw new Error(`Environment Variable ${name} is not set`);
}
return value;
}

const PORT = Number(getEnvironmentVariable('PORT', '8080'));
const DATABASE_URL = getEnvironmentVariable('DATABASE_URL', '');
const USER_SERVICE_ENDPOINT = getEnvironmentVariable(
'USER_SERVICE_ENDPOINT',
''
);
const AUTH_SERVICE_ENDPOINT = getEnvironmentVariable(
'AUTH_SERVICE_ENDPOINT',
''
);
const AUTH_ENC_SECRET = getEnvironmentVariable('AUTH_ENC_SECRET', '');
const AUTH_SIGN_SECRET = getEnvironmentVariable('AUTH_SIGN_SECRET', '');

void createNodeblocksAuthApp({
corsOrigin: [/.*/],
}).startService({
PORT: Number(PORT),
env: 'development',
domain: AUTH_SERVICE_ENDPOINT,
adapter: defaultAdapter.createAuthDefaultAdapter(
{
authEncSecret: AUTH_ENC_SECRET,
authSignSecret: AUTH_SIGN_SECRET,
enableRefreshToken: false,
tokenExpireTime: {
accessToken: '2h',
onetimeToken: '5m',
refreshToken: '1d',
},
},
DATABASE_URL,
USER_SERVICE_ENDPOINT
),
});
  1. Build and run the service
npm run compile
npm run start

If this works, you should see the following:

[2023-09-28T05:41:22.518Z]  INFO: NODEBLOCKS_AUTH_SERVICE/16920 on <your-pc>: Starting (adapter=nb-auth-default-adapter, port=8080)

This means it's working! You now have a Nodeblocks Block running locally.

Testing it works

We recommend using Postman for manually testing your endpoints. After setting up your Postman locally, add a new request to the following endpoint:

GET http://localhost:8080/ping

When you run this request, you should see a response like the following

{
"packageInfo": {
"gitCommitHash": "",
"sdkVersion": "1.3.0",
"serviceAdapterAPIVersion": "^1.1.0",
"serviceName": "@basaldev/blocks-auth-service",
"serviceVersion": "1.2.0"
},
"status": "ok"
}

This means that your Auth Block is running successfully and responding to requests. Now, let's try to login!

POST http://localhost:8080/login
{
"email": "email@example.com",
"password": "password1234",
"fingerprint": "<choose-a-fingerprint>"
}
info

A fingerprint is a value you specify that must be provided with every following request. This fingerprint guarantees that this device is the client that requested the access token.

You should get the following response:

{
"code": "INTERNAL_REQUEST_ERROR",
"details": [],
"message": "error requesting post http://localhost:8081/users/check_password"
}

What's happening here? This is occurring because the Auth block needs to contact the User block to check whether the provided password is as expected. We provided USER_SERVICE_ENDPOINT, but aren't actually running a User block at the moment, so let's do that.

tip

While the Auth block requires the User block in order to perform password checking by default, this is not a hard-coded requirement. By injecting your own dependency, this password checking can be performed in any method you require.

Adding the User Block

You can organize your services using either a repository per service, or a single overall monorepo with subfolders for each service. There are benefits to each approach.

Separate RepositoriesMonorepository
UpsidesWorks directly with Nodeblocks Cloud. Easy to organize. Deploy independently.Deploy all services together. Easier to keep in sync.
DownsidesEasy for services to get out of date with each otherNo Nodeblocks Cloud support. Harder to deploy an individual service.

For this tutorial, we will be using separate repositories.

  1. Create a new project using the auth project above (you may want to delete node modules first)
cd ..
cp -r my-project my-project-user
  1. Install the user package instead of auth
npm uninstall @basaldev/blocks-auth-service
npm install --save @basaldev/blocks-user-service
  1. Update .env/.env.default files
PORT=8081
DATABASE_URL=mongodb://dev:dev@localhost:27017
USER_SERVICE_ENDPOINT=http://localhost:8081
AUTH_SERVICE_ENDPOINT=http://localhost:8080
ORGANIZATION_SERVICE_ENDPOINT=http://localhost:8083
AUTH_ENC_SECRET=<write a secret over 20 characters>
AUTH_SIGN_SECRET=<write a secret over 20 characters>

# Bucket configuration
BUCKET_NAME=my_bucket
MAX_ATTACHMENT_SIZE_MB=10
ALLOWED_ATTACHMENT_CONTENT_TYPES=jpg,png,gif

# Email configuration
SEND_GRID_API_KEY=sendgrid-api-key
SENDER=noreply@mycompany.co.jp
VENDOR_EMAIL_URL=http://localhost:3000/email/verify
CUSTOMER_EMAIL_URL=http://localhost:3000/waiting-email-verify
VENDOR_RESET_PASSWORD_URL=http://localhost:3000/waiting_reset_password
CUSTOMER_RESET_PASSWORD_URL=http://localhost:3000/waiting_reset_password
ACCEPT_INVITATION_URL=http://localhost:3000/accept_invitation
  1. Update index.ts
import {
UserDefaultAdapterOptions,
createNodeblocksUserApp,
createUserDefaultAdapter,
} from '@basaldev/blocks-user-service';

function getEnvironmentVariable(name: string, defaultValue: string) {
const value = process.env[name] || defaultValue;
if (value === undefined) {
throw new Error(`Environment Variable ${name} is not set`);
}
return value;
}

const PORT = Number(getEnvironmentVariable('PORT', '8081'));
const DATABASE_URL = getEnvironmentVariable('DATABASE_URL', '');
const SEND_GRID_API_KEY = getEnvironmentVariable('SEND_GRID_API_KEY', '');
const AUTH_SERVICE_ENDPOINT = getEnvironmentVariable(
'AUTH_SERVICE_ENDPOINT',
''
);
const ORGANIZATION_SERVICE_ENDPOINT = getEnvironmentVariable(
'ORGANIZATION_SERVICE_ENDPOINT',
''
);
const AUTH_ENC_SECRET = getEnvironmentVariable('AUTH_ENC_SECRET', '');
const AUTH_SIGN_SECRET = getEnvironmentVariable('AUTH_SIGN_SECRET', '');

const BUCKET_NAME = getEnvironmentVariable('BUCKET_NAME', '');
const MAX_ATTACHMENT_SIZE_MB = getEnvironmentVariable(
'MAX_ATTACHMENT_SIZE_MB',
''
);

const SENDER = getEnvironmentVariable('SENDER', '');

async function main() {
const adapter: UserDefaultAdapterOptions = {
encSecret: AUTH_ENC_SECRET || '',
emailConfig: {
sender: SENDER,
inviteUser: {
enabled: false,
},
verifyEmail: {
enabled: false,
},
resetPassword: {
enabled: false,
},
},
signSecret: AUTH_SIGN_SECRET || '',
allowedAttachmentContentTypes: ['image/jpeg', 'image/png', 'image/gif'],
maxAttachmentSizeMB: Number(MAX_ATTACHMENT_SIZE_MB),
};

await createNodeblocksUserApp({
corsOrigin: [/.*/],
}).startService({
PORT,
env: 'development',
adapter: createUserDefaultAdapter(
adapter,
DATABASE_URL,
BUCKET_NAME,
AUTH_SERVICE_ENDPOINT,
ORGANIZATION_SERVICE_ENDPOINT,
{
authEncSecret: AUTH_ENC_SECRET || '',
authSignSecret: AUTH_SIGN_SECRET || '',
},
{
sendGridApiKey: SEND_GRID_API_KEY,
}
),
});
}

void main();
  1. Now build and run your service
npm run compile
npm run start
  1. Once you see the startup message in your terminal, create a new request in your Postman and try pinging the user service:
GET http://localhost:8081/ping

You should see a response like the following:

{
"packageInfo": {
"gitCommitHash": "",
"sdkVersion": "1.3.0",
"serviceAdapterAPIVersion": "^1.1.0",
"serviceName": "@basaldev/blocks-user-service",
"serviceVersion": "1.3.0"
},
"status": "ok"
}

Now when you run your login on the Auth service, you should see a new error:

{
"code": "login_error",
"details": [],
"message": "email or password is wrong"
}

Creating a User

Let's create a user so that we can login to them in the Auth service.

POST http://localhost:8081/users
{
"name": "my-user",
"email": "email@example.com",
"password": "password1234",
"typeId": "000"
}

Expected response:

{
"id": "...",
"email": "email@example.com",
"name": "my-user",
"typeId": "000",
"emailVerified": false,
...
}

Now try your login request. You should get the following:

{
"accessToken": "...",
"userId": "..."
}

Using your access token

Let's use your token to fetch your user info. Perform the following request, with the following headers:

GET http://localhost:8081/users/<your user id>

Authorization: Bearer <your access token>
x-nb-fingerprint: <same fingerprint used for login>

You should receive the same response as when you created this user.

Next steps

🎉 Congratulations! You've created two services using the Auth and User Blocks and made git repositories for each of them. From here, you have a number of different options on how to proceed: