---
title: 'Project documentation template'
disqus: hackmd
---
Usthing Web Backend Tutorial (Map)
===
[TOC]
## Functional >> imperative -> js dev
- functional: describe the function of this function
- imperative: describe how to perform this function
- https://stackoverflow.com/questions/17826380/what-is-difference-between-functional-and-imperative-programming-languages

## Functional programming helper libraries
reference :
https://github.com/stoeffel/awesome-fp-js
### Lodash
https://lodash.com/
map : iteration
```jsx=
import _ from "lodash"
function square(n) {
return n * n;
}
_.map([4, 8], square);
// => [16, 64]
_.map({ 'a': 4, 'b': 8 }, square);
// => [16, 64] (iteration order is not guaranteed)
var users = [
{ 'user': 'barney' },
{ 'user': 'fred' }
];
// The `_.property` iteratee shorthand.
_.map(users, 'user');
// => ['barney', 'fred']
```
flow : integrate multiple functions
```jsx=
function square(n) {
return n * n;
}
var addSquare = _.flow([_.add, square]);
addSquare(1, 2);
// => 9
```
groupBy :
```jsx=
_.groupBy([6.1, 4.2, 6.3], Math.floor);
// => { '4': [4.2], '6': [6.1, 6.3] }
// The `_.property` iteratee shorthand.
_.groupBy(['one', 'two', 'three'], 'length');
// => { '3': ['one', 'two'], '5': ['three'] }
```
### Basic Shell Operations
#### Windows(don't care)
#### Linux: dev / prod environment
https://www.digitalocean.com/community/tutorials/linux-commands

### Vim : Terminal Text Editor
learning:
https://danielmiessler.com/study/vim/
cheatsheet:
https://vim.rtorr.com/
### Git : Version Control
https://the-turing-way.netlify.app/reproducible-research/vcs/vcs-git-summary.html

### Docker: Virtual Environment
>Official Doc : https://docs.docker.com/get-started/03_updating_app/
>CheatSheet : https://dockerlabs.collabnix.com/docker/cheatsheet/

### Nginx : Web Server
```nginx=
user www www; ## Default: nobody
worker_processes 5; ## Default: 1
error_log logs/error.log;
pid logs/nginx.pid;
worker_rlimit_nofile 8192;
events {
worker_connections 4096; ## Default: 1024
}
http {
include conf/mime.types;
include /etc/nginx/proxy.conf;
include /etc/nginx/fastcgi.conf;
index index.html index.htm index.php;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] $status '
'"$request" $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log main;
sendfile on;
tcp_nopush on;
server_names_hash_bucket_size 128; # this seems to be required for some vhosts
server { # php/fastcgi
listen 80;
server_name domain1.com www.domain1.com;
access_log logs/domain1.access.log main;
root html;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:1025;
}
}
server { # simple reverse-proxy
listen 80;
server_name domain2.com www.domain2.com;
access_log logs/domain2.access.log main;
# serve static files
location ~ ^/(images|javascript|js|css|flash|media|static)/ {
root /var/www/virtual/big.server.com/htdocs;
expires 30d;
}
# pass requests for dynamic content to rails/turbogears/zope, et al
location / {
proxy_pass http://127.0.0.1:8080;
}
}
upstream big_server_com {
server 127.0.0.3:8000 weight=5;
server 127.0.0.3:8001 weight=5;
server 192.168.0.1:8000;
server 192.168.0.1:8001;
}
server { # simple load balancing
listen 80;
server_name big.server.com;
access_log logs/big.server.access.log main;
location / {
proxy_pass http://big_server_com;
}
}
}
```
### Hosting Providers
>e.g : Godaddy
https://www.quicksprout.com/best-web-hosting/
#### DNS(Domain Name System) Record

#### Types



### SSH: Remote Server Accessing
https://www.digitalocean.com/community/tutorials/ssh-essentials-working-with-ssh-servers-clients-and-keys#ssh-overview
Coding Patterns
---
### Early Return
#### Avoid
```jsx=
function handleClick (event) {
// Make sure clicked element has the .save-data class
if (event.target.matches('.save-data')) {
// Get the value of the [data-id] attribute
let id = event.target.getAttribute('data-id');
// Make sure there's an ID
if (id) {
// Get the user token from localStorage
let token = localStorage.getItem('token');
// Make sure there's a token
if (token) {
// Save the ID to localStorage
localStorage.setItem(`${token}_${id}`, true);
}
}
}
}
```
#### Prefer
```jsx=
function handleClick (event) {
// Make sure clicked element has the .save-data class
if (!event.target.matches('.save-data')) return;
// Get the value of the [data-id] attribute
let id = event.target.getAttribute('data-id');
if (!id) return;
// Get the user token from localStorage
let token = localStorage.getItem('token');
if (!token) return;
// Save the ID to localStorage
localStorage.setItem(`${token}_${id}`, true);
}
```
### Try / Catch Block
```jsx=
try {
tryStatements
} catch (exceptionVar) {
catchStatements
} finally {
finallyStatements
}
```
### OOP
Basic Node Server
---
```jsx
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World\n');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
```
> Simplest backend Node Server

