Fullstack Alibaba Clone with GraphQL, React, and React Native

Fullstack Alibaba Clone with GraphQL, React, and React Native

In this article, we will build a fullstack e-commerce application similar to Alibaba using modern technologies like GraphQL, React, and React Native. The app will have all the essential features of an online marketplace including products listings, categories, shopping cart, payments, and mobile applications.

Let's get started!

Setting Up the Backend with GraphQL

The backend will be built using GraphQL as our API layer. We'll use the Apollo Server framework to write our GraphQL server. Checkout: https://zipprr.com/alibaba-clone/

First, let's initialize a new Node.js project:

npm init

Next, install the dependencies:

npm installgraphqlapollo-server-expressmongoosebcryptjsonwebtoken

GraphQL Schema Design

For the data model, we'll define the main types in our schema - Product, Category, User etc.

type Query {
  products: [Product]
  categories: [Category]
  user: User
}

type Product {
  id: ID!
  name: String!
  price: Float! 
  description: String
  image: String
  category: Category
}

type Category {
  id: ID!
  name: String!
  products: [Product]
}

type User {
  id: ID!  
  email: String!
  name: String
  purchases: [Order]
}

Resolvers

Next, we define resolvers to fetch data from the MongoDB database:

// product.js
const Product = mongoose.model('Product');

export default {
  products: () => Product.find({}),

  product: (_, {id}) => Product.findById(id) 
}

Authentication

For authentication, we'll use JSON Web Tokens (JWT) stored in cookies.

// auth.js
import jwt from 'jsonwebtoken';

export const authenticate = async (_, {email, password}) => {

  const user = await User.findOne({email});

  if(!user || !bcrypt.compareSync(password, user.password)) {
    throw new Error('Invalid credentials'); 
  }

  return {
    token: jwt.sign({userId: user.id}, process.env.JWT_SECRET) 
  };
}

GraphiQL Testing

We can now test our API using GraphiQL. Start the server:

node index.js

Make queries on http://localhost:4000/graphql:

{
  products {
    name
    price
  }
}

This completes the backend setup with GraphQL!

Building the Web App with React

Now let's build the frontend React app that will consume the GraphQL API.

Project Setup

npm init react-app client
cd client

Apollo Client

Install Apollo Client to connect React to our GraphQL backend:

npm install @apollo/client graphql

setup Apollo Client:

import {ApolloClient, InMemoryCache} from '@apollo/client';

const client = new ApolloClient({
  uri: 'http://localhost:4000/graphql',
  cache: new InMemoryCache()
});

Components

We'll create core components like ProductList, ProductDetails, Cart, etc.

ProductList.js:

import { useQuery } from '@apollo/client';
import gql from 'graphql-tag';

const PRODUCTS_QUERY = gql`
  query ProductsQuery {
    products {
      name
      price
      image
    }
  }
`

export default function ProductList() {

  const { loading, error, data } = useQuery(PRODUCTS_QUERY);

  if(loading) return <p>Loading...</p>
  if(error) return <p>Error!</p>

  return (
    <div>
      {data.products.map(product => (
        <ProductItem 
          key={product.id}
          product={product} 
        />
      ))}
    </div>
  )
}

Authentication

For authentication, we use the API endpoint defined earlier:

const SIGNIN_MUTATION = gql`
  mutation SignInMutation($email: String!, $password: String!) {
    authenticate(email: $email, password: $password) {
      token
    }
  }
`

function SignIn() {

  const [signIn] = useMutation(SIGNIN_MUTATION);

  const onSubmit = async (data) => {
    const response = await signIn({
      variables: {
        email: data.email,
        password: data.password  
      }
    });

    localStorage.setItem('token', response.data.authenticate.token);
  }

  //..
}

Routing

Add route protection and navigation with React Router:

import { BrowserRouter, Routes, Route } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<HomePage />} />

        <Route path="/products" element={
          <RequireAuth>
            <ProductList />
          </RequireAuth>
        }/>

        <Route path="/account" element={
          <RequireAuth>
            <AccountPage />  
          </RequireAuth>
        }/>
      </Routes>
    </BrowserRouter>
  )
}

This completes the frontend web app built with React!

Mobile App with React Native

React Native Setup

To build the mobile apps, we'll use React Native:

npx react-native init Mobile

GraphQL Connection

Setup Apollo Client same as web:

import { ApolloClient, InMemoryCache } from '@apollo/client';

const client = new ApolloClient({
  uri: 'http://192.168.1.100:4000/graphql',
  cache: new InMemoryCache()
});

Components

Create reusable cross-platform components:

import { View, Text, Image } from 'react-native';

export default function ProductItem({product}) {
  return (
    <View>
      <Image source={{uri: product.image}} />
      <Text>{product.name}</Text>
      <Text>${product.price}</Text>
    </View>
  )
}

Authentication

Sign In/Up screens with mutations:

