[NodeJs] 벨로그 전체 게시글 조회수 통계 API 만들어봄

38330 단어 expressnodejsexpress

벨로그에서는 본인 게시물의 조회수 통계를 볼 수 있는데

타인의 통계는 당연히 안되겠지만

내 전체 게시물 통계가 궁금해서 가끔 확인할려고 앱을 하나

만들어봄

(나중에 날짜 별 포스트별 조회수로 정리좀 해야지)

https://github.com/isntkyu/velog-total


API IO 탐색 (PostMan 사용)

  • 개발자 도구를 켠다 (F12)

기본적으로 통계를 찾아가기 위한 모든 url은

Request URL: https://v2.velog.io/graphql

이거다 (method : POST)

그리고 request payload 를 달리해서 API 를 호출함

  • 그리고 중요한건 Request header에 쿠키가 꼭 필요함

이 토큰이 있는 쿠키 값을 그냥 복붙해서 쓰기로 하자
(싸그리 뒤져보았으나 저거를 내 로컬에서 생성할 힌트는 없었다.)
(참고로 이 토큰은 만료되지 않아서 계속 쓰면됨)


내 게시글 > 통계 를 받아올 때

Request Payload :

{        
 "operationName":"GetStats",
 "variables":{                       
   "post_id": 
 },
 "query":"query GetStats($post_id: ID!) {\n  getStats(post_id: $post_id) {\n    total\n    count_by_day {\n      count\n      day\n      __typename\n    }\n    __typename\n  }\n}\n"
}

RESPONSE :

{
  "data": {
    "getStats": {
      "total": 3,
      "count_by_day": [
        {
          "count": 1,
          "day": "2022-02-15T00:00:00.000Z",
          "__typename": "ReadCountByDay"
        },
        {
          "count": 2,
          "day": "2022-02-09T00:00:00.000Z",
          "__typename": "ReadCountByDay"
        }
      ],
      "__typename": "Stats"
    }
  }
}


직접적으로 통계를 얻는 호출이다.
postId 를 이용해서 total 조회수를 얻는거지 

그러면 ? 모든 포스트의 postId 값을 전부 모으면 되겠네

Request Payload :

{
    "operationName":"Posts",
    "variables":{
      "username":`isntkyu`,
      "tag":null
                    },
                    "query":"query Posts($cursor: ID, $username: String, $temp_only: Boolean, $tag: String, $limit: Int) {\n  posts(cursor: $cursor, username: $username, temp_only: $temp_only, tag: $tag, limit: $limit) {\n    id\n    title\n    short_description\n    thumbnail\n    user {\n      id\n      username\n      profile {\n        id\n        thumbnail\n        __typename\n      }\n      __typename\n    }\n    url_slug\n    released_at\n    updated_at\n    comments_count\n    tags\n    is_private\n    likes\n    __typename\n  }\n}\n"
                }

REPONSE BODY :

{
	"data":
    	"posts": []
}

post 배열을 JSON 파싱하면 모든 포스팅의 대한 정보가 온다
(postId를 포함)

포스팅 개수도 일치한다.


---

이젠 postId 배열을 

let postIds = posts.map(post => post.id)

추출해서 반복문으로 위의 통계를 누적시키면 해결~

여기서 비동기 async 라이브러리의
waterfall, whilest 를 사용해서 비동기 처리 비동기 반복문을 사용했다.

[비동기 반복문 사용법]


기본 로직