> Backend JS Basic Skills
**HTTP Basics
---
checkout CORS / authentication / caching / cookies / redirects and Headers
https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP
**Rest
---
#### Methods
```gherkin=
GET /path
POST /path
PUT /path
DELETE /path
```
#### Status Code
https://restfulapi.net/http-status-codes/
>1xx: Informational – Communicates transfer protocol-level information.
2xx: Success – Indicates that the client’s request was accepted successfully.
3xx: Redirection – Indicates that the client must take some additional action in order to complete their request.
4xx: Client Error – This category of error status codes points the finger at clients.
5xx: Server Error – The server takes responsibility for these error status codes.
#### Headers
https://www.soapui.org/learn/api/understanding-rest-headers-and-parameters/
>Authorization: Carries credentials containing the authentication information of the client for the resource being requested.
>WWW-Authenticate: This is sent by the server if it needs a form of authentication before it can respond with the actual resource being requested. Often sent along with a response code of 401, which means ‘unauthorized’.
>Accept-Charset: This is a header which is set with the request and tells the server about which character sets are acceptable by the client.
>Content-Type: Indicates the media type (text/html or text/JSON) of the response sent to the client by the server, this will help the client in processing the response body correctly.
>Cache-Control: This is the cache policy defined by the server for this response, a cached response can be stored by the client and re-used till the time defined by the Cache-Control header.
#### Practices
https://stackoverflow.com/questions/4024271/rest-api-best-practices-where-to-put-parameters
**NestJS
---
#### Decorators
```jsx=
@Get(/path)
@Post(/path)
@Patch(/path)
@Delete(/path)
```
```gherkin=
@Post()
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
@Get()
findAll() {
return this.usersService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.usersService.findOne(+id);
}
@Patch(':id')
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.usersService.update(+id, updateUserDto);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.usersService.remove(+id);
}
```
> Read more about NestJS here: https://docs.nestjs.com/
**Mongoose (ODM) for Mongo Database
---
>Official Doc :https://mongoosejs.com/docs/guide.html
#### Basic Usage
```jsx
//Define schema
import { Model, Schema, HydratedDocument, model } from 'mongoose';
interface IUser {
firstName: string;
lastName: string;
}
interface IUserMethods {
fullName(): string;
}
interface UserModel extends Model<IUser, {}, IUserMethods> {
createWithFullName(name: string): Promise<HydratedDocument<IUser, IUserMethods>>;
}
const schema = new Schema<IUser, UserModel, IUserMethods>({
firstName: { type: String, required: true },
lastName: { type: String, required: true }
});
// invoked directly by a Model
schema.static('createWithFullName', function createWithFullName(name: string) {
const [firstName, lastName] = name.split(' ');
return this.create({ firstName, lastName });
});
//invoked by an instance of a Mongoose document
schema.method('fullName', function fullName(): string {
return this.firstName + ' ' + this.lastName;
});
const User = model<IUser, UserModel>('User', schema);
User.createWithFullName('Jean-Luc Picard').then(doc => {
console.log(doc.firstName); // 'Jean-Luc'
doc.fullName(); // 'Jean-Luc Picard'
});
```
#### Available Schema Types
```jsx=
const schema = new Schema({
name: String,
binary: Buffer,
living: Boolean,
updated: { type: Date, default: Date.now },
age: { type: Number, min: 18, max: 65 },
mixed: Schema.Types.Mixed,
_someId: Schema.Types.ObjectId,
decimal: Schema.Types.Decimal128,
array: [],
ofString: [String],
ofNumber: [Number],
ofDates: [Date],
ofBuffer: [Buffer],
ofBoolean: [Boolean],
ofMixed: [Schema.Types.Mixed],
ofObjectId: [Schema.Types.ObjectId],
ofArrays: [[]],
ofArrayOfNumbers: [[Number]],
nested: {
stuff: { type: String, lowercase: true, trim: true }
},
map: Map,
mapOfString: {
type: Map,
of: String
}
});
```
#### Schema Type Options

#### Queries

