Aller au contenu principal

EPITUNES

Epimac workshop, about 45 minutes.

You are going to build a small music search app with React Native, Expo and TypeScript. You type an artist name, the app calls the iTunes API and displays the songs with their cover. It runs on your own phone, iOS or Android.

info

Requirements: a computer with a web browser and a phone (iPhone or Android). No Mac needed and nothing to install on the computer. You can work alone or in a group of 2 to 4.

Working in a group​

Each group uses one Snack, on one computer. Change who types at every step, so that everybody writes some code. Everyone in the group can scan the QR code of this Snack and run the app on their own phone.

At the end, the group sends one link in the form, with the names of all the members.

Project tree​

EPITUNES/
README.mdx
starter/
App.tsx
package.json
tsconfig.json
api/
itunes.ts
components/
SongCard.tsx
data/
sampleSongs.ts
types/
song.ts

starter/ is the skeleton you have to complete:

  • App.tsx is the main screen, with the search bar and the list of songs
  • api/itunes.ts contains the call to the API (step 2)
  • components/SongCard.tsx displays one song of the list (steps 1 and 3)
  • data/sampleSongs.ts contains 5 hardcoded songs, used until your search works
  • types/song.ts contains the Song type, the shape of a song

Where to find the skeleton​

You don't need to clone this repo. The files of starter/ are already loaded in this Snack:

https://snack.expo.dev/@yasminebnl/epitunes

Snack is the online editor of Expo. Open the link and work directly in it: your changes stay in your browser, the original is not modified.

In the code, everything you have to write is marked with a TODO and the number of the step.

Why Expo, React Native and TypeScript​

Not everyone has a Mac, and you need one to build a native iOS app because Xcode only exists on macOS. With React Native you write the app once and it runs on both iOS and Android. Expo provides the tools around it. Today we use two of them: Snack, the online editor, and Expo Go, an app that runs your code on your phone.

The code is written in TypeScript. It is JavaScript with types: the editor knows the shape of your data and warns you when you use a field that doesn't exist.

During the workshop your app runs inside Expo Go. Publishing an app on the App Store or the Play Store is also possible with Expo, without a Mac, but you need developer accounts. It is explained in the Expo documentation (links at the end).

Timing​

StepTime
0. Setup5 min
1. Display the songs10 min
2. Call the API15 min
3. Customize10 min
4. Bonus: open the previewif you have time
Send your link and show your app5 min

TypeScript notes if you only know C​

  • Like in C, values have types, but the type comes after the name: const name: string = 'toto';. Most of the time you can skip it, TypeScript guesses it.
  • type Song = { ... } describes an object, like a struct. A ? after a field name means that the field can be missing.
  • Strings are written with quotes and you concatenate them with +.
  • song.trackName reads a field, like with a struct.
  • In the part of the code that looks like HTML, {value} inserts the value of a variable. View is a container, Text displays text and Image displays an image.
astuce

When the editor underlines something in red, put your mouse on it. The message usually tells you what is wrong.

Step 0: setup​

  1. Install Expo Go on your phone, or update it if you already have it. Expo Go asks you to log in: create a free Expo account, it takes a minute.
  2. Open the Snack link on the computer of the group.
  3. In Snack, in the panel on the right, select My Device. A QR code shows up.

Install Expo Go from the App Store. Open the Camera app and scan the QR code.

remarque

Expected result: the title "EPITUNES", a search bar, a Search button and 5 cards with "Song title", "Artist name" and a link "Open in Apple Music", without any cover. All the cards are identical for now, it's normal.

The app reloads by itself every time you edit the code. If the screen turns red, you have a syntax error and the first line of the message tells you where.

attention

Your code only exists in the browser tab. Don't close it before you have sent us your link.

Step 1: display the songs​

File: components/SongCard.tsx

First open types/song.ts. The Song type describes one song:

export type Song = {
trackId: number;
trackName: string;
artistName: string;
collectionName: string;
artworkUrl100: string;
trackViewUrl: string;
previewUrl?: string;
};
FieldContent
trackIdunique ID of the song
trackNametitle of the song
artistNamename of the artist
collectionNamename of the album
artworkUrl100URL of the cover (100x100)
trackViewUrllink to the song on Apple Music
previewUrlURL of a 30 second preview, can be missing

