삭제한 Store의 API에 접근할 수 없는 이유

Today I Learned 날짜 2024년 2월 14일 수요일 내용 안돼 앱을 삭제한 shop의 메타필드와 테마 내 에셋을 삭제하는 Task를 진행중이다. 문제가 되는 부분을 정리하자면 app이 삭제되면 웹훅 시그널이 도착하는데, 이 때 shopify API로 메타필드나 에셋에 접근하면 access token으로 인해 401이 뜬다. 메타필드와 asset에 접근하는 다른 커맨드를 이용해 잘 작동되는게 확인된 access_token을 삭제해도 마찬가지로 aceess_token으로 인해 401이 뜬다. 열심히 구글링하는 과정에서 다음 링크를 발견했다. 요약하면, “app/uninstalled”라는 topic의 웹훅이 도착했을 떄는 이미 우리 app이 삭제된 이후기 떄문에 access token이 무효화되어 스토어의 에셋이나 메타필드에 접근할 수 없다는 것. 무려 Shopify 파트너의 답변이라… 그렇다면 알파리뷰를 삭제한 store의 스니펫을 위해 API로 전송한 데이터를 삭제할 수 있는 방법이 없다. 그리고 shopify 개발자 포럼을 확인해보니 이 문제를 나만 겪는게 아닌가보다. ...

2024년 2월 14일 · 2 분 · 배준수

rich snippet 위치 찾기

# Today I Learned ## 날짜 2024년 2월 13일 화요일 ## 내용 ### 왤까? 저번주부터 진행하던 Task는 고객이 서비스를 설치할 당시 생성된 데이터들 중 우리 서버에 있는 것과 Shopify에 저장해둔 것을 찾아 삭제해야 한다. 고객이 서비스를 삭제할 때 발생하는 일련의 과정은 웹훅으로 구현되어 있다. 내 로컬에서 태스크를 진행하기 위해 테스트 서버와 로컬에 웹훅을 설치해 열심히 구현했다. 저번 TIL에 있었던 metafields나 asset이 여기에 해당된다. 생성될 때의 함수를 보고 반대로 했다. 내가 지워야할 데이터는 구글에 rich snippet을 제공하기 위해 생성되었던 것들인데, 탐색해서 삭제하는 로직을 완성했다. 문제를 겪는 부분이 있고, 분명 발생해야 할 문제인데 그렇지 않은 부분도 있다. 우선, 설치를 삭제한 shop의 테마를 shopify에서 조회하는데 자꾸 실패한다. 이미 작성된 다른 커맨드를 이용해 테마를 조회할 떄는 잘 나오는데 왜 여기서만 문제가 될까? 같은 함수를 사용하는데.. 삭제해야할 테마가 존재하지 않는다면 그냥 넘어가도록 로직을 설정할지, 무언가 잘못된 부분이 있는지 아직 확신이 서지 않는다. 왜 안될까? 두번쨰로, 테마의 asset을 다루는 API는 Shopify에 예외적인 상황임을 알려 승인받지 않는다면 더 이상 지원하지 않는다. 우리 서비스는 승인을 받았지만, 실서버만 적용되기 때문에 테스트서버에선 asset API가 작동되지 않을 것이라고 조언을 받았었다. 이 과정을 어떻게 처리해야할지 참 고민이 많았는데 아직까지 나타나지 않고 있다. 왜 될까? ## 회고 긴 연휴 끝이라 집중을 잘 못할까 걱정했는데 기우였다. 휴식이 최고.

2024년 2월 13일 · 1 분 · 배준수

공정하다는 착각

