Building a custom Contentful app for the Last.fm API
![Through the magic of APIs, we'll show you how to create a Contentful app that pulls in music and album covers from Last.fm to brighten up your content.](https://images.ctfassets.net/fo9twyrwpveg/3JR3RmPCeDuwFyziq6kPTD/c47304466197c018de914634586e615c/2022-12-custom-app-last.fm-api.png?fm=jpg&q=90&w=1536)
Recently I watched my first musical — the stage version of Back to the Future — and I was amazed! It was the most beautiful, entertaining performance that I have ever seen. And just like the rest of my team, I became a fan of musicals!
If you’ve never had the pleasure, a musical is a form of art performance that combines acting, dancing, and music, with storytelling that takes place in the form of songs. Some of the most popular musicals in the world are Hamilton, Wicked, and The Lion King.
I have become such a huge fan that for every project I work on, I want to tie them to musicals! As a result, I created a Contentful app that allows users to add soundtrack album details to their content. Of course, you could also add conventional albums, but my starting inspiration is a fondness for musicals.
In this article, I’ll walk you through the steps of creating the Last.fm app and help you add some music to your content. So Marty McFly, let's get started!
![Back to the Future](https://images.ctfassets.net/fo9twyrwpveg/2b6yi87qf4mZbN8hUAI9vS/d580650641e616fc8eca60c7153a1f82/unnamed__26_.png)
What is Last.fm?
Last.fm is a popular online service that offers music information. You can get details on the artists, albums, top songs, and more. After you create your user profile, the platform can recommend songs based on your listening habits. For this app, you will use the Album Search API provided by Last.fm.
Prerequisites
To build this app, you will need the following:
Last.fm API Account: Sign up for a Last.fm API account and create a new app. Follow the instructions mentioned in this documentation to create an app and generate an API Key.
Contentful space: If you don’t already have an account on Contentful, sign up here and create a space with at least one content type. If you are unsure about how to create content types, follow the instructions mentioned in this documentation.
Node.js and npm: To develop and run the app locally, you need Node.js. Install Node.js, and it will also install npm for you.
Quick start
If you want to skip the details and get started quickly, you can find the application on GitHub. You can install it on your Contentful space directly, or run it locally on your machine.
To learn to build the app from scratch, then keep on reading.
Bootstrap the app
You can create apps for your Contentful space to customize the editorial experience, integrate external services, and much more.Â
To create apps for your Contentful space, you will use the App Framework. The App Framework provides all the necessary tools to create apps. It provides packages that allow you to interact with the APIs, interact with various locations, and more.Â
If you want to learn more about the App Framework, check out the documentation.
You can use the CLI to create an app on your machine by running the following command to bootstrap the app.
NOTE: By default, the above command will bootstrap the project in TypeScript. If you want to use JavaScript, use the --javascript
flag.
Once the repo is ready, you can start the local server by running the following command from the project directory.
If you navigate to localhost:3000, you will see a warning message that states that you can’t view the app outside Contentful.Â
In the next section, you will learn to create an app in Contentful and interact with the app inside Contentful.
Creating an app in Contentful
Now that you have the project running locally, the next step is to create the app and configure its app definition in Contentful. The app definition will allow you to select the locations, the host URL, and other parameters for your app.
Login to your Contentful space and select Manage apps from the Apps dropdown list. Next, click on Manage app definitions on the top left, and then click on the Create app button.
Enter a name for your app in the App name field, and click on Create app. This will create a new app and take you to the app’s definition page.Â
Since you will be running the app locally during development, on the App definition screen, enter http://localhost:3000 in the frontend field.Â
Next, under Locations, select the App configuration screen. The app configuration location lets you get configuration details from your users, e.g., setting the Last.fm API key.
You also need to select Entry field > JSON object. This is the location that will allow users to interact with the app and store information.Â
Click on the Save button to save the app definition. Your app definition should be the same as the following image.
![App details](https://images.ctfassets.net/fo9twyrwpveg/3vT7UAMbpxdscc2rpTYITc/7fad1ab5ccdfab186d3a0ce783641a1a/unnamed__27_.png)
To install the app on your Contentful space, click on Actions and select Install to space.Â
Select your space from the Select a space dropdown list and the environment from the Select an environment dropdown list. Authorize the app, and you will be greeted with the default App config page.Â
In the next section, you will learn how to customize the App configuration location.
Customize the App configuration location
The App configuration location is the first screen a user will interact with after installing the app if you have configured it in the App definition. This is where the user can provide details like the API Key, properties they want to fetch, etc.
To customize the App configuration location, open the src/locations/ConfigScreen.tsx
file. To add a form, replace the code inside return()
with the following code.
The above code uses the Flex
, Form
, FormControl
, and TextInput
components from Forma 36. Update your imports to use these components.Â
You can also observe that the TextInput
value attribute gets the value from parameters.apiKey
.Â
The parameters is a state of the type AppInstallationParameters
that is already defined for you.Â
To make the most out of TypeScript, update the AppInstallationParameters
. Your app AppInstallationParameters should be as follows.
The final code should look as follows.
Diving deeper into code is out of the scope of this article. If you’re interested in learning more, you can read the official documentation.Â
But here’s a quick summary of what the code does: when the app gets installed for the first time, the user views this form. Here the user enters their API key. The API key is stored in the parameters object when the user clicks the Install button. This allows you to reference the value from any other location.
Save the code, and you will now view the form in the App configuration location. Enter your Last.fm API key, and hit Install.Â
Your app is now installed and ready for use!
![Last.fm](https://images.ctfassets.net/fo9twyrwpveg/4piH5oSnGhiAUIDLVyX9ss/0f0f6d5c4e35640ddd59152ec4ed7a2b/unnamed__30_.png)
In the content type where you want to add the album data, create a new field of the type JSON object. Make sure you select your app in the Appearance tab.
![Last.fm](https://images.ctfassets.net/fo9twyrwpveg/274L4oU9Vgmj3oggEq3Tfr/d9245c5e971b4ce2b9ac7b31273a89ca/unnamed__31_.png)
Create a new entry for that content type, and you should see the default JSON editor. You will learn how to customize this field in the next section.
Customize the Entry Field location
While configuring the App definition, you selected the App configuration as the Entry field location.Â
In the previous section, you customized the App configuration location. In this section, you will customize the Entry field location to display user input and render data.
For this app, the user will enter the album name they want to add. The app will return all the relevant albums from the API and display them to the user in a dialog component. The user selects the album, and the app saves the album information.Â
Similar to the App configuration location, you can customize the Entry field location in the src/locations/Field.tsx
file. Open the file and replace the return statement with the following code.
Update your imports to include Form
, FormControl
, TextInput
, and the Button
components.Â
If you observe the code carefully, there is an albumSearch
state and an openDialog
function. Initialize the albumSearch
state as follows. Make sure to update your imports for the useState
hook.Â
Next, define the openDialog
function as follows.
The above function will open up a dialog component that returns the result from the Last.fm API. You’re passing the albumName
parameter, which gets used within the Dialog
component.
Your final code should look as follows.
Save the code, and the app will hot reload. Your field will now have an input field and a button similar to the image below.
![last.fm](https://images.ctfassets.net/fo9twyrwpveg/553H0ooCBAMSY9bEcy6l1H/d67d667bd54759f5565fdb1befcdb785/unnamed__32_.png)
Try submitting the form and the dialog box will render. You know what’s next Marty — customizing the dialog component.
Fetching the data and customizing the dialog component
In this section, you will learn to customize the dialog component. This component will fetch the data from the Last.fm API, and present it to the user.
Open the src/locations/Dialog.tsx
file and the following TypeScript interfaces.
Next, declare a state album of the type Album. You will store the result of the API call in the album state. You use the API key to fetch data from Last.fm. Since you already set the API key when installing the app, you will use that API key. Destruct the apiKey
from sdk.parameters.installation
.
Now that you have the state and the API key, you will define a function that will fetch the data from the Last.fm API. Copy and paste the following function code.
In the above code, you are using the fetch API to fetch the results from the API. In the query parameters, you passed the album name (albumName
) and the API key (apiKey
).Â
Once you get a response from the API, you resolve the promise using the json()
method and destruct the results array. Lastly, you update the value of the album state with the required result.
The app takes the search query from the input field you created earlier. Once the user submits the form, the dialog gets rendered. The fetchData
function should execute as soon as the component gets rendered.Â
Hence, add a useEffect
hook, and call the fetchData
function passing the album name from the input field. Below is the code that does just that.
Your component will fetch the data every time the user searches for a new album. However, the component still doesn’t render the data. Replace the return with the following code to display the data in the dialog component.
Let’s understand what is happening in the above code. Using the IF statement, you first check whether the album contains any value. If the app is fetching the data, the album state is null, and the user will see a spinner. But once the data gets fetched, the result gets rendered.
The onClick
attribute of the EntityList.Item
component closes the dialog component and sends the name and image information of the selected album back to the field location.
Before moving on to the next section, add the useAutoResizer()
hook to your dialog component. This hook handles the resizing of the component. Your dialog component should look as follows.
Store album data in Contentful
With your app, a user can search for their favorite album. Once the user selects the album from the search result, the app neither displays it to the user nor stores the data in Contentful. Whoops!
In this section, you will update the Field component to render the selected data and store it in Contentful.
Open the src/locations/Field.tsx
file and declare the Album
interface.
Next, import the useFieldValue
hook from the @contentful/react-apps-toolkit
package and declare albumData
as follows.Â
Update the openDialog
function, and set the value of albumData
to album.
When the user selects an album from the list, the dialog box closes, returning the album name and the album image. The above code stores this object value in the field. The user might close the dialog without selecting an album. The IF statement takes care of that.
The last step is to update our component to display the selected album. Add the following code at the end of the closing Form
tag.
Here, you are checking again if albumData
contains any data or not. If it contains data returned from the dialog component, you render it using the AssetCard
component from Forma 36. You also added an action that allows the user to remove the selected album.
One last thing you should add is the useAutoResizer
hook. Your final code for the Field location should be as follows.
Try searching for a different album. Your app will now fetch the data, display the search result, and render the selected album.
![albumName](https://images.ctfassets.net/fo9twyrwpveg/2N6Y3875XfMBOTkv0B0Bus/b03aa592f8645a9354872a4fce7bb223/unnamed__33_.png)
What’s next?
In this article, you created a Contentful that integrates with an external API, and allows you to add content.
Now that your app is ready, host it for your team to use. You can host the app on Contentful or on external services like Netlify, Vercel, etc. Follow along with the documentation to learn how to host your app.
There are tons of apps created by the community that you can view on the Developer Showcase. If you create an app that might benefit others, consider making a submission.
And lastly, feel free to hit me up on Twitter to share your favorite musical, talk about Contentful, or ask questions.