๋ฆฌํฌํธ API ๋ฒ ์คํธ ํ๋ํฐ์ค
ํญ์กฐ์ด ์คํผ์ ๋ฆฌํฌํธ API ์๋ํฌ์ธํธ, ์์ฒญ ๊ตฌ์กฐ ๋ฐ ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ์ดํดํ์ฌ ์ ํํ UA ๋ฐ์ดํฐ์ ํจ๊ณผ์ ์ผ๋ก ์ก์ธ์คํฉ๋๋ค.
์ฝ๋ ์๊ฐ 2๋ถ์ต๊ทผ ์
๋ฐ์ดํธ: 3๋ฌ ์
๋ฆฌํฌํธ API๋ ๊ด๊ณ ์ฃผ์ ํผ๋ธ๋ฆฌ์ ๊ฐ GraphQL ์ฟผ๋ฆฌ ์ธ์ด๋ฅผ ์ฌ์ฉํ์ฌ ํญ์กฐ์ด ํ๋ซํผ์ ๋ฆฌํฌํธ ๋ฐ์ดํฐ์ ์ ๊ทผํ๊ณ ์คํผ์ ์ฝํ ์ธ ๋ฅผ ๊ด๋ฆฌํ ์ ์๋๋ก ํฉ๋๋ค. GraphQL์ ๋ํ ์์ธํ ๋ด์ฉ์ GraphQL์ ๊ณต์ ์น์ฌ์ดํธ๋ฅผ ์ฐธ๊ณ ํ์ญ์์ค. API ํ์๊ธฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ฟผ๋ฆฌ ๋น๋๋ฅผ ์ง์ํ ์ ์์ต๋๋ค. ์ผ์ชฝ ์๋จ์ ์ฑ ์์ด์ฝ์ ํด๋ฆญํ์ฌ ๊ธฐ์ ์๋ฃ ํ์๊ธฐ๋ฅผ ํ์ฅํ๊ณ ์ฟผ๋ฆฌ์์ ์ฌ์ฉํ ์ ์๋ ํ๋ ๋ฐ ๋ฉํธ๋ฆญ์ ๋ํ ์ ๋ณด๋ฅผ ์ฐพ์ต๋๋ค.

