post image

Nike App Backend: node.js, MongoDB, Redux Toolkit Query

Last updated on: Jun 7, 2023

In this tutorial we will build a backend for an e-commerce application - Nike app.

The backend will be a REST API build with NodeJS and Express.

For the database, we will use MongoDB.

In the end, we will query our API from our React Native applicaiton using Redux Toolkit Query.

This guide is intended to be followed alongside the video tutorial

Get yourself a cup of coffee, and let’s start learning new stuff by building exciting projects.

Build a REST API with NodeJS

Functional requirements:


  • Get a list of products
  • Get one product


  • Create order
  • Get order by reference number

Non functional requirements

  • NodeJS backend with express
  • MongoDB for the database
  • Run the server locally

NodeJS server

Start by creating a new directory for our backend project, and then open it with VSCode.

Initialize an empty project

npm init -y

Install nodemon as a dev dependency. Nodemon will automatically restart our server when we do some changes.

npm i -D nodemon

Install express

npm i express

Finally, let’s create our index.js inside the src file, that will be the entry point of our backend.

const express = require('express');
const app = express();
const PORT = 3000;
app.get('/', (req, res) => {
res.send("<h2>Hello world!</h2>");
app.listen(PORT, () => {
console.log('API is listening on port ', PORT);

Add the dev script in package.json

"scripts": {
"dev": "nodemon src/index.js"

Run the server by executing the npm run dev command, and then visit http://localhost:3000/ to see our first page.

Products CRUD


Create the productRoutes.js file

const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.send('Get all products');
router.get('/:productId', (req, res) => {
res.send(`Get product with id: ${req.params.productId}`);
module.exports = router;

And then, connect the product router to the main application inside src/index.js

app.use('/products', productRoutes);


We will use MongoDB as our database.

Let’s create it on, which offers a free plan for hosting your database in the cloud.

  • Create an account and sign in

  • Create a Project

  • Create a database


  • Create a database user and whitelist your local ip address

  • Create the products collection, and populate the collection with the data from the asset bundle (code/data/products.json)

Connect to Mongodb from NodeJS

Install the mongodb driver

npm install mongodb@5.1

Connect to our mongodb database, from src/database/db.js

const { MongoClient } = require('mongodb');
const uri =
const client = new MongoClient(uri);
const database = client.db('test');
const products = database.collection('products');
module.exports = {

Add the database interaction logic inside src/database/products.js

const { ObjectId } = require('mongodb');
const db = require('./db');
const getAllProducts = async () => {
return await db.products.find().toArray();
const getProduct = async (id) => {
return await db.products.findOne({ _id: new ObjectId(id) });
module.exports = {

Let’s also update our productRoutes to use the database layer

const express = require('express');
const router = express.Router();
const { getAllProducts, getProduct } = require('../database/products');
router.get('/', async (req, res) => {
const products = await getAllProducts();
res.send({ status: 'OK', data: products });
router.get('/:productId', async (req, res) => {
const product = await getProduct(req.params.productId);
if (!product) {
res.status(404).send({ status: 'FAILED', error: 'Product not found' });
res.send({ status: 'OK', data: product });
module.exports = router;

Now, if you access the http://localhost:3000/products/ you should see a list of products coming from our database.

Orders CRUD

Let’s start by creating the router src/routes/orderRoutes.js

const express = require('express');
const router = express.Router();
router.get('/:reference', (req, res) => {
res.send(`Get order ${req.params.reference}`);
});'/', (req, res) => {
res.send('Creating an order');
module.exports = router;

And connect it with our main app in src/index.js

Orders database layer

Create and export the collection inside src/database/db.js

const orders = database.collection('orders');
module.exports = {

Write the logic for the orders database layer in src/database/orders.js

const db = require('./db');
const getOrder = async (ref) => {
return await db.orders.findOne({ ref });
const createOrder = async (order) => {
const result = await db.orders.insertOne(order);
return { ...order, _id: result.insertedId };
module.exports = {

Now, let’s call the database layer from our router:

Install the body-parser package that will parse the incoming data and transform it to json

npm i body-parser

Add it to our app inside src/index.js


Let’s send a post request using curl form our terminal. If you have an HTTP client like Postman, you can use it.

curl -X POST -H "Content-Type: application/json" \
-d "{\"items\":[{\"product\":{\"id\":\"1\",\"image\":\"\",\"name\":\"Wild Berry\",\"price\":160},\"size\":42,\"quantity\":2},{\"product\":{\"id\":\"2\",\"image\":\"\",\"name\":\"Air Force 1\",\"price\":169},\"size\":43,\"quantity\":1},{\"product\":{\"id\":\"3\",\"image\":\"\",\"name\":\"Nike Cosmic\",\"price\":129},\"size\":44,\"quantity\":1}],\"subtotal\":450,\"deliveryFee\":15,\"total\":465,\"customer\":{\"name\":\"Vadim Savi\",\"email\":\"\",\"address\":\"26985 Brighton Lane, Lake Forest, CA\"}}" \

Order routes

const express = require('express');
const router = express.Router();
const { createOrder, getOrder } = require('../database/orders');
router.get('/:reference', async (req, res) => {
const order = await getOrder(req.params.reference);
if (!order) {
res.status(404).send({ status: 'FAILED', error: 'Order not found' });
res.send({ status: 'OK', data: order });
});'/', async (req, res) => {
const orderData = req.body;
const ref = (Math.random() + 1).toString(36).substring(7);
orderData.ref = ref;
const newOrder = await createOrder(orderData);
res.status(201).send({ status: 'OK', data: newOrder });
module.exports = router;

Query the REST API from React Native

For this part, we will work with the application that we have build in the first part of the series Building the Ultimate Nike App in React Native & Redux.

The source code for the UI can be found here.

To query the data from our API inside React Native, we will use the RTK Query library from Redux Toolkit.

RTK Query is provided as an optional addon within the @reduxjs/toolkit package. It is purpose-built to solve the use case of data fetching and caching, supplying a compact, but powerful toolset to define an API interface layer for your app. It is intended to simplify common cases for loading data in a web application, eliminating the need to hand-write data fetching & caching logic yourself.

Create the API Slice

Let’s start by creating a new slice for the api inside src/store/apiSlice.js

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
const baseUrl = 'http://localhost:3000/';
// Define a service using a base URL and expected endpoints
export const apiSlice = createApi({
reducerPath: 'api',
baseQuery: fetchBaseQuery({ baseUrl }),
endpoints: (builder) => ({
getProducts: builder.query({
query: () => 'products',
getProduct: builder.query({
query: (id) => `products/${id}`,
// Export hooks for usage in functional components, which are
// auto-generated based on the defined endpoints
export const { useGetProductsQuery, useGetProductQuery } = apiSlice;

And add it to the main store inside src/store/index.js

import { configureStore } from '@reduxjs/toolkit';
import { productsSlice } from './productsSlice';
import { cartSlice } from './cartSlice';
import { apiSlice } from './apiSlice';
export const store = configureStore({
reducer: {
products: productsSlice.reducer,
cart: cartSlice.reducer,
api: apiSlice.reducer,
// Adding the api middleware enables caching, invalidation, polling,
// and other useful features of `rtk-query`.
middleware: (getDefaultMiddleware) =>

Use hooks inside components

Now, let’s use the auto-generated hook to query the products inside src/screens/ProductsScreen.js

const { data, error, isLoading } = useGetProductsQuery();
if (isLoading) {
return <ActivityIndicator />;
return (

Inside the src/screens/ProdictDetailsScreen.js we need to query the product

const { data, error, isLoading } = useGetProductQuery(;
if (isLoading) {
return <ActivityIndicator />;
if (error) {
return <Text>{error.error}</Text>;
const product =;

For this to work, we have to send the id of the product when we click on it inside ProductsScreen.js

onPress={() => {
// update selected product
// dispatch(productsSlice.actions.setSelectedProduct(;
navigation.navigate('Product Details', { id: item._id });

Orders API integration

Let’s add the orders endpoints to our apiSlice.js

createOrder: builder.mutation({
query: (newOrder) => ({
url: 'orders',
method: 'POST',
body: newOrder,
getOrder: builder.query({
query: (ref) => `orders/${ref}`,

And use the newOrder mutation inside the ShoppingCart.js

const onCreateOrder = async () => {
const result = await createOrder({
items: cartItems,
if ( === 'OK') {
'Order has been submitted',
`Your order reference is: ${}`

Add the clear cart reducer inside the cartSlice.js

clear: (state) => {
state.items = [];

Track orders

Let’s start by creating a blank screen screens/TrackOrder.js, and add it as a screen inside navigation.js

<Stack.Screen name="Track Order" component={TrackOrder} />

We will navigate to this page by pressing on an icon from the products page header

headerLeft: () => (
onPress={() => navigation.navigate('Track Order')}

Now, we can implement the Track order screen. We need to have a in input where we can type our order reference, and query the api to look for the order.

import {
} from 'react-native';
import { useState } from 'react';
import { useGetOrderQuery } from '../store/apiSlice';
const TrackOrder = () => {
const [ref, setRef] = useState('');
const { data, isLoading, error } = useGetOrderQuery(ref);
return (
<View style={styles.root}>
placeholder="Your order reference"
{isLoading && <ActivityIndicator />}
{data?.status !== 'OK' && <Text>Order not found</Text>}
{data?.status === 'OK' && <Text>Order: {JSON.stringify(}</Text>}
const styles = StyleSheet.create({
root: {
padding: 10,
input: {
borderColor: 'lightgrey',
borderWidth: 1,
padding: 10,
borderRadius: 5,
export default TrackOrder;


Congrats 🎉 

We have build a REST API and also integrated it inside our React Native applicaiton using Redux Toolkit Query.

I hope you learned something new today, and had fun following along.

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 👌

Read next

Income report - November 2021

Income report - November 2021

November has been a great month for us. Here is the detailed report of the revenue and expenses for

Read more
How I developed an App (from 0 to market) in a 12H Livestream

How I developed an App (from 0 to market) in a 12H Livestream

From the time I started doing youtube, I had this idea in mind to do a 12H Livestream and to build something. It was inspired by the extreme challenges of Mr. Beast's. However, I always procrastinated doing it because I was kinda scared (12 hours coding wi...

Read more