data/sampleSongs.ts contains 5 songs of this type. SongCard receives one song, but for now it displays hardcoded text.

TODO 1a: display the real title.

<Text style={styles.title}>{song.trackName}</Text>

TODO 1b: do the same for the artist.

Hint

The field is in the table above. You can also type song. in the editor: it lists all the fields of the type.

TODO 1c: add the cover of the song on the left of the card, where the TODO 1c comment is. Use the Image component, already imported at the top of the file, with the cover style, which already exists at the bottom of the file.

astuce

A picture from the internet needs a size, otherwise it is not displayed. That's what the cover style is for.

Hint
<Image source={{ uri: song.artworkUrl100 }} style={styles.cover} />
  • source tells where the picture comes from: uri is its address on the internet, here the cover of the song
  • style={styles.cover} gives the picture its size

The double braces are not a typo. The first pair says that a value comes next, the second pair creates an object with one field, uri. In C, it would be close to passing a struct: (t_source){ .uri = song.artworkUrl100 }.

remarque

Expected result: 5 different cards. Each card has the cover on the left, the title in bold and the artist below.

astuce

If you make a typo in a field name, like song.trackname, the editor underlines it in red. That's TypeScript doing its job.

Step 2: call the API​

File: api/itunes.ts

We use the iTunes Search API. It is free and you don't need an API key. It is simply a URL that returns JSON. Try it in your browser:

https://itunes.apple.com/search?term=daft+punk&media=music&entity=song&country=fr&limit=3

Everything you need to know about this API is in the API reference at the end of this page.

Step 3: customize your app​

Files: components/SongCard.tsx and App.tsx, in the styles object at the bottom of each file.

Styles look like CSS, but they are written in an object. The names are in camelCase, the strings have quotes and the numbers have no unit.

card: {
backgroundColor: '#1c1c1e',
borderRadius: 12,
padding: 10,
},

Do at least 3 of these changes:

  • TODO 3: rename the app, at the top of App.tsx
  • change the background color of the screen or of the cards
  • make the covers round with borderRadius on cover (half of the width gives a circle)
  • change the size or the color of the title with fontSize and color
  • display the name of the album under the artist with song.collectionName

There is no expected result for this step. Do what you like, but keep it readable because you will show it at the end.

Step 4 (bonus): open the preview​

File: App.tsx

Each song can have a previewUrl, a 30 second extract of the song. When you tap a card, the app calls playPreview(song), but the function is empty.

TODO 4: open the preview of the song. Linking.openURL(address) asks the phone to open an address outside the app. Linking is already imported at the top of App.tsx.

astuce

previewUrl has a ? in the type: some songs don't have one. Check that it exists before you use it.

Hint
if (!song.previewUrl) {
return;
}
remarque

Expected result: you tap a card, your phone opens the extract and plays it. Press play if it doesn't start by itself.

If you still have time:

  • display the genre or the price: add the field to the Song type first (for example primaryGenreName: string; or trackPrice?: number;), then display it in SongCard. All the fields are listed in the API reference below.
  • search apps instead of songs: in the URL of api/itunes.ts, replace media=music&entity=song with media=software&entity=software. Apps have no preview and some fields are different, see the API reference.

Send us your app​

You don't need git for this. One link per group.

  1. Click Save at the top of Snack. If Snack asks you to log in, use the same Expo account as in Expo Go. The URL of the page changes, and this new URL is the link of your project.
  2. One person of the group fills in the form with this link and the names and contacts of everyone in the group.

It is not graded. We just want to see what you made.

Good to know​

info

Please keep the "Open in Apple Music" link on the cards and the text "Previews provided courtesy of iTunes" at the bottom of the screen. Apple asks for them when an app uses its covers and previews.

The API is only called when you press Search. This is on purpose, because of the limit of requests.

