콘텐츠 임베드에 oEmbed 사용하기

김혜진·2021년 4월 17일
1

올 초에 리치 에디터 내에 콘텐츠 임베드 작업을 하면서 oEmbed 라는 포맷을 처음 접했다.

사용자가 url입력시 youtube, vimeo, twitter와 같은 콘텐츠를 임베드해서 띄워주는 작업이었는데, 단순히 특정 프로바이더에서 제공하는 api만 사용할 수 있을거라 생각하던 중에 oEmbed라는 새로운 포맷이 있다는 것을 알게 되었다.

oEmbed

oEmbed is a format for allowing an embedded representation of a URL on third party sites. The simple API allows a website to display embedded content (such as photos or videos) when a user posts a link to that resource, without having to parse the resource directly.
oEmbed 문서 중

[번역]
oEmbed는 타사 사이트에서 URL의 내장된 표현을 허용하는 형식입니다. 단순 API를 사용하면 사용자가 리소스를 직접 구문 분석할 필요 없이 해당 리소스에 대한 링크를 게시할 때 포함된 콘텐츠(예: 사진 또는 비디오)를 표시할 수 있습니다.

단순히 문서 소개만 읽으면 이걸 왜 사용해야하는지에 대해 와닿지 않을 수 있어서 개인적으로 생각한 oEmbed 장점 몇 가지를 적어보려고 한다.

 

oEmbed를 사용하면 얻을 수 있는 이점

1. 각기 다른 프로바이더들의 embed API를 신경쓰지 않아도 된다.

예를 들어 youtube와 vimeo에서 각각의 api를 통해 bts를 검색한 결과를 임베드 한다고 가정해보자.

youtube api의 경우에는 https://www.googleapis.com/youtube/v3/search?q=bts 와 같이 url을 만들어 보내주어야 한다. 이외에도 필터링, channelId, channelType 등의 여러 매개변수를 쿼리 스트링으로 붙여 요청할 수 있다.

vimeo api의 경우에는 https://api.vimeo.com/videos?query=bts와 같은 url을 만들어 보내주어야 하며, youtube와 마찬가지로 direction, filter,per_page 등의 매개변수를 쿼리 스트링으로 붙여 요청할 수 있다.

이때 중요한 것은 각 프로바이더들마다 요청을 보내는 api가 다르다는 점이다. 그뿐 아니라 프로바이더 내에서도 videoId를 입력해 특정 콘텐츠를 가져온다거나 search, playlist, comments 등이 각각 다른 api를 가지고 있기 때문에 그에 맞는 주소를 찾아서 요청해야 한다.

그렇다면 사용자로부터 임베드를 원하는 주소를 받았을 때

  1. 프로바이더를 먼저 확인하고
  2. 해당 프로바이더내에서도 필요한 데이터를 제공하는 정해진 api 주소로 요청을 보내주어야 한다.

video 관련 예시이므로 youtube와 vimeo만 추가해두었는데 만약 instagram, facebook, twitter 등 다양한 콘텐츠 임베드를 제공해야 한다고 가정하면 그 수고로움이 어느 정도일지 예상하기 어렵지 않다🤔..

 

oEmbed 사용 시
바로 이런 경우에 oEmbed 포맷의 도움을 받을 수 있는데, 우선 아래의 yml 파일을 보자. 주요하게 보아야 할 곳은 schemesurl, example_urls 이다.

---
- provider_name: YouTube
  provider_url: https://www.youtube.com/
  endpoints:
  - schemes:
    - https://*.youtube.com/watch*
    - https://*.youtube.com/v/*
    - https://youtu.be/*
    url: https://www.youtube.com/oembed
    example_urls:
    - https://www.youtube.com/oembed?url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DiwGFalTRHDA
    - https://www.youtube.com/oembed?url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DiwGFalTRHDA&format=xml
...

---
- provider_name: Vimeo
  provider_url: https://vimeo.com/
  endpoints:
  - docs_url: https://developer.vimeo.com/apis/oembed
    schemes:
    - https://vimeo.com/*
    - https://vimeo.com/album/*/video/*
    - https://vimeo.com/channels/*/*
    - https://vimeo.com/groups/*/videos/*
    - https://vimeo.com/ondemand/*/*
    - https://player.vimeo.com/video/*
    url: https://vimeo.com/api/oembed.{format}
    example_urls:
    - https://vimeo.com/api/oembed.xml?url=http%3A%2F%2Fvimeo.com%2F76979871
    - https://vimeo.com/api/oembed.json?url=http%3A%2F%2Fvimeo.com%2F76979871
...