공정하다는 착각 지은이: 마이클 샌델 지음 출판사: 와이즈베리 감상 능력주의는 진급, 승진, 포상 등 집단 내에서 이익을 분배할 때 개인의 능력을 기준으로 삼는 것을 의미한다. 지극히 당연하고 합리적인 방식인 것처럼 보이며 실제로 능력주의의 가치를 달성하기 위해 사회적으로 많은 노력이 소모되고 있다. 그런 면에 익숙해져있다보니, 능력주의를 정답이라고 생각했었다. 어느정도 모범답안이 될 순 있겠다. 학연, 지연, 혈연으로 밀고 당겨주는 불합리함보다는 훨씬 나은 것은 분명하다. 나름대로, 능력주의에 있는 결함에 대해 생각을 하곤 했었다. 예컨대, 모든 수험생이 한날 한시에 같은 시험을 보는 수능은 능력주의를 가장 잘 보여주는 제도다. 국가적으로 철저히 보안을 신경쓰고, 철저히 원칙을 적용한다. 재벌가의 자녀들조차 재수를 하는걸 보면 납득이 되리라고 생각한다. 그날의 컨디션, 건강이나 사고 등 예측할 수 없는 변수는 존재하겠지만, 천재지변까지 통제할 수는 없다는 건 누구나 인정하는 사실이다. 수능은 완벽히 공정한가? 백만원이 넘는 과외를 받는 학생과 가정 형편이 어려워 아르바이트를 해야하는 학생이 공정한 절차를 치뤘다고 볼 수 있는가? 아픈 가족을 돌보는데 매일 시간을 써야하는 학생의 불리함도 천재지변으로 어쩔 수 없는 요인이라고 해야할까? 사실 이 문제는 이미 사회적으로도 충분히 고려되고 있는 문제다. 그 떄문에 특정 조건의 학생들에게 학습 자료를 제공한다거나, 입학 전형을 분리해서 적용한다. 가정에 경제적 지원을 복지로 제공하는 것과는 별개로 말이다. 나는 열심히 공부해서 좋은 대학에 진학했다. 정말 최선을 다하여 공부했다고 자신할 수 있지만 내가 무능을 노력으로만 이겨냈다고 생각하지 않는다. 나는 수능을 보기 위해 필요한 재능을 어느정도는 타고났다. 공부에 대한 재능은 아니다. 그랬다면 변리사 시험을 통과하지 않았을까? 내가 언어를 잘 못했고, 6등급인 물리를 1등급으로 만드는데 3개월이 걸린 것을 생각하면 좀더 세분화되있는 재능으로 생각해야 한다. 유머글이지만, 페이커가 시대를 잘 태어났다는 글을 본 적이 있다. 조선시대에 태어났으면 롤드컵 4회 우승이 불가능했다는 내용이었다(물론 나의 빛 나의 사랑 대상혁은 뭘 해도 성공했을 위인이라고 생각한다). 마찬가지로 내가 수 만년 전 구석기시대에서 태어났으면 재능을 인정 받았을까? 지금은 이 재능이 대학 졸업장으로 변해 나의 가치를 뽐내는 데 정말 좋은 근거가 되어준다. 하지만 구석기 시대에서 수능 과학탐구 성적을 올리는 재능은 어떻게 인정받을 것인가? 더하기를 못해도 더 빠르게, 오래 달려 사냥을 잘하는 사람이 더 중요한 사람이지 않았을까? 그 시대에 사냥의 결과물을 능력주의로 분배한다면 난 내 밥벌이는 제대로 했을까? 이에 대한 고민을 해본 적이 있다. 내 결론은 “어떻게 완벽히 공정할 수 있겠어?” ...

2024년 2월 8일 · 8 분 · 배준수

Shopify API

Today I Learned 날짜 2024년 2월 7일 수요일 내용 새로 시작한 Task에 대해 파악하는데 하루 종일 썼다. 내가 등록한 ECS Task가 5일동안 작동하지 않았는데, 로그나 apm.capture에 아무것도 안떴다. 다시 작동하니까 아무 문제 없이 잘 되는데 이유를 모르겠다. 그냥 해프닝이길.. Shopify에서 정보 받아오기 메타필드(metafield) 그동안 잘 보지 않았던 부분이라 정확한 개념을 우선 파악했다. Shopify에는 스토어에 대한 정보를 저장하여 매번 서버에서 가져오지 않고 프론트에서 동적으로 출력하는데 사용할 수 있다. 데이터를 메타필드에 저장한다. ...

2024년 2월 7일 · 1 분 · 배준수

스프린트 준비

Today I Learned 날짜 2024년 2월 6일 화요일 내용 많은 것을 하진 못했다. weekly review report email은 잘 작동했지만 1가지 오류가 발생했다. 실서버 데이터 중 잘못된 데이터가 있어 그 샵의 시간대를 찾지 못했다. 어제 미처 추가하지 못한 부분이라 해당 부분에 대한 예외처리 코드를 추가했다. 당장 급한 Task는 없다고 생각해 테스트 코드를 작성하려고 했다. 이번에 만든 기능들에 대한 유닛테스트 코드를 작성해두고 싶었다. 2달? 정도 전 내가 이미 있던 테스트들이 고장나있던 상태라 고쳤는데 1가지 오류가 발생했다. 모든 타입의 위젯을 생성해보는 테스트였는데 특정 타입에서 item_per_page 라는 속성이 없어 발생한 문제였다. 각 위젯별로 위젯에 보여줄 아이템의 갯수를 설정할 수 있는데 GALLERY_GRID_TEMPLATE 타입에는 설정할 수 없다. 내가 파악하기론, GALLERY_GID 라는 위젯 안에 들어가는 템플릿이기 때문이다. 따라서 위젯을 생성하는 함수에서는 처리하지 않는 타입이라 오류가 발생했다. 제외 이유를 각주에 추가하고 테스트 케이스에서 제외했다. ...

2024년 2월 6일 · 1 분 · 배준수

예외 처리

