# Write a Middleware for Youtube Playlist
This article explains the steps to implement a Middleware for a Youtube Playlist Widget Provider.
Given the following HTML page, we need to integrate the Youtube Playlist into the Marfeel version of the website.
<html>
<body>
<h1>Learning more about Middleware</h1>
<p>
This tutorial series will teach you everything you'll need to know about Middleware.
</p>
<div class="video_playlist">
<iframe src="https://www.youtube.com/watch?v=2pZmKW9-I_k">
<a class="video_play" data-video-url="https://www.youtube.com/watch?v=iTZ1-85I77c">
<img src="https://i.ytimg.com/vi/2pZmKW9-I_k/hqdefault.jpg?sqp=-oaymwEYCKgBEF5IVfKriqkDCwgBFQAAiEIYAXAB&rs=AOn4CLAAHeRygFd0XyAEzHXgh3lu9fj00Q" />
<h3>Middleware - Part 1</h3>
</a>
<a class="video_play" data-video-url="https://www.youtube.com/watch?v=0DzDqtcxnz0">
<img src="https://i.ytimg.com/vi/2pZmKW9-I_k/hqdefault.jpg?sqp=-oaymwEYCKgBEF5IVfKriqkDCwgBFQAAiEIYAXAB&rs=AOn4CLAAHeRygFd0XyAEzHXgh3lu9fj00Q" />
<h3>Middleware - Part 2</h3>
</a>
<a class="video_play" data-video-url="https://www.youtube.com/watch?v=0DzDqtcxnz0">
<img src="https://i.ytimg.com/vi/2pZmKW9-I_k/hqdefault.jpg?sqp=-oaymwEYCKgBEF5IVfKriqkDCwgBFQAAiEIYAXAB&rs=AOn4CLAAHeRygFd0XyAEzHXgh3lu9fj00Q" />
<h3>Middleware - Part 3</h3>
</a>
</iframe>
</div>
</body>
</html>
# Youtube Playlist Widget Provider
At Marfeel, there is already a Widget Provider for Youtube Playlist Widget Provider (opens new window) available. If we take a look at its schema, we'll see that it has two required properties, videoSrc
and videos
.
videos
has its schema, finding that the expected format is an array of objects containing at least, an id
property.
TIP
Schemas are auto-generated and available within the package. Find it within the node_modules folder of the repository you are working on.
The path will be similar to node_modules/@marfeel/widget/schema/index.json
.
To send the correct values for these parameters you'll implement a Middleware that uses the OnExtraction hook, the Middleware will retrieve the data from the tenant's page and pass it to the Widget Provider.
The Middleware implementation will receive the tenant's HTML as the document
parameter.
# Implementation guide
First, locate where the data you need it is and implement a logic that finds the desired element from the document and processes it to retrieve the information required:
const wrapper = document.querySelector('.video_playlist');
const iframe = wrapper.querySelector('iframe');
const videoSrc = iframe.getAttribute('src');
const videos = [...wrapper.querySelectorAll('a.video_play')]
.map((element) => {
const id = element.dataset.videoUrl.replace('https://www.youtube.com/watch?v=', '');
const imgSrc = element.querySelector('img')?.getAttribute('src');
const title = element.querySelector('h3')?.textContent;
return {
id,
imgSrc,
title
};
});
In this example we use document.querySelector('.video_playlist')
(opens new window) to find the target element. Its src
attribute corresponds to the videoSrc
parameter.
Then, we find the video elements a.video_play
and iterate them with a map
function (opens new window) where we use the replace
string manipulation method (opens new window) to retrieve the desired id.
Each video image source is extracted from the img
element and the title from the h3
of each video element.
Once all required values are retrieved, you need to return an object that matches the signature of YoutubePlaylistProps
(opens new window). In this case, an object with the videoSrc
and an array of videos
and their parameters.
// on-extraction.ts
import { YoutubePlaylistProps } from '@marfeel/widget-providers-youtube-playlist';
import { onExtractionFunction } from '@marfeel/middlewares-types';
export const onExtraction: onExtractionFunction<YoutubePlaylistProps> = async ({ document }): Promise<YoutubePlaylistProps | undefined> => {
const wrapper = document.querySelector('.video_playlist');
if (!wrapper) {
return;
}
const iframe = wrapper.querySelector('iframe');
if (!iframe) {
return;
}
const videoSrc = iframe.getAttribute('src');
const videos = [...wrapper.querySelectorAll('a.video_play')]
.map((element) => {
const id = element.dataset.videoUrl.replace('https://www.youtube.com/watch?v=', '');
const imgSrc = element.querySelector('img')?.getAttribute('src');
const title = element.querySelector('h3')?.textContent;
return {
id,
imgSrc,
title
};
});
return {
videoSrc,
videos
};
};
# Create the test
All providers require an associated test, and all Middleware tests are very alike.
Read more on how to create tests for Middleware.