schemes는 사용자가 입력한 주소 중 oEmbed로 요청이 가능한 스키마를 의미하고, url 은 요청을 보내는 주소를 의미하며 쿼리 스트링에 임베드를 원하는 주소를 붙여주면 된다. 전체적인 요청 주소 예시 및 응답 포맷 및 example_urls 부분을 참고할 수 있다.

모든 스키마를 커버하지는 않기 때문에 위의 예시로 들었던 검색 등은 불가해진다. 하지만 특정 콘텐츠나 채널,.. 등 oEmbed가 제공하는 선에서는 하나의 api 주소를 사용할 수 있게 된다.

더 많은 oEmbed포맷을 제공하는 프로바이더와 각각의 스키마는 oEmbed/providers에서 확인할 수 있다.

 

2. provider가 달라도 응답은 (대체로) 정해진 포맷으로 전달 받을 수 있다.

비교를 위해 우선 각각의 프로바이더에서 제공하는 api를 사용했을 때의 응답 데이터를 살펴보자. 아래 참고에 써둔 문서들에서 직접 요청을 보내볼 수 있다. (한 눈에 살펴보기 위해 주요 데이터만 남겨둠.)

youtube의 경우

{
  "kind": "youtube#videoListResponse",
  "etag": "KS7iKvs0Wl9LVgCZqAFzK9bvgFM",
  "items": [
    {
      "kind": "youtube#video",
      "etag": "zq7hDQcIAqmFqw4lsxfN_TxSRDw",
      "id": "oCw8aTprplw",
      "snippet": {
        "publishedAt": "2021-03-26T12:03:03Z",
        "channelId": "UCeprvjzu8c9gYC5oLfW9nvg",
        "title": "아이유 노래모음 | IU | PLAYLIST",
        "description": "아이유 노래모음 | IU | PLAYLIST",
        },
        "channelTitle": "낭스월드",
        "tags": ["아이유", "노래모음", "IU", "PLAYLIST"],
        "categoryId": "10",
        "liveBroadcastContent": "none",
      }
    }
  ],
  //..
}

 
vimeo의 경우

{
  //.. 
  "data": [
    {
      "uri": "/videos/238341234",
      "name": "DNA -BTS",
      "description": "I LOVE BTS~~~~ DNA",
      "type": "video",
      "link": "https://vimeo.com/238341234",
      "duration": 255,
      "width": 1280,
      "language": null,
      "height": 720,
      "embed": {
        "html": "<iframe src=\"https://player.vimeo.com/video/238341234?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=2221\" width=\"1280\" height=\"720\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture\" allowfullscreen title=\"DNA -BTS\"></iframe>",
      },
      "created_time": "2017-10-16T03:54:09+00:00",
      "modified_time": "2021-04-16T06:15:29+00:00",
      "release_time": "2017-10-16T03:54:09+00:00",
    }
    //..
  ]
}    

여기서 중점적으로 보아야 할 것은 youtube와 vimeo에서 응답으로 받은 데이터들의 형태가 제각기 다르다는 점이다. 프로바이더들마다 응답 데이터의 형태가 각기 다르다면 관리하는 로직의 복잡성 역시 예상하기 어렵지 않다🤔..

 

oEmbed 사용 시
이때 oEmbed를 통해 요청을 보낸다면 비슷한 포맷의 응답을 기대할 수 있다. 아래의 youtube, vimeo, twitter의 응답 데이터를 보자.

youtube

{
  "type": "video",
  "author_name": "Relaxing Music핑크에이드",
  "provider_name": "YouTube",
  "provider_url": "https://www.youtube.com/",
  "width": 480,
  "height": 270,
  "html": "<iframe width="480" height="270" src="https://www.youtube.com/embed/uyBmtL0ZMeY?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>",
  "version": "1.0",
  "title": "2시간 연속 듣기 | Jazz & Pop 분위기로 듣는 캐롤 | 크리스마스 캐롤 | 성탄음악",
  "thumbnail_url": "https://i.ytimg.com/vi/uyBmtL0ZMeY/hqdefault.jpg",
  "thumbnail_height": 360,
  "thumbnail_width": 480
}

 
vimeo

{
  "type": "video"
  "author_name": "JayFactory",
  "author_url": "https://vimeo.com/jayfactory",
  "provider_name": "Vimeo",
  "provider_url": "https://vimeo.com/",
  "width": 426,
  "height": 240,
  "html": "<iframe src="https://player.vimeo.com/video/346721734?app_id=122963" width="426" height="240" frameborder="0" allow="autoplay; fullscreen" allowfullscreen title="BTS (방탄소년단) &amp;lsquo;Heartbeat (BTS WORLD OST)&amp;rsquo; MV"></iframe>",
  "version": "1.0",
  "title": "BTS (방탄소년단) ‘Heartbeat (BTS WORLD OST)’ MV",
  "thumbnail_url": "https://i.vimeocdn.com/video/796875098_295x166.jpg",
  "thumbnail_height": 166,
  "thumbnail_width": 295
}

 
twitter

