프로젝트에서 다른 모듈과 연계시 오래 걸리는 작업의 결과를 받아 오기 위해 Kafka 를 사용 하고 있다. 이번에도 Rest API 를 이용하여 연계를 하기로 하였다.이런 경우에는 언제나 그렇듯이 연계 시스템들이 잘 개발 되었있을 것이란 믿음은 깨졌다.
이런 이유로 Mock서버를 구성 하였는데, 여느 경우와 달리 연계 모듈에서 오래 걸리는 작업의 결과는 Kafka 로 보내 주어야 한다는 경우로 인해 조금 머리가 아팠다.
- Rest API 로 연계
- Rest API + Kafka 로 연계
Rest API 로만 연계 하는 경우는 PRISM을 이용하여Rest Mocking Server 를 구성하면 되지만, 응답을 KAFKA 로 넘겨줘야 하는 경우 때문에 어떻게 해야 할지 고민을 하게 되었다.
NODE 에 익숙하진 않았지만, 빠르게 구성 하기 위해 NODE 기반의 http-proxy, express, kafka-node 를 이용하기로 결정하였고 아래와 같이 동작 하도록 Mock Server 를 구성하였다.( 전체 코드 : https://github.com/jjeaby/JRestMockServer )
- Rest API 로 연계 : 1→2→3→4
- Rest API + Kafka 로 연계 : 1→2→3→4→5→6
제일 먼저 PRISM 으로 Mock Server를 실행하는 코드를 작성한다.
PRISM 은 Swagger Spec Document 를 기반으로 Mock Server 를 구성해 주는 도구로 자세한 설명은 여기(= PRISM 으로 REST API Mock Server 구성) 를 참고 하길 바란다.
PRISM 을 실행하는 것은 node 의 spawn 을 이용하여 cli 로 구동 하도록 하였다. 여기서 조금 고민한 부부은 kafka 에서 오류가 발생한 경우 PRISM 이 함께 종료되지 않는 경우가 있어서 prismMockServer.on('close', (code) .... 에서 Exception 메세지를 남기로 process.exit 를 이용해 PRISM process 를 종료 한 것이다.
/*
* Prism 으로 기본 Mock 서버 구동 하기
* */
let prismMockServer = () => {
prismMockServer = spawn('prism', ['mock', '--host', '0.0.0.0', '-p', prismMockPort, '-d', prismMockSwaggerDoc]);
prismMockServer.stdout.on('data', (data) => {
data = data.toString().replace(/\r?\n|\r/g, " ");
console.log(`stdout: ${data}`);
});
prismMockServer.stderr.on('data', (data) => {
data = data.toString().replace(/\r?\n|\r/g, " ");
console.log(`stderr: ${data}`);
});
prismMockServer.on('close', (code) => {
throw {name: 'kafkaException', message: 'kafka 서버 연결 오류가 발생하였습니다.'}
process.exit(3);
});
return prismMockServer
}
이제 http-proxy 를 이용하여 25001 port 로 요청되는 모든 데이터를 15001 port 로 요청하고, 특정 Rest API 의 경우 kafka 로 Produce 하는 코드를 작성한다.
kafka 로 Topic 을 Produce 하는 경우를 구분하기 위해 kafkaSendRestApi 를 마들고 METHOD REST Api를 key 로 갖는 JSON 을 생성한다.
const kafkaSendRestApi = {
"GET /PETS?LIMIT=286": {
"code": "200",
"message": "success"
}
};
이제 http-proxy 를 이용하여 25001 port 로 연결되는 모든 정보를 15001 port 로 보내는 코드를 작성한다.
여기서 잘 봐야 할 부부은 proxyRes.on('end', function 에서 res.end() 를 이용하여 response 값을 변경 시킬수 있다는 것과 kafkaSendRestApi 에 추가한 METHOD REST Ap 조건인 경우 sendKafka 함수를 이용하여 Topic 을 Produce 해준다는 것이다.
/*
* MOCK Proxy Server 구성
* */
let mockProxyServer = (mockServerName, mockServerUrl, mockWithKafkaServerUrl) => {
let prismMockPort = parseInt(mockServerUrl.split(":")[2]);
let proxyMockPort = parseInt(mockWithKafkaServerUrl.split(":")[2]);
let option = {
target: mockServerUrl,
selfHandleResponse: true,
};
const proxyServer = createProxyServer({});
proxyServer.on('proxyReq', function (proxyReq, req, res) {
proxyReq.setHeader('Content-Type', 'application/json');
if (req.body) {
let bodyData = req.body;
proxyReq.setHeader('Content-Length', Buffer.byteLength(JSON.stringify(bodyData)));
proxyReq.write(JSON.stringify(bodyData));
}
});
proxyServer.on('proxyRes', function (proxyRes, req, res) {
let restApi = `${req.method} ${req.url}`;
let body = [];
res.setHeader('Content-Type', 'application/json');
proxyRes.on('data', function (chunk) {
body.push(chunk);
});
proxyRes.on('end', function () {
body = Buffer.concat(body).toString();
let bodyJson = JSON;
bodyJson.status = "success";
bodyJson.result = JSON.parse(body);
if (kafkaSendRestApi[restApi.toUpperCase().trim()]) {
sendKafka("topic", "messageKey", JSON.stringify(bodyJson));
res.end(JSON.stringify(successResponse));
} else {
res.end(JSON.stringify(bodyJson));
}
// }
});
});
const mockServer = express();
mockServer.use(bodyParser.json());
mockServer.use(bodyParser.urlencoded({extended: true}));
mockServer.use(function (req, res) {
proxyServer.web(req, res, option)
});
console.log('listening', '\x1b[31m', `${mockServerName}`, '\x1b[0m', '\x1b[36m', 'With Kafka on port,', '\x1b[31m', `${proxyMockPort}`, '\x1b[0m', ', only Mock on port', '\x1b[31m', `${prismMockPort}`, '\x1b[0m');
mockServer.listen(proxyMockPort);
}
이제 kafka-node 를 이용하여 kafka 로 topic 을 produce 해주는 sendKafka 코드를 작성한다.
/*
* KAFKA 관련 설정
**/
const sendKafka = (topicName, messageKey, message) => {
const client = new kafka.KafkaClient({kafkaHost});
const producer = new kafka.Producer(client);
const payloads = [
{topic: topicName, key: messageKey, messages: message},
];
producer.send(payloads, function (err, data) {
if (data === undefined) {
prismMockServer.kill('SIGHUP');
}
});
}
이렇게 코드를 모두 작성 하고 서버를 실행 시키면
- 아래와 REST Api Mock Server 가 구동되고
- kafkaSendRestApi 에 METHOD REST API 가 추가된 경우 Response 응답 Rest API + Kafka 로 연계 : 1→2→3→4→5→6
- kafkaSendRestApi 에 METHOD REST API 가 추가된 안된 경우 Response
Rest API 로 연계 : 1→2→3→4
전체 코드는 생각 보다 간단하게 작성 되었습니다. 개발시 급하게 사용하게 되어서 급하게 만들어 코드가 엉망이네요.(^^;; 사실 node 를 잘 몰라서)
REST API Mock Server 를 구성하여야 하는데 다른 서버를 거쳐야 한다는 조건이 있는 경우도 이 코드를 활용 할 수 있을 겁니다:) 그럼~~ 즐거운 개발 세발~~:)
'개발' 카테고리의 다른 글
Proxy 환경에서 NPM 환경 설정 : Proxy With NPM Config (0) | 2021.07.19 |
---|---|
Windows 에서 npm install 시 node-gyp rebuild 동작시 Error 발생으로 npm install 이 되지 않는 경우 해결 방법 (0) | 2021.07.18 |
Kafkacat 을 이용한 Kafka 동작 확인 방법 : kafkacat usage (0) | 2021.07.18 |
Spring Boot With Kafka Single Broker (0) | 2021.07.18 |
코드 작성 없이 PRISM 으로 REST API Mock Server 구성 하기 (0) | 2021.07.18 |