If something doesn't work​

  • The screen is red: it is a syntax error, usually a missing } or a missing quote. Ctrl + Z works.
  • Something is underlined in red: put your mouse on it to read the TypeScript error.
  • Expo Go asks you to log in: create a free Expo account, it is the same account for Snack.
  • The QR code doesn't open the app: update Expo Go, or check that your phone has internet.
  • You get "Network request failed": wait a little, or switch your phone to mobile data.
  • For anything else, ask us.

Documentation​

iTunes Search API reference​

The API is public: no account and no key. It has two endpoints, search and lookup, and both answer in JSON. Official documentation: performance-partners.apple.com/search-api

https://itunes.apple.com/search?parameter1=value1&parameter2=value2
  • term (required): the text to search, URL encoded (spaces become +)
  • country (recommended): two-letter country code, like fr, us or gb. Default: us
  • media: music, software, podcast, movie, musicVideo, audiobook, ebook, tvShow, shortFilm or all. Default: all
  • entity: the type of result, it depends on media. For music: song, album, musicArtist, musicVideo. For software: software, iPadSoftware, desktopSoftware
  • attribute: where to look for the term. For music: artistTerm, songTerm, albumTerm... Default: everywhere
  • limit: maximum number of results, from 1 to 200. Default: 50
  • lang: en_us or ja_jp. Default: en_us
  • explicit: Yes or No. Default: Yes

Examples:

  • Songs whose artist matches "daft punk", French store, 10 results: https://itunes.apple.com/search?term=daft+punk&media=music&entity=song&attribute=artistTerm&country=fr&limit=10
  • Albums: https://itunes.apple.com/search?term=daft+punk&media=music&entity=album&country=fr
  • Apps: https://itunes.apple.com/search?term=notes&media=software&country=fr&limit=5

Lookup​

Gets items from their ID instead of searching by text. The IDs come from a search result (trackId, artistId, collectionId).

  • One item: https://itunes.apple.com/lookup?id=909253
  • The albums of an artist: https://itunes.apple.com/lookup?id=909253&entity=album
  • Several items at once: put several IDs separated by commas.

With entity, the first element of results is the item you asked for (here the artist), and the related items come after it.

Response​

{
"resultCount": 1,
"results": [
{
"wrapperType": "track",
"kind": "song",
"trackId": 120954025,
"artistId": 909253,
"trackName": "Upside Down",
"artistName": "Jack Johnson",
"collectionName": "Sing-a-Longs and Lullabies for the Film Curious George",
"artworkUrl100": "https://...",
"previewUrl": "https://...",
"trackViewUrl": "https://...",
"trackTimeMillis": 210743,
"trackPrice": 0.99,
"currency": "USD",
"primaryGenreName": "Rock"
}
]
}

In TypeScript, the response looks like this:

type SearchResponse = {
resultCount: number;
results: Song[];
};

Main fields:

FieldContent
wrapperTypetrack, collection or artist
kindsong, music-video, podcast...
trackId, artistId, collectionIdIDs, to use with lookup
trackNametitle of the song (or name of the app)
artistNameartist (or developer of the app)
collectionNamealbum
artworkUrl60, artworkUrl100cover, 60x60 or 100x100 pixels
previewUrl30 second preview, only for tracks
trackViewUrlpage of the item on Apple Music or on the App Store
trackTimeMillisduration in milliseconds
trackPrice, collectionPrice, currencyprices
primaryGenreNamegenre
releaseDaterelease date, ISO format
trackExplicitnessexplicit, cleaned or notExplicit

Apps (media=software) have other fields, like formattedPrice, averageUserRating, description or artworkUrl512, and no previewUrl. Use console.log to see everything you get.

Limits and rules​

  • About 20 requests per minute, and Apple says this can change. Above the limit, the API refuses your requests for a while.
  • The whole room probably shares the same IP address, so don't spam the Search button. If the API stops answering, wait one minute.
  • Covers and previews can only be used to promote the content of Apple's stores: keep a link to the store next to them, say that previews are provided courtesy of iTunes, and play previews in streaming instead of downloading them.

Contact​

This workshop was made by Epimac. If you liked it, come and see us on our Linktree.