Today I Learned 날짜 2024년 2월 5일 월요일 내용 이전에 진행했던 Task들을 마무리했다. 로컬에서는 문제없이 작동한다는 것을 확인했기 떄문에, 테스트 서버에서 확인이 필요했다. logging문으로 구체적인 예외 메시지를 확인할 수 있었는데, 특정 데이터가 None일 때 오류가 발생했다. 오류가 난 필드는 shop이 꼭 가지고 있어야 하는 데이터였기 때문에 이상했다. 테스트 서버의 데이터베이스를 확인해보니 모든 필드의 값이 None으로 되어있는 뜬금없는 데이터가 들어있었다. 그 레코드 하나를 지우면 해결될 일이지만, 실제 서버에서 이런일이 발생했다면 저 뜬금없는 레코드 하나때문에 작동을 안하고, 찾을려고 이리저리 뒤져볼 모습을 생각하니 해프닝으로 넘어갈 일은 아니라고 생각했다. ...

2024년 2월 5일 · 1 분 · 배준수

효율성에 매몰되지 않기

Today I Learned 날짜 2024년 2월 2일 금요일 내용 삼지선다 나름 기가 막힌 아이디어가 떠올라서, 어제의 Task를 처리했다. 내가 달성해야 할 구현 목표는 다음과 같다. 구글 스프레드시트에 있는 데이터는 기존 행에 새로운 값을 덮어써준다. 구글 스프레드시트에 없지만 2024년 2월 이후 가입했거나, 기존에 가입했으나 새로 AI 서비스를 이용하게 된 고객의 데이터는 새로운 행에 추가해준다. 서비스에서 탈퇴해 데이터가 없어졌을 떈 스프레드시트에서도 삭제한다. 추가된 데이터를 한번 정제해서 쓰면 되니 굳이 API가 완벽하게 정리된 데이터를 만들 필요는 없다고 하셨지만 뭔가 놓치고 있다는 느낌이 자꾸 들어 기존의 걸림돌을 되짚어봤다. ...

2024년 2월 2일 · 2 분 · 배준수

2.3 인터넷 전자메일

2.3 인터넷 전자메일 인터넷 메일 시스템의 상위 요소에는 다음 3가지가 있다. 사용자 에이전트(user agent) 사용자의 메시지 읽기, 전달, 저장, 구성을 담당 ex) 지메일, 마이크로소프트 아웃룩, 스파트몬용 지메일 앱 메일 서버(mail server) 각 수신자는 메일 서버 안에 **메일박스(mailbox)**를 갖고 있다. 메일박스는 수신한 메시지를 유지하고 관리한다. 송신자의 사용자 에이전트 → 송신자의 메일 서버 → 송신자의 메일 서버의 메시지 큐 → 수신자의 메일서버 → 수신자의 메일 서버 내 메일박스 수신자의 서버 고장으로 전달할 수 없으면 메시지를 **메시지 큐(message queue)**에 보관하고 나중에 전달을 재시도한다. SMTP(Simple Mail Transfer Protocol) 인터넷 전자메일을 위한 주요 애플리케이션 계층 프로토콜 TCP의 신뢰적인 데이터 전송 서비스를 이용 송신자의 메일 서버에서 수행하는 클라이언트와 수신자 메일 서버에서 수행되는 서버를 갖고 있음. 메일 서버가 송신할 때 : SMTP의 클라이언트로 동작 메일 서버가 수신할 때 : SMTP의 서버로 동작 2.3.1 SMTP A가 B에게 메일을 보내는 과정 A는 네이버의 전자메일 사용자 에이전트에게 B의 전자메일 주소(B@gmail.com)를 제공하고 메시지를 작성하여 메시지를 보내라고 명령한다. A의 사용자 에이전트(네이버)는 메시지를 A의 메일 서버에게 보내고 그 메시지는 서버에서 메시지 큐에 들어간다. A의 메일 서버에서 동작하는 SMTP의 클라이언트 측은 메시지 큐에서 메시지를 확인한다. 이후 B의 메일 서버에서 수행되는 SMTP 서버에게 TCP 연결을 설정한다. 이때 포트는 25. 초기 SMTP 핸드셰이킹 이후에 SMTP 클라이언트는 A의 메시지를 TCP 연결로 보낸다. B의 메일 서버 호스트에서 SMTP의 서버 측은 메시지를 수신한다. 이 메시지는 B의 메일 서버의 메일박스에 저장된다. B은 사용자 에이전트를 이용해 그 메시지를 읽는다. A와 B의 메일 서버가 물리적으로 거리가 멀더라도, 중간 메일 서버는 사용하지 않는다. 따라서 B의 서버가 죽어 있으면 전달하지 못한다. 이 떄, A 서버의 메시지 큐에 두고 지속적으로 재발송한다. 일정시간이 지나면, 폐기하고 A에게 발송이 실패했음을 알린다. 두 서버의 TCP 연결이 설정되면, SMTP의 서버와 클라이언트는 애플리케이션 계층 핸드셰이킹을 수행한다. 핸드셰이킹에서 서로에 대한 정보를 알게 되는 것처럼, 이때 클라이언트는 서버에게 두 사람(송신자와 수신자)의 전자메일 주소를 제공한다. 2.3.2 메일 메시지 포맷 우편을 보낼때, 편지 봉투에는 여러 정보가 담기게 된다(발신자, 수신자 등) 전자 메일에서는 메시지 몸체 앞에 있는 헤더에 담긴다. 2.3.3 메일 접속 프로토콜 메일 서버가 개인의 로컬호스트에 있다면, 항상 메일을 받기 위해 서버가 켜져있어야 한다. 따라서, 일반 사용자는 로컬 호스트에서 사용자 에이전트를 수행하고 늘 켜져 있는 공유 메일 서버에 저장된 메일박스에 접근한다. 즉, 메일 서버는 보통 사용자들과 공유한다. 송신자의 사용자 에이전트는 메일 서버를 통해 수신자의 메일 서버로 메시지를 전송한다. 왜 송신자의 사용자 에이전트가 직접 수신자의 메일 서버로 메시지를 전송하지 않을까? 송신자의 사용자 에이전트는 수신자의 메일 서버에 도달할 수 없기 때문 이유는 보안 문제, SMTP의 규약, 스팸 방지, 신뢰성 보장 등 다양하다. 수신자의 사용자 에이전트는 받은 메시지를 보기 위해 SMTP를 사용할 수 없다. SMTP는 push지만 메시지는 pull 해야 하기 때문 메시지를 받는 방법 HTTP를 통해 요청 인터넷 메일 접근 프로토콜(Internet Mail Access Protocol, IMAP) 사용 이 둘 모두 메일 서버에 의해 유지되는 폴더를 관리하게 된다.

