Implementing Audio in a Podcast App with Strapi
Tags: strapi, nuxt, node, podcast
Published: 2022-01-17 13:22:58

Podcasts have exploded in popularity, and platforms including Google Podcasts and Spotify offer content creators a way to communicate their thoughts with listeners around the world. If you’d like to join them, you can create your own podcast app using Strapi and Nuxt.js. 

[Strapi](https://strapi.io/) is a headless CMS (content management system) based on Node.js that is used to build APIs. Strapi provides a UI where you can develop your collection types and subsequent APIs to fetch the data, using REST or GraphQL APIs. One of the benefits of Strapi is that it is completely open-source and self-hosted.

[Nuxt.js](https://nuxtjs.org) is a framework for building Vue.js apps that are universal in nature. The code written in Nuxt.js can run on both client and server, offering client-side rendering and server-side rendering at the same time.

In this tutorial, you’ll learn to implement audio in a podcast app. You’ll build your app in Nuxt.js and manage your podcast content in the Strapi CMS.

## Setting Up the Environment

You’ll just need to install Node.js to get started. The installation includes npm, which you’ll need to use Strapi and Nuxt.js. 

This tutorial uses Node v14.18.x, Strapi v4.0.x, and Nuxt.js v2.15.x.

The entire source code for this tutorial is available in this [GitHub repository](https://github.com/ravgeetdhillon/strapi-nuxtjs-podcast-app).

## Setting Up the Project

You’ll need a master directory that holds the code for both the frontend (Nuxt.js) and backend (Strapi). Open your terminal, navigate to a path of your choice, and create a project directory by running the following command:

```bash
mkdir strapi-nuxtjs-podcast-app
```

In the `strapi-nuxtjs-podcast-app` directory, you’ll install both Strapi and Nuxt.js projects.

### Setting Up Strapi

In your terminal, execute the following command to create the Strapi project:

```bash
npx create-strapi-app@latest backend --quickstart
```

This command will create a Strapi project with quickstart settings in the `backend` directory.

Once the execution completes for the above command, your Strapi project will start on port 1337 and open up [localhost:1337/admin/auth/register-admin](http://localhost:1337/admin/auth/register-admin) in your browser. Set up your administrative user:

![Administrative user sign-up form for Strapi](https://i.imgur.com/kVCJ9Gv.png)

Enter your details and click the **Let’s Start** button. You’ll be taken to the Strapi dashboard.

### Creating Podcasts Collection Type

Under the **Plugins** header in the left sidebar, click the **Content-Types Builder** tab and then click **Create new collection type** to create a new Strapi collection.

![Create a new collection](https://i.imgur.com/W5GlqKi.png)

In the modal that appears, create a new collection type with **Display name** - **Podcast** and click **Continue**.

![Create podcasts collection](https://i.imgur.com/hDbaDpO.png)

Next, create three fields for your collection type:

1. **title** - Text field with **Short text** type
    
    ![Create text field for podcast collection](https://i.imgur.com/duzDtdG.png)
    
2. **description** - Text field with **Long text** type
    
    ![Create description field for podcast collection](https://i.imgur.com/k4BWPR9.png)
    
3. **audio** - Media field with **Single media** type
    
    ![Create audio field for podcast collection](https://i.imgur.com/GB94IbK.png)

Once you have added all the fields, click the **Finish** button and save your collection type by clicking the **Save** button.

![Save podcast collection](https://i.imgur.com/oE976vl.png)

Your collection type is set up, and now you need to add data to it.

Under the **Collection Types** header in the left sidebar, click the **Podcasts** tab and then click **Add New Podcasts** to create a new entry:

![Add a new podcast](https://i.imgur.com/yIRWNIV.png)

Fill in the fields for **Title**, **Description**, and **Audio** and click **Save**.

![Create a new podcast with title, description, and audio fields](https://i.imgur.com/f8Fl6eR.png)

This will save your podcast entry as a draft, and it will not be available when you query the podcast’s API. Click **Publish** to make the podcast entry live.

![Save new podcast entry](https://i.imgur.com/fuQwwIO.png)

Add a couple more podcasts in the same way. Check your **Podcasts List View** to see all the published podcasts.

![List view of all podcasts](https://i.imgur.com/XXY5cO1.png)

### Setting Up Permissions for Podcasts API

At this point, you have enough data in your Strapi CMS to test the API.

Open Postman and send a GET request to the Podcasts API endpoint, [localhost:1337/api/podcasts](http://localhost:1337/api/podcasts). You will not be able to access the endpoint because you have not allowed public access to it.

![Send GET request in Postman](https://i.imgur.com/cdWDV4d.png)

To configure the permissions for your podcast’s endpoint, click on the **Settings** tab under the **General** header, then select **Roles** under the **Users & Permissions Plugin**. Since you want to allow public access to your podcasts, you need to configure the permissions related to the **Public** role. Click the **Edit** icon to the right of the **Public** role.

![Edit permissions related to public role](https://i.imgur.com/HRAJ87V.png)

Scroll down to find the **Permissions** tab and check the **find** and **findone** routes for the Podcasts collection type. Save the updated permissions by clicking the **Save** button.

![Configure role permissions in Strapi](https://i.imgur.com/nHgaqEu.png)

Go back to Postman, send a GET request to [localhost:1337/api/podcasts](http://localhost:1337/api/podcasts), and you’ll get the list of podcasts from Strapi.

![Send GET request in Postman](https://i.imgur.com/umfbfkd.png)

Next, send a GET request to [localhost:1337/api/podcasts/2](http://localhost:1337/api/podcasts/2) and you’ll get the individual podcast with ID 2 as a response from Strapi.

![Send GET request in Postman to get a single podcast](https://i.imgur.com/M1Evc0V.png)

Strapi setup is complete. Now you’re ready to fetch podcasts in your Nuxt.js app.

## Setting Up Nuxt.js

It’s time to build the Nuxt.js frontend app.

Since your current terminal window is serving the Strapi project, open another terminal window and execute the following command to create a Nuxt.js project:

```bash
npx create-nuxt-app frontend
```

On the terminal, you’ll be asked some questions about your Nuxt.js project. For this tutorial, choose the options highlighted below:

![Set up for Nuxt.js project](https://i.imgur.com/683neUq.png)

Once you have answered all the questions, it will install all the dependencies.

After the installation is complete, navigate into the `frontend` directory and start the Nuxt.js development server by running the following commands:

```bash
cd frontend
npm run dev
```

This will start the development server on port 3000 and take you to [localhost:3000](http://localhost:3000/). The first view of the Nuxt.js website will look like this:

![First view of Nuxt.js app](https://i.imgur.com/exTg1Gv.png)

### Setting Up @nuxtjs/strapi Module

[@nuxt/strapi](https://strapi.nuxtjs.org/) is the Nuxt module for integrating Strapi with Nuxt.js.

Shut down the Nuxt.js development server by pressing Control-C in your terminal and execute the following command to install the module for your Nuxt.js app:

```bash
npm install @nuxtjs/strapi --save
```

Once the installation is complete, open the `nuxt.config.js` file and add the following properties to the default object exported by `nuxt.config.js`:

```jsx
export default {
  ...
  // 1
  // environment variables used by nuxt
  publicRuntimeConfig: {
    strapiEndpoint: 'http://localhost:1337',
  },

  // 2
  modules: [
    '@nuxtjs/strapi',
  ],

  // 3
  strapi: {
    url: 'http://localhost:1337/api',
    entities: ['podcasts'],
  },
  ...
}
```

In the above config:

1. You added `strapiEndpoint` to the `publicRuntimeConfig` so that you can access it anywhere in the Nuxt.js app by using `$config.strapiEndpoint`.
2. You added the `@nuxtjs/strapi` module to the `modules` array so that Nuxt.js loads this package whenever the Nuxt.js app is initialized.
3. You declare the `strapi` config variable. `url` corresponds to the URL from which the Strapi serves its API. In the `entities` array, you can specify the collection types present in your API. This will help you to access them using the `$strapi` object; for example, `$strapi.$podcasts`. For more options, check the [official documentation](https://strapi.nuxtjs.org).

## Implementing Audio

Now that you have set up the necessary packages for developing your Nuxt.js website, you need to design a podcasts page.

### Designing Podcasts Page

This page will fetch your podcasts from Strapi CMS and display them in the UI.

In the `pages` directory, open the `index.vue` file and replace all the existing code with the following code:

```jsx
<template>
  <section class="py-5">
    <b-container>
      <b-row>
        <b-col lg="7" class="mx-lg-auto">
          <!-- 3 -->
          <div v-if="!podcasts">Loading...</div>
          <div v-else>
            <h1 class="mb-5 border-bottom">Podcasts</h1>
            <!-- 4 -->
            <div v-for="(podcast, index) in podcasts.data" :key="index" class="mb-4">
              <h2 class="h4">{{ podcast.attributes.title }}</h2>
              <p class="mb-1">{{ podcast.attributes.description }}</p>
              <nuxt-link :to="`/podcasts/${podcast.id}`">Listen</nuxt-link>
            </div>
          </div>
        </b-col>
      </b-row>
    </b-container>
  </section>
</template>

<script>
export default {
  data() {
    return {
      // 1
      podcasts: null,
    }
  },
  // 2
  async created() {
    const response = await this.$strapi.$podcasts.find()
    this.podcasts = response.data
  },
}
</script>
```

In the above code:

1. You set the `podcasts` as `null` in the `data` object, which is passed to the `<template>`.
2. In the `created` lifecycle hook, you fetch (`find()`) all the podcasts (`$podcasts`) from the Strapi (`$strapi`) and assign the response (`response.data`) to the `podcasts` data variable.
3. In the `<template>`, you check if the `podcasts` variable is Falsy, then you render a `Loading...` message.
4. Once the `podcasts` variable evaluates to a Truthy, you loop (`v-for`) over it and render the podcasts with `title`, `description` attributes, and link to the individual route for each podcast using `podcast.id`.

Save your progress and start your Nuxt.js development server by running:

```bash
npm run dev
```

Visit [localhost:3000](http://localhost:3000/articles) and you’ll see your podcasts page rendered by Nuxt.js:

![Podcasts page in Nuxt.js app](https://i.imgur.com/2ViyZPV.png)

## Designing a Single Podcast Page

Now that you have created a podcasts page, the next step is to design a single podcast page that needs to be [dynamic](https://nuxtjs.org/docs/features/file-system-routing/) and provides the user with the option to listen to the podcast. You can fetch your podcast from the endpoint [localhost:1337/api/podcasts/:id](http://localhost:1337/api/podcasts/:id).

In the `pages` directory, create a subdirectory, `podcasts`. Then at `pages/podcasts` path, create a `_id.vue` file and add the following code to it:

```jsx
<template>
  <section class="py-5">
    <b-container>
      <b-row>
        <b-col lg="7" class="mx-lg-auto">
          <!-- 3 -->
          <div v-if="!podcast">Loading...</div>
          <!-- 4 -->
          <div v-else>
            <h1 class="mb-5 border-bottom">{{ podcast.attributes.title }}</h1>
            <!-- 5 -->
            <audio class="mb-4" controls>
              <source
                :src="`${$config.strapiEndpoint}${podcast.attributes.audio.data.attributes.url}`"
                :type="podcast.attributes.audio.data.attributes.mime"
              />
              Your browser does not support the audio.
            </audio>
            <p class="mb-2">{{ podcast.attributes.description }}</p>
            <nuxt-link to="/">Back</nuxt-link>
          </div>
        </b-col>
      </b-row>
    </b-container>
  </section>
</template>

<script>
export default {
  data() {
    return {
      // 1
      podcast: null,
    }
  },
  // 2
  async created() {
    const { id } = this.$route.params
    const response = await this.$strapi.$podcasts.findOne(id, { populate: '*' })
    this.podcast = response.data
  },
}
</script>
```

In the above code:

1. You set the `podcast` as `null` in the `data` object, which is passed to the `<template>`.
2. In the `created` lifecycle hook, first you destructure the `id` of the dynamic route from the `this.$route.params` object. Then you use the `$strapi` object to fetch (`findOne()`) the podcast with id (`id`) and also pass the `populate: ‘*’` query parameter. This is required because in Strapi v4, relations, media, components, and dynamic zone fields are not sent by default in the response.
3. In the `<template>`, you check if the `podcast` variable is Falsy, then you render a `Loading...` message.
4. Once the `podcast` variable evaluates to a Truthy, you use Vue template variables to render the UI for it.
5. You use the `<audio>` tag for rendering the podcast’s audio URL (`podcast.audio.url`) and set the `type` prop to `podcast.attributes.audio.data.attributes.mime`. Since `podcast.attributes.audio.data.attributes.url` is a relative path, you need to prepend it with `$config.strapiEndpoint`, which refers to the Strapi server URL.

Save your progress and wait for the server to hot reload. Click **Listen** on any podcast on the index page to open the single podcast page. Test the audio by clicking the play button and verify that everything works as expected:

![Audio rendered in Nuxt.js from Strapi](https://i.imgur.com/iJy08QL.gif)

## Conclusion

That's it! Although this tutorial focused on implementing audio in a Nuxt.js app, you can use any frontend framework with Strapi and render your audio. You can also use audio in a blog, so that a user can listen to your blog using an audio file instead of reading. 

You have many options for implementing audio in your customer-facing app. As you saw, [Strapi](https://strapi.io/) can help you set up your podcast easily and quickly. For more information on how Strapi can help you customize your content site, explore [its CMS solutions](https://strapi.io/solutions/editorial-cms).

The entire source code for this tutorial is available in this [GitHub repository](https://github.com/ravgeetdhillon/strapi-nuxtjs-podcast-app).