딩코딩코딩 2023. 6. 29. 10:38

Day-65
### REST API
1. HTTP를 통해 SOAP(Simple Object Access Protol), Cookie 를 통한 세션 트레킹 같은 별도의 전송 계층 없이 전송을 하기 위한 간단한 인터페이스(not protocol)
2. Web Application -> service, REST -> Resource
3. Resource (CRUD : Create, Read, Update, Delete)
HTTP Method : GET, POST, PUT, PATCH, DELETE


### REST API 구성 요소
1. Resource : 자원에 정의. HTTP URI(Uniform Resource Identifier)
2. Verb : 행위. HTTP Method : GET, POST, PUT, PATCH, DELETE
3. Representation : 내용. HTTP Message Payload

### REST API 특징
1. Client / Server : low dependency
2. Stateless : 모든 요청에 상태 정보를 저장하지 않는다.(API => API key or Token)
3. 캐시 처리 기능 (scalability, 성능향상)
4. 계층화 (Load balancer / shared cache)
5. Code on demand (Server에서 실행가능한 코드를 
Client에게 전송, Client 확장성을 도모할 수 있음)
6. 자체 표현 구조(별도의 문서가 필요 없음)

### RESTful
1. 동사형보다 명사형
2. 단수형보다 복수형
3. URL의 depth는 Level 2 정도가 되도록(직관적/동작을 이해할 수 있도록) : /show/users
4. HTTP 응답코드
- 200 : Success

- 304: Not Error, Indirection 
- 400 : Bad-request
- 401 : 인증 실패
- 404 : Resource not found
- 500 : Internal Error

5. HTTP Resonse Body
- 에러처리에 대한 내용은 body에 표현
- 각 숫자마다 error code 범위를 미리 정의
- 회원관련 : 1000, 상품관련 : 2000
6. 부분 응답(patial response)
- 검색 HTTP GET에 query string 이용
- ex) users/user?usreno=1&name=“moon”
- HATEOS(HyperMedia as the Engine of application state) 특징을 이용하여 http link를 함께 리턴

### RESTful API
# cd /allnew/node
# cp -r member restful
# cd restful


## app.js
  1 const express = require('express');
  2 const morgan = require('morgan');
  3 const path = require('path');
  4 const bodyParser = require('body-parser');
  5 const cookieParser = require('cookie-parser');
  6
  7 const app = express();
  8
  9 app.set('port', process.env.PORT || 8000);
 10 app.use(morgan('dev'));
 11 app.use(bodyParser.json());
 12 app.use(bodyParser.urlencoded({ extended: false }));
 13 app.use(cookieParser());
 14 app.use(express.static(path.join(__dirname, 'public')));
 15
 16 var main = require('./routes/main.js');
 17 app.use('/', main);
 18
 19 app.listen(app.get('port'), () => {
 20     console.log('8000 Port : Server Started...')
 21 });

## public/index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>
        RESTful API Example
    </title>
</head>

<body>
    <h3>RESTful API Example</h3>
    <hr />
        <h4> GET APIs </h4>
    <hr />
    <form method="post" action="/api/users/userBody" target="targetURL" name="userForm">
        <p><input type="button" value="GET /Hello" onclick="document.targetURL.location.href='/Hello'"></p>
        <p><input type="button" value="GET /api/users" onclick="document.targetURL.location.href='/api/users'"></p>
        <p>ID : <input type="text" size="15" name="id" /></p>
        <input type="button" value="GET /api/users/user?params" 
        onclick="document.targetURL.location.href='/api/users/user?user_id='+document.userForm.id.value">&nbsp;
        <input type="button" value="GET /api/users/path" 
        onclick="document.targetURL.location.href='/api/users/'+document.userForm.id.value">&nbsp;
        <p>Name : <input type="text" size="15" name="name" /></p>
        <input type="button" value="GET /api/users/user?userid & name" 
        onclick="document.targetURL.location.href='/api/users/user?user_id='+document.userFor m.id.value+'&name='+document.userForm.name.value "/><br />
    <hr />
        <h4> POST APIs </h4>
    <hr />
        <button type="submit" name='userBody' formaction="/api/users/userBody">POST => /api/users/userBody</button>
        &nbsp;&nbsp;
        <button type="submit" name='add' formaction="/api/users/add">POST => /api/users/add</button>
        &nbsp;&nbsp;
    </form>
    <hr />
    <iframe name="targetURL" width="100%" height="70%" style="border : none" src="/api/users"></iframe>