function SignInScreen() {

  const [signIn] = useMutation(SIGNIN_MUTATION);

  const onSubmit = async ({email, password}) => {
    try {
      const {data} = await signIn({variables: {...}});

      setToken(data.authenticate.token);
      Navigation.replace('Home');
    } catch (err) {
      alert('Invalid credentials!');
    }
  }

  //..
}

Navigation

Add react-navigation for app routing:

import { createStackNavigator } from '@react-navigation/stack';

const Stack = createStackNavigator();

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen 
          name="Home" 
          component={HomeScreen} />

        <Stack.Screen 
          name="Products"
          component={ProductListScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  )
}

This completes the mobile app development with React Native!

Hosting and Deployment

Deploying GraphQL Server

We can deploy the GraphQL server to Heroku :

heroku create
git push heroku main

Add environment variables:

heroku config:set JWT_SECRET=secret

React Web App

Build and deploy the React frontend to GitHub Pages:

npm run build

# in client directory
npm install gh-pages --save-dev

# edit package.json
"homepage": "https://USER.github.io/client",
"scripts": {
  "predeploy": "npm run build",
  "deploy": "gh-pages -d build"
} 

npm run deploy

React Native Apps

We can deploy the mobile builds to App Stores after testing:

For iOS, generate a signed archive and submit to App Store Connect.

For Android, create a signed release bundle and upload to Google Play Console.

Data Modeling with GraphQL

GraphQL's data modeling is more flexible compared to REST. Some advantages:

Schema as API

The GraphQL schema defines the full API surface area upfront. It clearly shows what can be queried or mutated without making requests.

We can request nested and related data in a single query. For example, fetching a product with its category details:

{
  product(id: "123") {
    name
    category {
      name
    } 
  }
}

Input Objects for Mutations

GraphQL uses input objects to define payloads for mutations. This avoids ambiguity and makes requests self-descriptive.

For example, the checkout mutation:

input CheckoutInput {
  shippingAddress 
  paymentDetails
  items: [ID!]
}

mutation Checkout($input: CheckoutInput!) {
  checkout(input: $input) {
    order {
      id
    }
  }
}

Flexible Queries

Clients can request only the exact fields required via queries, avoiding over-fetching of data.

Authentication and Authorization

We implemented JWT token based authentication for our API. Here are some additional best practices:

Authorization with Permissions

We can define permissions levels in GraphQL like ADMIN, USER. Check these on resolvers:

export default {
  mutateProduct: async (_, args, {user}) => {
    if(!user.isAdmin) throw Error('Not authorized')

    // mutate
  }
}

Social Login

Add OAuth via social providers like Google/Facebook. Exchange OAuth tokens for JWT on backend.

export const socialLogin = async ({oauthToken, provider}) => {

  // Find/create user from oauth info

  return {token: signJwt(user)}
}

rateLimiting & blacklisting

Protect against brute force attacks by rate limiting requests and blacklisting IPs after failures.

HTTPS and Helmet

Always serve GraphQL over HTTPS. Use Helmet to set security headers.

This improves security of the authentication pipeline.

Payments Integration

For payments, we integrated with Stripe payment gateway:

Server:

  1. Install stripe pkg:
npm i stripe
  1. Define Stripe secret key:
const stripe = Stripe(process.env.STRIPE_SECRET_KEY);
  1. Charge credit card on checkout mutation:
constCharge = await stripe.charges.create({
  amount, 
  currency,
  source: token  
});

// Save order

Client:

  1. Show Stripe elements on checkout page:
<StripeCardElement />
  1. Tokenize card on submit:
const {token} = await stripe.createToken({card});
  1. Pass token to server on mutation

We can also store payment methods and implement subscription payments.

Testing the Applications

Unit Testing

Write unit tests for React components using React Testing Library:

test('renders product data', () => {

  const {getByText} = render(<ProductItem product={product}/>);

  expect(getByText(product.name)).toBeInTheDocument();
})

Integration Testing

Test GraphQL resolvers and schemas:

test('gets a product by ID', async() => {

  const product = await Product.get(id); 

  expect(product.name).toEqual('Product 1');
});

E2E Testing

Use Cypress for E2E flows like signup, purchase etc:

it('allows user to purchase a product', () => {

  cy.visit('/products/1');
  cy.contains('Add to Cart').click();

  // Assertions
})

Growth and Maintenance

For continued growth:

  • Implement search and recommendations

  • Add admin dashboard

  • Marketplace seller subscriptions

  • Internationalization

  • Performance monitoring and caching

  • Email marketing and promotions

Follow best practices like code reviews, monitoring, logging and updating dependencies.

Conclusion

In this article, we built a fullstack e-commerce application similar to Alibaba using GraphQL, React and React Native. Key technologies used were - GraphQL, React, React Native, Apollo, MongoDB, Stripe etc. This demonstrated an end to end workflow for building production-ready fullstack applications.