{
  "type": "rich",
  "author_name": "Donald J. Trump",
  "author_url": "https://twitter.com/realDonaldTrump",
  "provider_name": "Twitter",
  "provider_url": "https://twitter.com",
  "width": 550,
  "height": null,
  "html": "<blockquote class="twitter-tweet"><p lang="en" dir="ltr">I won the Election!</p>&mdash; Donald J. Trump (@realDonaldTrump) <a href="https://twitter.com/realDonaldTrump/status/1328334945148952576?ref_src=twsrc%5Etfw">November 16, 2020</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>↵",
  "version": "1.0",
  "cache_age": "3153600000",
  "url": "https://twitter.com/realDonaldTrump/status/1328334945148952576"
}

type, provider_name, provider_url, width, height, html 등등.. 한 눈에 보기에도 공통 데이터가 많다는 것을 알 수 있다. html 값을 통해 각 프로바이더에서 제공하는 ui를 그려줄 수 있다.

그러므로 (그럴 일이 있을 진 모르겠지만..🤔) 콘텐츠 타입에 따라 그릴 ui를 정한다거나 필요한 정보만 걸러 서버에 저장한다거나,.. 이외에도 데이터 관리해야 할 경우에 공통 포맷을 가지고 있으므로서 훨씬 일이 수월해지게 된다. 또한, 서포트하는 프로바이더를 추가해야하는 경우에도 응답 형태를 1:1로 대응하지 않아도 된다.

 

3. url 이외의 데이터도 핸들링 할 수 있다.

이것은 oEmbed만의 장점은 아니고.. iframe의 단점에 가깝다..

api요청 없이 iframe의 src 속성에 곧바로 url을 꽂는 방법도 있기는 하다. 이럴 경우 사용자가 입력한 url만 저장해두면 되는데, 문제는 응답으로 받는 데이터가 없기 때문에 url이외의 데이터는 전혀 관리할 수 없게 된다는 것이다.

예를 들어, 각 프로바이더에서 제공하는 것을 사용하던 oEmbed를 사용하던 api요청을 보내면 위의 예시처럼 응답 데이터가 있기 때문에 이를 직접 관리할 수 있어 필요한 정보만 따로 서버에 저장할 수도 있고 특정 값만 띄우도록 ui를 제어할 수도 있다. 이에 반해 iframe에 src 속성을 이용해 띄우게 되면 iframe 내부는 다른 브라우저 영역이 되기 때문에 직접적인 제어가 어려워진다.

즉, 데이터 관리를 다른 브라우저에서 하도록 할 것인지 아니면 직접 할 것인지의 문제인 것 같다.

이외로도 iframe 사용으로 인한 보안상의 이슈나 사용자 경험 등에 대한 관리도 추가적으로 필요해진다.

 

마무리

초기 기획시 youtube, vimeo, twitter, facebook, instagram, pinterest.. 등의 프로바이더를 서포트해야 했는데, 각기 다른 주소로 요청을 받고 각기 다른 형태의 응답을 주어 로직이 지저분하고 복잡해졌었다. 당시 동료분이 oEmbed 포맷을 알려주셔서 찾아보았는데 사실 처음엔 문서가 꽤나 불친절해서 이걸 왜 써야하나 싶었는데 진행하면서 필요성을 깨달았다.

아 그리고 관련된 솔루션도 많다. 대표적으로는 embed.ly가 있는데 Medium 블로그도 임베드 형식을 까보면.. embed.ly를 통해 oEmbed 포맷을 사용하고 있음.

블로그로 정리하면서 문서를 다시 보니 약 두 달 전에 보던 문서와 꽤 많이 달라져 있었다..👀 굉장히 빠르게 업데이트 되는 것을 보면 앞으로도 오래 오래 사용되지 않을까 하는 생각이 든다.

 

참고


https://github.com/iamcal/oembed/
https://developers.google.com/youtube/v3/docs/search/list
https://developer.vimeo.com/api/reference/videos#search_videos
https://www.ostraining.com/blog/webdesign/against-using-iframes/
https://css-tricks.com/oembed/#why-use-oembed

profile
꿈꿀 수 있는 개발자가 되고 싶습니다

1개의 댓글

comment-user-thumbnail
2022년 4월 17일

안녕하세요 ! oembed 포스팅 잘 봤습니다 :) 혹시 데이터를 받아올때 cors에러는 뜨지 않으셨는지 궁금합니다 !

답글 달기