</body>
</html>


## routes/main.js
const express = require('express');
const bodyParser = require('body-parser');

const app = express()

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

const users = [
        {id:1, name:"User1"},
        {id:2, name:"User2"},
        {id:3, name:"User3"}
]

app.get('/hello', (req, res) => {
    res.send("Hello World~!!");
})

// request X , response O
app.get("/api/users", (req, res) => {
    res.json({ok:true, users:users});
})

// Query param, request O, response O
app.get("/api/users/user", (req, res) => {
    let user = "";
    const { user_id, name } = req.query
    if (req.query.name == null) {
        user = users.filter(data => data.id == user_id)
    } else {
        user = users.filter(data => data.id == user_id && data.name == name)
    }
    res.json({ok:false, users:user});
})

// Path param, request O, response O
app.get("/api/users/:user_id", (req, res) => {
    const user_id = req.params.user_id
    const user = users.filter(data => data.id == user_id)
    res.json({ok:false, users:user});
})

// post, request body O, response O
app.post("/api/users/userBody", (req, res) => {
    const user_id = req.body.id
    const user = users.filter(data => data.id == user_id)
    res.json({ok:false, users:user});
})

// post, request body O, response O
app.post("/api/users/add", (req, res) => {
    const { id, name } = req.body
    const user = users.concat({ id, name})
    res.json({ok:true, users:user});
})

// put, request body O, response O
app.put("/api/users/update", (req, res) => {
    const { id, name } = req.body
    const user = users.map(data => {
        if (data.id == id) data.name = name
        return {
            id : data.id,
            name : data.name
        }
    })
    res.json({ok:true, users:user});
})

// patch, request params & body O, response O
app.patch("/api/users/update/:user_id", (req, res) => {
    const { user_id } = req.params
    const { name } = req.body
    const user = users.map(data => {
        if (data.id == user_id) data.name = name
        return {
            id : data.id,
            name : data.name
        }
    })
    res.json({ok:true, users:user});
})

// delete, request body O, response O
app.delete("/api/users/delete", (req, res) => {
    const { user_id } = req.body
    const user = users.filter(data => data.id != user_id)
    res.json({ok:false, users:user});
})

module.exports = app;


# npm init -y

# npm install express morgan path body-parser cookie-parser

# npm install -g nodemon

# nodemon app.js


## node.js 한글깨짐문제해결 방법
response.writeHead(200, {'Content-Type':'text/plain; charset=utf-8'});

## restful -> lightsail에 업로드
# cd ..

# tar cvzf restful.tar.gz ./restful

# scp restful.tar.gz bit:/root

# ssh bit

# cd /node

# mv ~/restful.tar.gz .

# tar xvzf restful.tar.gz

# cd worldcup

# pm2 status

# pm2 stop app

# cd ../restful

# pm2 start app.js

http://13.209.183.10:8000/

### RESTful API - remote
# cd /allnew/node

# cp -r restful remoteapi

## public/index.html
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>
        RESTful API Example
    </title>
</head>