async.waterfall([
        function(callback) { //태그 다 가져오기
            got.post("https://v2.velog.io/graphql", {
                headers: {
                   cookie: accessToken
                },
                json: {
                    "operationName":"Posts",
                    "variables":{
                        "username":`${userName}`,
                        "tag":null
                    },
                    "query":"query Posts($cursor: ID, $username: String, $temp_only: Boolean, $tag: String, $limit: Int) {\n  posts(cursor: $cursor, username: $username, temp_only: $temp_only, tag: $tag, limit: $limit) {\n    id\n    title\n    short_description\n    thumbnail\n    user {\n      id\n      username\n      profile {\n        id\n        thumbnail\n        __typename\n      }\n      __typename\n    }\n    url_slug\n    released_at\n    updated_at\n    comments_count\n    tags\n    is_private\n    likes\n    __typename\n  }\n}\n"
                }
            }).then(response => {
                // console.log(JSON.parse(response.body).data.posts)
                let posts = JSON.parse(response.body).data.posts
                let postIds = posts.map(post => post.id)
                // console.log(postIds)
                callback(null, postIds);
            })
        },
        function(arg1, callback) { // 태그이름 담기
            let postsLength = arg1.length
            console.log("post s Length: ", postsLength)
    
            let count = 0;
            let total = 0;
            async.whilst(
                function test(cb) { cb(null, count < postsLength); },
                function iter(callback) {
                    got.post("https://v2.velog.io/graphql", {
                        headers: {
                            cookie: accessToken
                        },
                        json: {
                            "operationName":"GetStats",
                            "variables":{
                                "post_id":`${arg1[count]}`
                            },
                            "query":"query GetStats($post_id: ID!) {\n  getStats(post_id: $post_id) {\n    total\n    count_by_day {\n      count\n      day\n      __typename\n    }\n    __typename\n  }\n}\n"
                        }
                    }).then(response => {
                        count++;
                        let result = JSON.parse(response.body)
                        console.log(result)
                        let view = result.data.getStats.total
                        total += view
                        // console.log(to)
                        callback();
                    })
                },
                function (err, n) {
                    console.log("total:", total)
                    callback(null, total);
                }
            );
        },
    ], function (err, result) {
        console.log(result)
        res.send({result:result})
    });

일단 개인적으로 대충 가끔 확인하려고 html 폼을 만들었다.

나만 쓸거기 때문.

아이디랑 쿠키를 복붙해 넣으면 되는데 쿠키

이제 express와 body-parser등으로 app.js 에서
uri를 매핑 시켜봅시다.


app.js

const express = require('express')
const got = require('got')
const app = express()
const async = require('async')

app.use(express.static('public'))

app.listen(3000, function () {
    console.log('connected nodejs')
});

app.get('/', function (req, res) {
    res.sendFile(__dirname + "/public/index.html")
})

// 바디파서
var bodyParser = require('body-parser')
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))

app.post('/search_post', function (req, res) {  
    console.log('POST');
    console.log(req.body);
    let userName = req.body.userId;
    let accessToken = req.body.accessToken;
    async.waterfall([
        function(callback) { //태그 다 가져오기
            got.post("https://v2.velog.io/graphql", {
                headers: {
                   cookie: accessToken
                },
                json: {
                    "operationName":"Posts",
                    "variables":{
                        "username":`${userName}`,
                        "tag":null
                    },
                    "query":"query Posts($cursor: ID, $username: String, $temp_only: Boolean, $tag: String, $limit: Int) {\n  posts(cursor: $cursor, username: $username, temp_only: $temp_only, tag: $tag, limit: $limit) {\n    id\n    title\n    short_description\n    thumbnail\n    user {\n      id\n      username\n      profile {\n        id\n        thumbnail\n        __typename\n      }\n      __typename\n    }\n    url_slug\n    released_at\n    updated_at\n    comments_count\n    tags\n    is_private\n    likes\n    __typename\n  }\n}\n"
                }
            }).then(response => {
                // console.log(JSON.parse(response.body).data.posts)
                let posts = JSON.parse(response.body).data.posts
                let postIds = posts.map(post => post.id)
                // console.log(postIds)
                callback(null, postIds);
            })
        },
        function(arg1, callback) { // 태그이름 담기
            let postsLength = arg1.length
            console.log("post s Length: ", postsLength)
    
            let count = 0;
            let total = 0;
            async.whilst(
                function test(cb) { cb(null, count < postsLength); },
                function iter(callback) {
                    got.post("https://v2.velog.io/graphql", {
                        headers: {
                            cookie: accessToken
                        },
                        json: {
                            "operationName":"GetStats",
                            "variables":{
                                "post_id":`${arg1[count]}`
                            },
                            "query":"query GetStats($post_id: ID!) {\n  getStats(post_id: $post_id) {\n    total\n    count_by_day {\n      count\n      day\n      __typename\n    }\n    __typename\n  }\n}\n"
                        }
                    }).then(response => {
                        count++;
                        let result = JSON.parse(response.body)
                        console.log(result)
                        let view = result.data.getStats.total
                        total += view
                        // console.log(to)
                        callback();
                    })
                },
                function (err, n) {
                    console.log("total:", total)
                    callback(null, total);
                }
            );
        },
    ], function (err, result) {
        console.log(result)
        res.send({result:result})
    });
})

실행 결과

ㅎㅎ

좋은 웹페이지 즐겨찾기