30 min
Saito
  1. 1. Information
    1. 1.1. Ingredients
    2. 1.2. Functions
  2. 2. Create the application
    1. 2.1. Frontend
    2. 2.2. Backend
  3. 3. Customize the application
    1. 3.1. Frontend
    2. 3.2. Backend
  4. 4. Deploy the application
    1. 4.1. Backend
    2. 4.2. Frontend
  5. 5. Download
  6. 6. Version

Only a few steps are needed to use the searching movies API of YouTube and show results of it.

In this tutorial, I’ll show you how to use the API and how to modify the application.

Information

Ingredients

  • Template: Simple Search
  • API Loigcs: YouTube Data API Search Video

Functions

  • Searching movies on YouTube.
  • Displaying a list of the movies.
  • Playing a movie in a dialog.

Create the application

Frontend

  1. Choose the Simple Search Template.

  2. Click the Search Page.

  3. Change the card from VerticalCard002 to VerticalCard003 to display more information.
    (VerticalCard003 is next to the right of the default card.)

  4. Customize the UI in K5 Playground.

Backend

  1. Change the WebAPI name.

    • Rename the sample_products to movies.
  2. Edit the API Logic of the GET /movies.

    1. Click the GET /movies endpoint.

    2. Remove the Fetch Document API Logic.

    3. Add the Search Video API Logic from Search menu at the right pane.

    4. Modify the code as follows.

      1. Set API Key

        1
        var apiKey =  '[API Key]';
      2. Set search keyword

        1
        var q = req.swagger.params.keyword.value;
      3. Change the part for extra information on movies.

        1
        var part = 'snippet';
      4. Create the pageToken variable for paging function.

        1
        var pageToken = req.swagger.params.offset.value ? ('&pageToken=' + req.swagger.params.offset.value) : '';
      5. Change the options.
        Set the maxResults and the pageToken for paging function and set the order for sorting.

        1
        2
        3
        4
        5
        6
        7
        8
        9
        var options = {
        url: url +
        "?key=" + apiKey +
        "&part=" + part +
        "&q=" + q +
        "&order=" + req.swagger.params.sort.value +
        "&maxResults=" + req.swagger.params.limit.value +
        pageToken,
        method: 'GET',
  3. Download the application.

Customize the application

Frontend

  1. Edit the actions/ProductActionCreators.js.

    Modify the code of the getProducts method.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    getProducts({ offset, limit, sort, keyword }) {
    const getProducts = api.get('/movies', {
    params: {
    keyword,
    offset,
    limit,
    sort,
    },
    });

    axios.all([getProducts])
    .then(axios.spread((productList) => {
    AppDispatcher.dispatch({
    type: ActionTypes.GET_PRODUCTS,
    data: {
    products: productList.data.items,
    count: productList.data.pageInfo.totalResults,
    pageToken: {
    prev: productList.data.prevPageToken,
    next: productList.data.nextPageToken,
    },
    },
    });
    })).catch(() => {
    // @todo handle error
    });
    },
  2. Edit the stores/ProductsStore.js.

    Add the pageToken to the data format.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    getInitialState() {
    return {
    data: Immutable.fromJS({}).toOrderedMap(),
    count: 0,
    pageToken: {
    prev: undefined,
    next: undefined,
    },
    };
    }

    reduce(state, action) {
    switch (action.type) {
    case ActionTypes.GET_PRODUCTS: {
    return {
    data: new Immutable.OrderedMap(action.data.products.map(x => [x.id.videoId, x])),
    count: action.data.count,
    pageToken: action.data.pageToken,
    };
    }
  3. Edit the components/containers/ProductListContainer.js.

    Change the parameter of the getProducts and the props of the ProductListPage.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    componentWillMount() {
    ProductActionCreators.getProducts({
    limit: Constants.PRODUCT_MAX,
    keyword: this.state.filter.data.get('keyword'),
    });
    }

    render() {
    const { products, cart, filter } = this.state;

    return (
    <ProductListPage
    router={this.context.router}
    products={products.data}
    productsDisplayCount={products.data.count()}
    productsCount={products.count}
    cartBadge={cart.data.count()}
    keyword={filter.data.get('keyword')}
    pageToken={products.pageToken}
    {...this.props}
    />
    );
    }
  4. Edit the components/pages/ProductListPage.js.

    1. Imports the extr UI components for a dialog displaying movie.

      1
      2
      3
      4
      import { FlatButton, RaisedButton } from 'material-ui';
      import NavigationChevronLeft from 'material-ui/svg-icons/navigation/chevron-left';
      import NavigationChevronRight from 'material-ui/svg-icons/navigation/chevron-right';
      import Dialog from 'material-ui/Dialog';
    2. Change the propTypes.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      export default class ProductListPage extends Component {
      static propTypes = {
      products: PropTypes.shape({
      id: PropTypes.shape({
      videoId: PropTypes.string,
      }).isRequired,
      }).isRequired,
      productsDisplayCount: PropTypes.number.isRequired,
      productsCount: PropTypes.number.isRequired,
      cartBadge: PropTypes.number.isRequired,
      keyword: PropTypes.string.isRequired,
      pageToken: PropTypes.shape({
      prev: PropTypes.string,
      next: PropTypes.string,
      }).isRequired,
      };
    3. Change the default value for the state.

      1
      2
      3
      4
      5
      state = {
      currentPage: 1,
      sort: 'date',
      openCardId: '',
      }
    4. Change the parameter of the getProducts method in the handleSortChange.

      1
      2
      3
      4
      5
      ProductActionCreators.getProducts({
      limit: Constants.PRODUCT_MAX,
      sort: value,
      keyword: this.props.keyword,
      });
    5. Add the paging handlers.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      handlePreviousPage = () => {
      const { keyword, pageToken } = this.props;

      this.setState({
      currentPage: this.state.currentPage - 1,
      });

      ProductActionCreators.getProducts({
      limit: Constants.PRODUCT_MAX,
      keyword,
      offset: pageToken.prev,
      sort: this.state.sort,
      });
      }

      handleNextPage = () => {
      const { keyword, pageToken } = this.props;

      this.setState({
      currentPage: this.state.currentPage + 1,
      });

      ProductActionCreators.getProducts({
      limit: Constants.PRODUCT_MAX,
      keyword,
      offset: pageToken.next,
      sort: this.state.sort,
      });
      }

      render() {
    6. Change the const pager.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      const pager = (
      <VerticalLayout alignX={'center'} alignY={'middle'} style={styles.pager}>
      <div>
      <FlatButton
      disabled={!this.props.pageToken.prev}
      onClick={this.handlePreviousPage}
      icon={<NavigationChevronLeft />}
      />
      <FlatButton
      disabled={!this.props.pageToken.next}
      onClick={this.handleNextPage}
      icon={<NavigationChevronRight />}
      />
      </div>
      </VerticalLayout>
      );
    7. Change the sort options.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      const sort = (
      <HorizontalLayout alignX={'right'} alignY={'middle'} style={styles.sort}>
      <span style={styles.sortLabel}>Sort</span>
      <SelectField
      value={this.state.sort}
      onChange={(event, index, value) => this.handleSortChange(value)}
      style={styles.sortControl}
      >
      <MenuItem value="date" primaryText="date" />
      <MenuItem value="rating" primaryText="rating" />
      <MenuItem value="relevance" primaryText="relevance" />
      <MenuItem value="title" primaryText="title" />
      <MenuItem value="viewCount" primaryText="viewCount" />
      </SelectField>
      </HorizontalLayout>
      );
    8. Change the card to show movies.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      const card = value => (
      <div>
      <VerticalCard003
      key={value.id.videoId}
      imageAlt={value.snippet.title}
      imageSrc={value.snippet.thumbnails.high.url}
      title={value.snippet.title}
      description={value.snippet.description}
      contentStyle={{ paddingBottom: 12 }}
      highlighted={new Date(value.snippet.publishedAt).toLocaleString()}
      >
      <RaisedButton
      label="Play"
      onTouchTap={() => this.setState({ openCardId: value.id.videoId })}
      />
      </VerticalCard003>
      <Dialog
      actions={<RaisedButton
      label="close"
      onTouchTap={() => this.setState({ openCardId: '' })}
      />}
      contentStyle={{ textAlign: 'center' }}
      title={value.snippet.title}
      modal={false}
      open={value.id.videoId === this.state.openCardId}
      onRequestClose={() => this.setState({ openCardId: '' })}
      >
      <iframe
      height={600}
      width={600}
      src={
      open
      ? `https://www.youtube.com/embed/${value.id.videoId}?&autoplay=1`
      : `https://www.youtube.com/embed/${value.id.videoId}`
      }
      frameBorder="0"
      allowFullScreen
      />
      </Dialog>
      </div>
      );

Backend

  1. Edit the api/swagger.json
    1. Modify the movies/get/parameters property.
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      "parameters": [
      {
      "name": "keyword",
      "in": "query",
      "required": false,
      "type": "string",
      "default": "",
      "description": ""
      },
      {
      "name": "sort",
      "in": "query",
      "required": false,
      "type": "string",
      "default": "date",
      "description": ""
      },
      {
      "name": "offset",
      "in": "query",
      "required": false,
      "type": "string"
      },
      {
      "name": "limit",
      "in": "query",
      "required": false,
      "type": "number",
      "default": 10
      }
      ],

Deploy the application

Finally, all you need to do is deploying backend and frontend.

Backend

1
2
cd backend
cf push [APP_NAME]

Frontend

1
2
3
4
5
6
cd frontend
npm install
set API_URL=[Backend URL] # for Windows
export API_URL=[Backend URL] # for Mac/Linux
npm run build
cf push [APP_NAME] -p public

Download

NOTE: Removed all actions and components not in use.

Version

  • Simple Search Template: v1.0.0