<body>
    <h3>RESTful API Example</h3>
    <hr />
        <h4> GET APIs </h4>
    <hr />
    <form method="post" action="/api/users/userBody" target="targetURL" name="userForm">
        <p><input type="button" value="GET /Hello" onclick="document.targetURL.location.href='/Hello'"></p>
        <p><input type="button" value="GET /api/users" onclick="document.targetURL.location.href='/api/users'"></p>
        <p>ID : <input type="text" size="15" name="id" /></p>
        <input type="button" value="GET /api/users/user?params" 
        onclick="document.targetURL.location.href='/api/users/user?user_id='+document.userForm.id.value">&nbsp;
        <input type="button" value="GET /api/users/path" 
        onclick="document.targetURL.location.href='/api/users/'+document.userForm.id.value">&nbsp;
        <p>Name : <input type="text" size="15" name="name" /></p>
        <input type="button" value="GET /api/users/user?userid & name" 
        onclick="document.targetURL.location.href='/api/users/user?user_id='+document.userFor m.id.value+'&name='+ 
        document.userForm.name.value"/><br />
    <hr />
        <h4> POST APIs </h4>
    <hr />
        <button type="submit" name='userBody' formaction="/api/users/userBody">POST => /api/users/userBody</button>
        &nbsp;&nbsp;
        <button type="submit" name='add' formaction="/api/users/add">POST => /api/users/add</button>
        &nbsp;&nbsp;
    </form>
    <hr />
    <iframe name="targetURL" width="100%" height="70%" style="border : none" src="http://13.209.183.10:8000/api/users"></iframe>
</body>
</html>

## routes/main.js
const express = require('express');
const bodyParser = require('body-parser');
const axios = require('axios');
const CircularJSON = require('circular-json');
const request = require('request');

const app = express()

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

let urls = "";

app.get('/hello', (req, res) => {
    urls = "http://13.209.183.10:8000/hello";
    request(urls, {json:true}, (err, result, body) => {
        if (err) { return console.log(err); }
        res.send(CircularJSON.stringify(body))
    })
});

// request X , response O
app.get("/api/users", (req, res) => {
    axios
        .get('http://13.209.183.10:8000/api/users')
        .then(result => {
            res.send(CircularJSON.stringify(result.data))
        })
        .catch(error => {
            console.error(error)
        })
})

// Query param, request O, response O
app.get("/api/users/user", (req, res) => {
    if (req.query.name == null) {
        urls = "http://13.209.183.10:8000/api/users/user?user_id="+req.query.user_id;
    } else {
        urls = "http://13.209.183.10:8000/api/users/user?user_id="+req.query.user_id+"&name="+req.query.name;
    }
    request(urls, {json:true}, (err, result, body) => {
        if (err) { return console.log(err); }
        res.send(CircularJSON.stringify(body))
    })
})

// Path param, request O, response O
app.get("/api/users/:user_id", (req, res) => {
    urls = "http://13.209.183.10:8000/api/users/"+req.params.user_id;
    request(urls, {json:true}, (err, result, body) => {
        if (err) { return console.log(err); }
        res.send(CircularJSON.stringify(body))
    })
})


// post, request body O, response O
app.post("/api/users/userBody", (req, res) => {
    const option = {
        uri : 'http://13.209.183.10:8000/api/users/userBody',
        method : 'POST',
        form : { id : req.body.id }
    }
    request.post(option, (err, result, body) => {
        if (err) { return console.log(err); }
        res.send(CircularJSON.stringify(body))
    })
})

// post, request body O, response O
app.post("/api/users/add", (req, res) => {
    const option = {
        uri : 'http://13.209.183.10:8000/api/users/add',
        method : 'POST',
        form : { 
            id : req.body.id,
            name : req.body.name
        }
    }
    request.post(option, (err, result, body) => {
        if (err) { return console.log(err); }
        res.send(CircularJSON.stringify(body))
    })
})

// put, request body O, response O
app.put("/api/users/update", (req, res) => {
    const option = {
        uri : 'http://13.209.183.10:8000/api/users/update',
        method : 'PUT',
        form : { 
            id : req.body.id,
            name : req.body.name
        }
    }
    request.put(option, (err, result, body) => {
        if (err) { return console.log(err); }
        res.send(CircularJSON.stringify(body))
    })
})

