Formula 1 App with React Native

Let’s build the Formula 1 mobile app with React Native.

The tech stack:

  • React Native with Expo
  • Expo Router
  • Real data from a public API
  • GraphQL API using IBM StepZen

Asset Bundle

The Asset bundle contains all the required assets to help you follow along.

Download Asset Bundle

Initialize the Expo project

Let’s start by initializing a new React Native project using Expo.

BASH
npx create-expo-app@latest F1 -t

For the template, choose "Blank (Typescript)" to start with a clean project.

After the project is initialized, let’s open it up in our editor of choice.

Open a terminal, and start the development server with npm start

The next step is to run our app on a device. The easiest way is to download the Expo Go app (available both on Play Market and App Store), and then scan the QR you see in the terminal. That way, you can continue to develop the app and see the hot updates directly on your device.

Optionally, you can run the app on an iOS Simulator by pressing i or on Android Emulator by pressing a. But for this, you have to set up the emulators using Xcode and/or Android Studio.

F1 API

For this project, we will use the Api-Formula-1. They provide data about Formula 1 races.

To request data, we can use curl with the following syntax. The {endpoint} should be replaces with the actual endpoint we need to query.

BASH
curl --request GET \
--url 'https://api-formula-1.p.rapidapi.com/{endpoint}' \
--header 'x-rapidapi-host: api-formula-1.p.rapidapi.com' \
--header 'x-rapidapi-key: <YOUR_API_KEY>'

For example, to query the races in a season, we can send the following request:

BASH
curl --request GET \
--url 'https://v1.formula-1.api-sports.io/races?season=2023&type=Race' \
--header 'x-rapidapi-host: v1.formula-1.api-sports.io' \
--header 'x-rapidapi-key: <YOUR_API_KEY>'

Build a GraphQL API using IBM Stepzen

Let’s add a thin GraphQL layer on top of the API-Formula-1.

This will make it easier to query exactly the data that we need form the client side. It will also allow us to switch the data provider in future, without changing the internal API design.

With IBM Stepzen, creating a GraphQL API is as easy as running one command. We can also connect it with multiple datasources.

We will start by connecting it to the REST API provided by API-Formula-1. Later, we can also connect it to a database, and add custom functionalities to our app. For example, we can evolve this app into a Fantasy app where you can create your own F1 team.

Setup the StepZen CLI

  1. Let’s install Stepzen CLI using npm install -g stepzen.
  2. Sign up for a free StepZen account
  3. Login inside your terminal using stepzen login and provide the details from StepZen Dashboard

We are ready to create our GraphQL API.

Setup the StepZen project

Create a new folder inside our React Native project, and navigate there:

BASH
mkdir stepzen && cd stepzen

Import the first endpoint

Let’s use StepZen’s ✨import✨ to magically create our GraphQL endpoint.

Let’s remind ourself how we used curl to get data about races

BASH
curl --request GET \
--url 'https://v1.formula-1.api-sports.io/races?season=2023&type=Race' \
--header 'x-rapidapi-host: v1.formula-1.api-sports.io' \
--header 'x-rapidapi-key: <YOUR_API_KEY>'

Now, all we have to do, is add stepzen import in front of it, and a couple of extra headers to name this endpoint. In the end, we should get

BASH
stepzen import curl --request GET \
--url 'https://v1.formula-1.api-sports.io/races?season=2023&type=Race' \
--header 'x-rapidapi-host: v1.formula-1.api-sports.io' \
--header 'x-rapidapi-key: <YOUR_API_KEY>'\
--query-name "races" \
--query-type "Race" \
--name "races"

After executing this command, Stepzen will introspect the result from that request, and will automatically generate the graphql schema for our api.

All we have to do, is start the server with:

BASH
stepzen start

This will deploy your API to Stepzen, and it will be publicly accessible over the internet.

Open it up in Stepzen Dashboard and execute a query to see it in practice.

Race rankings query

While we are still here, we can also import our second endpoint to get the rankings for a specific race.

BASH
stepzen import curl --request GET \
--url 'https://v1.formula-1.api-sports.io/rankings/races?race=50' \
--header 'x-rapidapi-host: v1.formula-1.api-sports.io' \
--header 'x-rapidapi-key: <YOUR_API_KEY>' \
--query-name "raceRankings" \
--query-type "RaceRankings" \
--name "raceRankings" \
--prefix "rank"

Home screen: the list of races

On the home screen, we will render a list of races.

simulator_screenshot_C060C513-6BFD-45FB-BD7D-77EA17BBECC0.png

Expo Router

Now that we will need multiple screens, let’s go ahead and configure Expo Router as our navigation library.

In this part, you will learn:

  • Create screens
  • Navigate between screens
  • Customize the navigation UI elements
  • Add a custom navigator: Material Top Tabs

Add the race details screens

Simulator_Screenshot_-iPhone_15_Pro-_2023-11-10_at_14.44.43.png

Setup Apollo Client

To query the GraphQL API we will use Apollo Client. Let’s install it first:

BASH
npx expo install @apollo/client graphql

Create a new Provider (src/providers/ApolloClientProvider.tsx) and set up the Apollo client to connect to our StepZen API.

TYPESCRIPT
import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';
import { PropsWithChildren } from 'react';
const client = new ApolloClient({
uri: 'https://<ACCOUNT_NAME>.stepzen.net/api/<ENDPOINT_NAME>/__graphql',
headers: {
Authorization:
'apikey <YOUR_API_KEY>',
},
cache: new InMemoryCache(),
});
const ApolloClientProvider = ({ children }: PropsWithChildren) => {
return <ApolloProvider client={client}>{children}</ApolloProvider>;
};
export default ApolloClientProvider;

Make sure to import it inside src/app/_layout.tsx and wrap our <Stack> Navigator inside it.

TYPESCRIPT
return (
<ApolloClientProvider>
...
</ApolloClientProvider>
</>
);

Query the list of races

TYPESCRIPT
import { gql, useQuery } from '@apollo/client';
const query = gql`
query Races($season: String, $type: String) {
races(season: $season, type: $type) {
response {
id
date
competition {
name
}
}
}
}
`;
...
const { data, loading, error } = useQuery(query, {
variables: { season: '2023', type: 'RACE' },
});
if (loading) {
return <ActivityIndicator />;
}
if (error) {
return <Text>Failed to fetch Races. {error.message}</Text>;
}
console.log(data);

Congrats 🎉

That’s it. We have managed to build some important screen in our F1 App. I recommend you to continue working on this project, and adding more features. That’s the best way to learn.

I hope you had fun building this project and learned something new about React Native, GraphQL and IBM StepZen.


Vadim Savin profile picture

Vadim Savin

Hi 👋 Let me introduce myself

I started my career as a Fullstack Developer when I was 16 y.o.

In search of more freedom, I transitioned to freelancing, which quickly grew into a global software development agency 🔥

Because that was not challenging enough, I started my startup which is used by over 20k users. This experience gave another meaning to being a (notJust) developer 🚀

I am also a proud ex-Amazon SDE and Certified AWS Architect, Developer and SysOps. You are in good hands 👌