ODM VS ORM (Object Relational Mapping)
https://tangledguy.hashnode.dev/odm-vs-orm
JWT(Json Web Tokens)
---
https://jwt.io/introduction
>Authorization
>Secure Information Exchange
Express (lightweight Node FrameWork)
---
>Official DOC : https://expressjs.com/en/guide/routing.html
>Examples : https://expressjs.com/en/starter/examples.html
#### MiddleWare
```jsx=
const express = require('express')
const cookieParser = require('cookie-parser')
const cookieValidator = require('./cookieValidator')
const app = express()
async function validateCookies (req, res, next) {
await cookieValidator(req.cookies)
next()
}
app.use(cookieParser())
app.use(validateCookies)
// error handler
app.use((err, req, res, next) => {
res.status(400).send(err.message)
})
app.listen(3000)
```
#### Routing
```jsx
const express = require('express')
const app = express()
//*foo* is the custom input
app.*METHOD*('*PATH*', (req, res) => {
*function body*
})
// respond with "hello world" when a GET request is made to the homepage
app.get('/', (req, res) => {
res.send('hello world')
})
app.get('/users/:userId/books/:bookId', (req, res) => {
res.send(req.params)
})
```
>Route path: /users/:userId/books/:bookId
Request URL: http://localhost:3000/users/34/books/8989
req.params: { "userId": "34", "bookId": "8989" }
#### Response Methods

Jest
---
>Official Doc : https://jestjs.io/docs/getting-started
>Functional Testing : https://katalon.com/resources-center/blog/functional-testing
#### Test With Mongo
```jsx=
const {MongoClient} = require('mongodb');
describe('insert', () => {
let connection;
let db;
beforeAll(async () => {
connection = await MongoClient.connect(globalThis.__MONGO_URI__, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
db = await connection.db(globalThis.__MONGO_DB_NAME__);
});
afterAll(async () => {
await connection.close();
});
it('should insert a doc into collection', async () => {
const users = db.collection('users');
const mockUser = {_id: 'some-user-id', name: 'John'};
await users.insertOne(mockUser);
const insertedUser = await users.findOne({_id: 'some-user-id'});
expect(insertedUser).toEqual(mockUser);
});
});
```
#### Snapshot Testing
> make sure your UI does not change unexpectedly
```jsx=
import renderer from 'react-test-renderer';
import Link from '../Link';
it('renders correctly', () => {
const tree = renderer
.create(<Link page="http://www.facebook.com">Facebook</Link>)
.toJSON();
expect(tree).toMatchSnapshot();
});
```
https://jestjs.io/docs/snapshot-testing
#### Test With React
Component (Link.js)
```jsx=
import {useState} from 'react';
const STATUS = {
HOVERED: 'hovered',
NORMAL: 'normal',
};
export default function Link({page, children}) {
const [status, setStatus] = useState(STATUS.NORMAL);
const onMouseEnter = () => {
setStatus(STATUS.HOVERED);
};
const onMouseLeave = () => {
setStatus(STATUS.NORMAL);
};
return (
<a
className={status}
href={page || '#'}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
{children}
</a>
);
}
```
Link.test.js
```jsx=
import renderer from 'react-test-renderer';
import Link from '../Link';
it('changes the class when hovered', () => {
const component = renderer.create(
<Link page="http://www.facebook.com">Facebook</Link>,
);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
// manually trigger the callback
renderer.act(() => {
tree.props.onMouseEnter();
});
// re-rendering
tree = component.toJSON();
expect(tree).toMatchSnapshot();
// manually trigger the callback
renderer.act(() => {
tree.props.onMouseLeave();
});
// re-rendering
tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
```
>https://jestjs.io/docs/tutorial-react
Caching
---
### Redis
>https://www.npmjs.com/package/redis
```jsx=
import { createClient } from 'redis';
const client = createClient({
url: 'redis://alice:foobared@awesome.redis.server:6380'
});
client.on('error', err => console.log('Redis Client Error', err));
await client.connect();
await client.set('key', 'value');
const value = await client.get('key');
await client.disconnect();
```
## Appendix and FAQ
:::info
**Find this document incomplete?** Leave a comment!
:::
General Concepts:
https://www.freecodecamp.org/news/have-an-idea-want-to-build-a-product-from-scratch-heres-a-checklist-of-things-you-should-go-through-in-your-backend-software-architecture/
Usthing Backend Reference**:
https://github.com/USThing/Backend-Refs
Usthing Backend Team Guidelines:
https://docs.google.com/document/d/1ZhLhc07_gENLfZUW-GHWbnHJP9HR__bhSM4NRI1cW5Y/edit#
Backend Team Docker Tutorial:
https://docs.google.com/document/d/1507FQISk8g86yrQFX85A_pFHjNqPoeRcyzatwmOYgXo/edit
Mongo Files(To be used) :
https://www.mongodb.com/docs/database-tools/mongofiles/#std-option-mongofiles.--local
Node Official:
https://nodejs.dev/en/learn/introduction-to-nodejs/
Usthing OAuth:
https://github.com/USThing/usthing-oauth-api
Apply Azure Developer (all itsc apis) ** :
https://docs.google.com/document/d/1JY7k1Dh7S7nDzyLQURkKCV4J4YWlFdm/edit
Backend Team Gdrive ** :
https://drive.google.com/drive/u/1/folders/1pu3lyfeXttbX12Xs05oR6ZZTs99UPzPN
Practices:
https://github.com/futurice/backend-best-practices
###### tags: `Usthing Web` `Backend T Documentation`