// patch, request params & body O, response O
app.patch("/api/users/update/:user_id", (req, res) => {
    const option = {
        uri : 'http://13.209.183.10:8000/api/users/update/'+req.params.user_id,
        method : 'PATCH',
        form : { 
            name : req.body.name
        }
    }
    request.patch(option, (err, result, body) => {
        if (err) { return console.log(err); }
        res.send(CircularJSON.stringify(body))
    })
})

// delete, request body O, response O
app.delete("/api/users/delete", (req, res) => {
    const option = {
        uri : 'http://13.209.183.10:8000/api/users/delete/',
        method : 'DELETE',
        form : { 
            user_id : req.body.user_id
        }
    }
    request.delete(option, (err, result, body) => {
        if (err) { return console.log(err); }
        res.send(CircularJSON.stringify(body))
    })
})

module.exports = app;

# npm install axios request circular-json

# nodemon app.js


## bit 에서..

[root@bit /node/restful]# pm2 start app.js

### awsu…
# cd /allnew/node/remoteapi

# rm -rf node_modules/

# cd ..

# tar cvzf remoteapi.tar.gz ./remoteapi

# scp remoteapi.tar.gz master:/allnew/docker

# rm -rf remoteapi.tar.gz


### master…
# cd /allnew/docker

# mkdir k8s-remote

# mv remoteapi.tar.gz k8s-remote/

## Dockerfile
  1 # step 1 : Base Images
  2 FROM node:18.16.0
  3
  4 # step 2 : Package Install
  5 RUN apt -y update && apt -y upgrade && apt -y install git net-tools vim
  6
  7 # step 3 : Specify a working directory
  8 WORKDIR '/root'
  9
 10 # step 4 : Config file copy
 11 COPY remoteapi.tar.gz .
 12
 13 # step 5 : install express
 14 RUN tar xvzf remoteapi.tar.gz
 15 WORKDIR '/root/remoteapi'
 16 RUN npm install
 17 RUN npm install -g nodemon
 18
 19 # Step 6 : open port
 20 EXPOSE 8000
 21
 22 # Step 7 : Execution Program
 23 CMD ["nodemon", "app.js"]

## Makefile
  1 build:
  2         docker build -t remote .
  3 run:
  4         docker run -it -d -p 8000:8000 --name remote remote
  5 exec:
  6         docker exec -it remote /bin/bash
  7 logs:
  8         docker logs remote
  9 ps:
 10         docker ps -a
 11 img:
 12         docker images
 13 rm:
 14         docker rm -f $$(docker ps -aq)
 15 rmi:
 16         docker rmi $$(docker images -q)


# make build

# make img

# make run

# make ps

http://15.165.183.87:8000/



# docker commit remote remoteapi

# docker commit remote remoteapi

# docker tag remoteapi impelfin/remoteapi

# make img

# docker push impelfin/remoteapi

# make rm

# make img

# docker rmi impelfin/remoteapi

# make rmi

# make img


## deployment.yaml

     1 apiVersion: apps/v1
     2 kind: Deployment
     3 metadata:
     4   name: remoteapi
     5   labels:
     6     app: remoteapi
     7 spec:
     8   replicas: 3
     9   selector:
    10     matchLabels:
    11       app: remoteapi
    12   template:
    13     metadata:
    14       labels:
    15         app: remoteapi
    16     spec:
    17       containers:
    18       - name: remoteapi
    19         image: impelfin/remotepai
    20         ports:
    21         - containerPort: 8000   # Contianer Port(pod port)


## service.yaml
  1 apiVersion: v1
  2 kind: Service
  3 metadata:
  4   name: remoteapi
  5   labels:
  6     run: remoteapi
  7 spec:
  8   type: NodePort     # service type
  9   ports:
 10   - nodePort: 30800  # outter port
 11     port: 8080       # service port
 12     targetPort: 8000   # container port (pod port)
 13     protocol: TCP
 14   selector:
 15     app: remoteapi
 16   type: LoadBalancer
 17   externalIPs:
 18   - 15.165.183.87


# kubectl apply -f deployment.yaml

# kubectl apply -f service.yaml

# kubectl get deployment

# kubectl get svc -o wide

# kubectl get pod -o wide