2024년 2월 1일 · 3 분 · 배준수

구글 스프레드시트에 기존 데이터 업데이트하기

Today I Learned 날짜 2024년 2월 1일 목요일 내용 스프린트 결과가 배포됐다. 다행히 큰 빵꾸는 없었다. 많은 유저가 몰려왔으면 좋겠다. 구글 스프레드시트에 데이터 추가하기 새로 만든 기능에 대한 KPI 데이터를 구글 스프레드시트에 추가하는 태스크를 맡았다. 이전에, 작동이 멈췄던 커맨드를 다시 돌리는 작업을 했었는데 이와 비슷할거라고 생각해서 별로 어렵지 않겠다 싶었다. 약간의 차이점이 있었는데 이 부분을 너무 쉽게 생각했다. 기존에는 매일매일 새로운 행에 데이터를 추가했지만, 이번에는 기존 데이터에 덮어써야 했다. 1개의 샵 당 1개의 데이터를 가지게 되며, 이미 데이터가 존재한다면 새로 행을 추가하지 않고 수정해야 한다. ...

2024년 2월 1일 · 3 분 · 배준수

2.2 웹과 HTTP(2)

2.2.3 HTTP 메시지 포맷 HTTP 요청 메시지 ex) 1 2 3 4 5 GET /somedir/page.html HTTP1.1 Host: www.abc.com Connection: close User-agent: Mozilla/5.0 Accept-language: fr 메시지가 일반 아스키 텍스트로 쓰여있어 우리가 읽을 수 있다. 메시지는 5줄로 되어있고 각 줄은 CR(carriage return, \r)과 LF(line feed, \n)로 구별된다. CR : \r, 맨 앞으로 이동하라는 뜻 LF: \n, 새로운 라인 첫 줄을 **요청 라인(request line)**이라고 부른다. 3개의 필드로 구성 : method(GET), URL(/somedir/page.html), HTTP 버전(HTTP1.1) 이후의 줄들은 **헤더 라인(header line)**이라고 부른다. 요청하는 객체가 존재하는 호스트(Host) 명시 TCP 연결에서 이미 알게 되었지만, 웹 프록시 캐시에서 필요함 비지속 연결 명시(Connection) 요청을 보내는 브라우저 타입(User-agent) 객체의 언어 버전(Accept-language) : 서버에 있다면 프랑스어로 보낼 것 헤더라인 이후에 개체 몸체(entity body)가 있음. POST 방식에서만 존재하는, 클라이언트가 채워 넣는 곳 GET요청에서는 body 대신 URL 끝에 parameter로 추가됨(https://url.com?…) HEAD 방식 HTTP 메시지로 응답하고, 요청 객체를 보내지 않음 개발자의 디버깅에 많이 사용 PUT, DELETE, … HTTP 응답 메시지 ex) ...

2024년 1월 31일 · 5 분 · 배준수