API ์๋ํฌ์ธํธ
๋ฆฌํฌํธ API ๋จ์ผ ์๋ํฌ์ธํธ๊ฐ ์์ต๋๋ค.์๋ํฌ์ธํธ๋ ์ํ๋๋ ์์ ๊ณผ ๊ด๊ณ์์ด ๋์ผํ๊ฒ ์ ์ง๋ฉ๋๋ค.https://api.tapjoy.com/graphql
API์์ ํต์
์ก์ธ์ค ํ ํฐ์ด ์์ผ๋ฉด API์ ์์ฒญ์ ๋ณด๋ผ ์ ์์ต๋๋ค. API ์์ฒญ์ ๊ตฌ์ฑํ ๋๋ ์ฟผ๋ฆฌ๋ ๋ณํ์ ์คํํ๋์ง์ ๊ด๊ณ์์ด JSON์ผ๋ก ์ธ์ฝ๋ฉ๋ ๋ณธ๋ฌธ์ HTTP POST๋ฅผ ํตํด ์ ๊ณตํฉ๋๋ค. ์์ฒญ ์์:POST /graphqlHost: api.tapjoy.comAuthorization: Bearer <OAuth Token>{ "query": "query { user { firstName } }"}
์ค๋ฅ ์ฒ๋ฆฌ
API ์ฌ์ฉ ์ ๋ฐ์ํ ์ ์๋ ์ค๋ฅ๋ ๋ค์๊ณผ ๊ฐ์ ๋ฒ์ฃผ๋ก ๊ตฌ๋ถ๋ฉ๋๋ค.- ์๋ฒ/๋คํธ์ํฌ ์ค๋ฅ
- ์ธ์ฆ/๊ถํ ๋ถ์ฌ ์ค๋ฅ
- ์ฟผ๋ฆฌ ๊ตฌ๋ฌธ ์ค๋ฅ
- ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ ์ค๋ฅ
์๋์ ์ค๋ช
๋ ๊ฐ ๋ฒ์ฃผ๋ ์ปจํ
์คํธ๋ฅผ ์ํด ๋ค์ ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
query { user { firstName lastName }}
์๋ฒ/๋คํธ์ํฌ ์ค๋ฅ
API ์ฌ์ฉ ์ค ๋ณต๊ตฌ ๋ถ๊ฐ๋ฅํ ์๋ฒ/๋คํธ์ํฌ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ์ด ๊ฒฝ์ฐ ํด๋น ์๋๋ฆฌ์ค์ ๋ง๋ ์ ์ ํ HTTP ์ํ ์ฝ๋๊ฐ ๋ฐํ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด, API ๋ฌธ์ ๋ก ์ฟผ๋ฆฌ ์คํ์ด ๋ถ๊ฐ๋ฅํ ๊ฒฝ์ฐ 500 ์ํ ์ฝ๋๊ฐ ํฌํจ๋ HTTP ์๋ต์ ๋ฐ๊ฒ ๋ฉ๋๋ค. ์ด๋ฌํ ์ํฉ์ ์ฒ๋ฆฌํ๋ ์ต์ ์ ๋ฐฉ๋ฒ์ ์ง์์ ๋ฐฑ์คํ๋ฅผ ์ ์ฉํ ์ฌ์๋ ๋์์ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค.์ธ์ฆ/๊ถํ ๋ถ์ฌ ์ค๋ฅ
์ธ์ฆ/๊ถํ ๋ถ์ฌ ์ค๋ฅ ๋ค์๊ณผ ๊ฐ์ ๋ช ๊ฐ์ง ์ด์ ๋ก ๋ฐ์ํ ์ ์์ต๋๋ค.- OAuth ํ ํฐ์ด ๋ง๋ฃ๋จ
- OAuth ํ ํฐ์ด ์ ํจํ์ง ์์
- ๊ธฐ๋ณธ ์ธ์ฆ ์์คํ ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๊ณ ์์
{ "errors": [ { "message": "Authentication could not be verified. Please try again later.", "code": 403 } ]}
- - ์ฌ๋์ด ์ดํดํ ์ ์๋ ์ค๋ฅ์ ๋ํ ์ค๋ช
message - - HTTP ์ํ ์ฝ๋์ ๋์ํ๋ GraphQL ์ํ ์ฝ๋
code
์ฟผ๋ฆฌ ๊ตฌ๋ฌธ ์ค๋ฅ
๋ชจ๋ ์ฟผ๋ฆฌ์ ๋ณ๊ฒฝ ์ฌํญ์ ์ฌ์ ์ ๊ตฌ๋ฌธ์ ์ผ๋ก ์ฌ๋ฐ๋ฅธ์ง, ๊ทธ๋ฆฌ๊ณ ์ค๋ช ๋ ๋ฐ์ดํฐ ์คํค๋ง๋ฅผ ๋ฐ๋ฅด๋์ง ๊ฒ์ฆ๋ฉ๋๋ค. ์ ๊ณต๋ ์ฟผ๋ฆฌ๊ฐ ๋ชจ๋ ์คํค๋ง ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ํต๊ณผํ์ง ๋ชปํ๋ฉด, ๋ค์ ๋ฐ์ดํฐ๋ฅผ ํฌํจํ HTTP 200 OK ์๋ต์ ๋ฐ๊ฒ ๋ฉ๋๋ค.{ "errors": [ { "message": "Field 'user' doesn't exist on type 'Query'", "locations": [ { "line": 2, "column": 3 } ], "fields": [ "query", "user" ] } ]}
- - ์ฌ๋์ด ์ดํดํ ์ ์๋ ์ค๋ฅ์ ๋ํ ์ค๋ช
message - - ๊ตฌ๋ฌธ ์ค๋ฅ์ ์์น
locations - - ๊ตฌ๋ฌธ ์ค๋ฅ์ ์ํฅ์ ๋ฐ๋ ํ๋
fields
๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ ์ค๋ฅ
ํ์ ํ๋๋ฅผ ๋ชจ๋ ํฌํจํ์ฌ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌ์ฑ๋ ๋ณํ์ ์ ๊ณตํ๋๋ผ๋ ๋น์ฆ๋์ค ์ ํจ์ฑ ๊ฒ์ฌ ๋๋ฌธ์ ์คํจํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๊ด๊ณ ์ฃผ๊ฐ ๋ค์๊ณผ ๊ฐ์ด ๊ด๊ณ ์ธํธ์ ์ ์ฐฐ๊ฐ๋ฅผ ์ต์ ๊ธ์ก ๋ฏธ๋ง์ผ๋ก ๋ณ๊ฒฝํ๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค.ํด๋น ์๋๋ฆฌ์ค์์๋ ๋ค์๊ณผ ๊ฐ์ ๋ฐ์ดํฐ๊ฐ ํฌํจ๋ HTTP 200 OK ์๋ต์ ์์ ํ๊ฒ ๋ฉ๋๋ค.mutation { updateAdSet(input: { id: "00000000-0000-0000-0000-000000000000", bidding: {amount: 10000} }) { adSet { id } }}
{ "data": { "updateAdSet": null }, "errors": [ { "message": "Amount is below the minimum (20000 micros)", "locations": [ { "line": 2, "column": 3 } ], "path": [ "updateAdSet", "input", "bidding", "amount" ], "code": 422 } ]}
- - ์ฌ๋์ด ์ดํดํ ์ ์๋ ์ค๋ฅ์ ๋ํ ์ค๋ช
message - - ์ ํจ์ฑ ๊ฒ์ฌ ์ค๋ฅ์ ์์น
locations - - ์๋ชป๋ ๊ฒ์ผ๋ก ํ๋จ๋ ํ๋์ ๋ํ ์์ ํ ์ฐธ์กฐ
path - - HTTP ์ํ ์ฝ๋์ ๋์ํ๋ GraphQL ์ํ ์ฝ๋
code
์ ํ
๋ฆฌํฌํธ API์๋ ๊ณผ๋ํ๊ฑฐ๋ ์ ์์ ์ธ API ํธ์ถ์ ๋ฐฉ์งํ๊ธฐ ์ํ ํน์ ๋ณดํธ ์ฅ์น๊ฐ ๋ง๋ จ๋์ด ์์ต๋๋ค. ์ฐ๋์ด ์ค์ ๋ ํ๋๋ฅผ ์ด๊ณผํ๋ ๊ฒฝ์ฐ, ํญ์กฐ์ด ์ธ์ผ์ฆ ๋ด๋น์(AM) ๋๋ ์ง์ ํ์ ๋ฌธ์ํ์ฌ ์ฐ๋ ์ต์ ํ ๋ฐฉ๋ฒ์ด๋ ํ๋ ์ฆ์ก ๋ฐฉ๋ฒ์ ํ์ธํ์ญ์์ค. ์๋ ์์๋ ๊ด๊ณ ์ฃผ ํ๊ฒฝ์ ๊ธฐ์ค์ผ๋ก ์ค๋ช ๋์์ผ๋, ํผ๋ธ๋ฆฌ์ ์ฐ๋์๋ ๋์ผํ๊ฒ ์ ์ฉ๋ฉ๋๋ค.๋ฐ์ดํฐ ๋ณด๊ด
๋ฆฌํฌํธ API ์ง๋ 2๋ ๊ฐ์ ๋ฐ์ดํฐ์ ์ก์ธ์คํ ์ ์์ต๋๋ค.ํ์ด์ง ๋งค๊น
ํ์ด์ง ๋งค๊น๋ ์ ํ์ ์ฟผ๋ฆฌํ ๋ ํด๋ผ์ด์ธํธ๋ ๋ค์์ ์ค์ํด์ผ ํฉ๋๋ค.- ๋๋
first์ธ์ ์ ๊ณตlast - ๋จ์ผ ํ์ด์ง์ 100๊ฐ ๋ ธ๋๋ฅผ ์ด๊ณผํ์ง ์์
์ ์ฟผ๋ฆฌ์์๋ ์ต๋ 50๊ฐ์ ๊ด๊ณ ์ธํธ๊ฐ ๋ฐํ๋๋ฉฐ, ๊ฐ ๊ด๊ณ ์ธํธ์๋ ์ต๋ 50๊ฐ์ ๊ด๊ณ ๊ฐ ํฌํจ๋ฉ๋๋ค. ์ปฌ๋ ์ ์ ํ์ด์ง ๋จ์๋ก ๋๋๋ ค๋ฉด ํ์ด์ง ์์ ์์น๋ฅผ ์ ์ดํ๊ธฐ ์ํด{ advertiser { adSets(first: 50) { edges { node { id name ads(first: 50) { edges { node { id name } } } } } } }}
afterbefore์ ์ฟผ๋ฆฌ์์๋ ์ปค์ ์์น 'Mg=='๋ถํฐ ์ต๋ 50๊ฐ์ ๊ด๊ณ ์ธํธ๋ฅผ ๋ฐํํฉ๋๋ค. ํด๋น ํฌ์ง์ ์ ์ด์ ์ฟผ๋ฆฌ์์ ๋ฐํ๋ endCursor๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ฒฐ์ ๋ฉ๋๋ค. hasNextPage๊ฐ false์ผ ๋ ํ์ด์ง์ด ์๋ฃ๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผํด์ผ ํฉ๋๋ค. ํ์ด์ง ๋งค๊น์ ๋ํ ์์ธํ ๋ด์ฉ์ GraphQL ๋ฌธ์์์ ํ์ธํ ์ ์์ต๋๋ค.{ advertiser { adSets(first: 50, after: "Mg==") { edges { node { id name } } pageInfo { endCursor hasNextPage } } }}
ํธ์ถ ๋ณต์ก๋
์คํค๋ง ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ํต๊ณผํ๋ ค๋ฉด ๋ชจ๋ ๋ง์ผํ API ํธ์ถ์ 10,000ํ ์ด์์ 'ํธ์ถ'์ ์ด๊ณผํด์๋ ์ ๋ฉ๋๋ค. ์ฌ๊ธฐ์ 'ํธ์ถ'์ ๋ฆฌ์์ค์ ๋ํ ์์ฒญ์ ์๋ฏธํฉ๋๋ค. GraphQL์ ์ฌ๋ฌ ํธ์ถ์ ๋จ์ผ ์ฟผ๋ฆฌ๋ก ๊ฒฐํฉํ ์ ์์ผ๋ฏ๋ก, ๋จ์ผ ์ฟผ๋ฆฌ์ ๋ํ ์ด ํธ์ถ ์๋ ์ฟผ๋ฆฌ ์คํ ์ ์ API์์ ๋ฏธ๋ฆฌ ๊ณ์ฐ๋ฉ๋๋ค. ํธ์ถ ํ์๋ ๊ฒฐ๊ณผ์์ ์ ํ๋๋ ๋ฆฌ์์ค ์(์: ์บ ํ์ธ, ๊ด๊ณ ์ธํธ, ๊ด๊ณ , ์ฑ, ์ธ์ฌ์ดํธ ๋ฑ)์ ๋๋ต์ ์ผ๋ก ์ผ์นํฉ๋๋ค. ์์ ๋์ผํ ์์๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.์ด ์์์์ ํด๋ผ์ด์ธํธ๋ ํ ๋ฒ์ ์ต๋ 50๊ฐ์ ๊ด๊ณ ์ธํธ๋ฅผ ์์ฒญํ๊ณ ์์ผ๋ฉฐ, ๊ฐ ๊ด๊ณ ์ธํธ๋ณ๋ก ํด๋น ์ธํธ ๋ด ์ต๋ 50๊ฐ์ ๊ด๊ณ ๋ฅผ ์์ฒญํ๊ณ ์์ต๋๋ค. ์ด ํธ์ถ ํ์๋ฅผ ๊ณ์ฐํ๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ํฉ๋๋ค.{ advertiser { adSets(first: 50) { # <= 50 calls edges { node { id name ads(first: 50) { # <= 50 calls edges { node { id name } } } } } } }}
ํ์ฌ ์์ ์์๋ ์๊ฐ๋น ํธ์ถ ํ์์ ๋ํ ์ ํ์ด ์์ต๋๋ค. ๊ทธ๋ฌ๋ ํฅํ ๋ณ๊ฒฝ๋ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค.50 = 50 ad sets+50 x 50 = 2500 ads = 2550 calls
์ธ์ฌ์ดํธ ๋ณต์ก๋
์ด๋ค ๋ ๋ฒจ์์๋ ์ฟผ๋ฆฌ๋๋ ๋ฆฌํฌํธ ์ธ์ฌ์ดํธ๋ ์ ๊ธฐ๋ณธ ๊ณ์ฐ์ ๋ฐ์๋์ง ์์ ์ถ๊ฐ ๋ณต์ก๋ ๋น์ฉ์ ๋ฐ์์ํต๋๋ค. ์ฟผ๋ฆฌ๋๋ ๋ ์ง๋ง๋ค ๊ณ์ฐ์ 1ํ์ ํธ์ถ์ด ์ถ๊ฐ๋ฉ๋๋ค. ์์ ๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.์ด ์์์์ ํด๋ผ์ด์ธํธ๋ ํ ๋ฒ์ ์ต๋ 50๊ฐ์ ๊ด๊ณ ์ธํธ๋ฅผ ์์ฒญํ๊ณ ์์ต๋๋ค. ๊ฐ ๊ด๊ณ ์ธํธ์ ๋ํด 3๊ฐ์ง ์งํ์ 1๊ฐ์ ์ธ๊ทธ๋จผํธ์ ๊ฑธ์ณ 7์ผ์น ๋ฆฌํฌํ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๊ณ ์์ต๋๋ค. ์ด ํธ์ถ ํ์๋ฅผ ๊ณ์ฐํ๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ํฉ๋๋ค.{ advertiser { # 50 calls adSets(first: 50) { edges { node { id name # 7 calls insights(timeRange: {from: "2024-03-01T00:00:00Z", until: "2024-03-08T00:00:00Z"}) { timestamps reports { country impressions conversions spend } } } } } }}
50 = 50 ad sets+50 x 7 = 350 insights = 400 calls