Dylan  Iqbal

Dylan Iqbal

1565885661

Build a Simple CRUD App with Python, Flask, and React

In this tutorial you are going to build a JavaScript application using React in the front-end and we are also going to build a ReST API written in Python which is going to persist.

Today’s modern web applications are often built with a server-side language serving data via an API and a front-end javascript framework that presents the data in an easy to use manner to the end user. Python is a dynamic language widely adopted by companies and developers. The language states on its core values that software should simple, readable making developers more productive and happier. You’ll also use Flask to help you to quickly put together a ReST API. React is a declarative, efficient, and flexible JavaScript library developed at Facebook for building user interfaces. It facilitates the creation of complex, interactive, and stateful UIs from small and isolated pieces of code called components.

To complete this tutorial, there are few things you will need:

You will start by creating the back-end.

Create a ReST API with Python

Make sure you have Python 3 installed. Check the version of Python installed by running the following command:

python --version

To install Python 3 you can use pyenv.

If you are using macOS, you can install it using Homebrew:

brew update
brew install pyenv

On a Linux system using the bash shell:

curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash

Once installed, you can run the following commands to install Python 3.

pyenv install 3.6.3
pyenv global 3.6.3

Your ReST API will use some third-party code (libraries) to help you (e.g. to connect to a database, to create schemas for your models, and validate whether the incoming requests are authenticated or not). Python has a powerful tool to manage dependencies called pipenv. To install pipenv on your machine follow these steps:

On macOS:

brew install pipenv
pip install --user pipenv

With pipenv installed, create a directory for your backend code:

mkdir kudos_oss && cd kudos_oss

The command below will create a Python 3 virtual environment and install Flask:

pipenv install flask==1.0.2

Python 3 provides some cool features like absolute_import and print_function that you will use in this tutorial. To import them run the following commands:

touch __init__.py
touch __main__.py

And copy and paste the following content into the __main__.py file:

from __future__ import absolute_import, print_function

Your backend will need to implement the following user stories:

  • As an authenticated user I want to favorite an github open source project
  • As an authenticated user I want to unfavorite an github open source project
  • As an authenticated user I want to list all bookmarked github open source projects I’ve previously favorited

A normal ReST API will expose endpoints so clients can create, update, delete, read and list all resources. By end of this section your back-end application will be capable to handle the following HTTP calls:

# For the authenticated user, fetches all favorited github open source projects
GET /kudos

# Favorite a github open source project for the authenticated user
POST /kudos

# Unfavorite a favorited github open source project
DELETE /kudos/:id

Define the Python Model Schemas

Your ReST API will have two core schemas, they are GithubRepoSchema and KudoSchema. GithubRepoSchema will represent a Github repository sent by the clients whereas KudoSchema will represent the data you are going to persist in the database.

Go ahead and run the following commands:

mkdir -p app/kudo
touch app/kudo/schema.py
touch app/kudo/service.py
touch app/kudo/__init__.py


The above commands will create the app directory with another directory within it called kudo then, the second command will create three files: schema.py, service.py, and init.py.

Copy and paste the content below within the schema.py file.

from marshmallow import Schema, fields

class GithubRepoSchema(Schema):
  id = fields.Int(required=True)
  repo_name = fields.Str()
  full_name = fields.Str()
  language = fields.Str()
  description = fields.Str()
  repo_url = fields.URL()

class KudoSchema(GithubRepoSchema):
  user_id = fields.Email(required=True)


As you may have noticed, the schemas are inheriting from Schema a package from the [marshmallow library] (https://marshmallow.readthedocs.io/en/3.0/), marshmallow is an ORM/ODM/framework-agnostic library for serializing/deserializing complex data types, such as objects, to and from native Python data types.

Install the marshmallow library running the following commands:

pipenv install marshmallow==2.16.3


Python ReST API Persistence with MongoDB

Great! You have now your first files in place. The schemas were created to represent the incoming request data as well as the data your application persists in the MongoDB. In order to connect and to execute queries against the database, you are going to use a library created and maintained by MongoDB itself called pymongo.

Install the pymongo library running the following commands:

pipenv install pymongo==3.7.2


You can either use MongoDB installed on your machine or you can use docker to spin up a MongoDB container. This tutorial assumes you have Docker and docker-compose installed.

docker-compose will manage the MongoDB container for you.

Create docker-compose.yml

touch docker-compose.yml


Paste the following content into it:

version: '3'
services:
  mongo:
    image: mongo
    restart: always
    ports:
     - "27017:27017"
    environment:
      MONGO_INITDB_ROOT_USERNAME: mongo_user
      MONGO_INITDB_ROOT_PASSWORD: mongo_secret


All you have to do now to spin up a MongoDB container is:

docker-compose up


With MongoDB up and running you are ready to work the MongoRepository class, it is always a good idea to have class with just a single responsibility, so the only point in your back-end application MongoDB is going to be explicitly dealt with is in the MongoRepository.

Start by creating a directory where all persistence related files should sit, a suggestion would be: repository.

mkdir -p app/repository


Then, create the file that will hold the MongoRepository class:

touch app/repository/mongo.py
touch app/repository/__init__.py


With pymongo properly installed and MongoDB up and running, paste the following content into the app/repository/mongo.py file.

import os
from pymongo import MongoClient

COLLECTION_NAME = 'kudos'

class MongoRepository(object):
 def __init__(self):
   mongo_url = os.environ.get('MONGO_URL')
   self.db = MongoClient(mongo_url).kudos

 def find_all(self, selector):
   return self.db.kudos.find(selector)

 def find(self, selector):
   return self.db.kudos.find_one(selector)

 def create(self, kudo):
   return self.db.kudos.insert_one(kudo)

 def update(self, selector, kudo):
   return self.db.kudos.replace_one(selector, kudo).modified_count

 def delete(self, selector):
   return self.db.kudos.delete_one(selector).deleted_count


As you can see the MongoRepository class is straightforward, it creates a database connection on its initialization then saves it to a instance variable to be use later by the methods: find_all, find, create, update, and delete. Notice that all methods explicitly use the pymongo API.

You might have noticed that the MongoRepository class reads a environment variable MONGO_URL . To export the environment variable, run:

export MONGO_URL=mongodb://mongo_user:mongo_secret@0.0.0.0:27017/


Since you might want to use other database in the future, it is a good idea to decouple your application from MongoDB. For the sake of simplicity you are going to create an abstract class to represent a Repository, this class should be the one used throughout your application.

Paste the following content into the app/repository/init.py file:

class Repository(object):
 def __init__(self, adapter=None):
   self.client = adapter()

 def find_all(self, selector):
   return self.client.find_all(selector)

 def find(self, selector):
   return self.client.find(selector)

 def create(self, kudo):
   return self.client.create(kudo)

 def update(self, selector, kudo):
   return self.client.update(selector, kudo)

 def delete(self, selector):
   return self.client.delete(selector)


You might recall the user story that you’re working on is that ann authenticated user should able to create, delete and list all favorited Github open-source projects. In order to get that done those MongoRepository’s methods will come handy.

You will soon implement the endpoints of your ReST API. First, you need to create a service class that knows how to translate the incoming request payload to our representation KudoSchema defined in the app/kudo/schema.py. The difference between the incoming request payload, represented by GithubSchema, and the object you persist in the database, represented by KudoSchema is: The first has an user_Id which determines who owns the object.

Copy the content below to the app/kudo/service.py file:

from ..repository import Repository
from ..repository.mongo import MongoRepository
from .schema import KudoSchema

class Service(object):
 def __init__(self, user_id, repo_client=Repository(adapter=MongoRepository)):
   self.repo_client = repo_client
   self.user_id = user_id

   if not user_id:
     raise Exception("user id not provided")

 def find_all_kudos(self):
   kudos  = self.repo_client.find_all({'user_id': self.user_id})
   return [self.dump(kudo) for kudo in kudos]

 def find_kudo(self, repo_id):
   kudo = self.repo_client.find({'user_id': self.user_id, 'repo_id': repo_id})
   return self.dump(kudo)

 def create_kudo_for(self, githubRepo):
   self.repo_client.create(self.prepare_kudo(githubRepo))
   return self.dump(githubRepo.data)

 def update_kudo_with(self, repo_id, githubRepo):
   records_affected = self.repo_client.update({'user_id': self.user_id, 'repo_id': repo_id}, self.prepare_kudo(githubRepo))
   return records_affected > 0

 def delete_kudo_for(self, repo_id):
   records_affected = self.repo_client.delete({'user_id': self.user_id, 'repo_id': repo_id})
   return records_affected > 0

 def dump(self, data):
   return KudoSchema(exclude=['_id']).dump(data).data

 def prepare_kudo(self, githubRepo):
   data = githubRepo.data
   data['user_id'] = self.user_id
   return data


Notice that your constructor init receives as parameters the user_id and the repo_client which are used in all operations in this service. That’s the beauty of having a class to represent a repository, As far as the service is concerned, it does not care if the repo_client is persisting the data in a MongoDB, PostgreSQL, or sending the data over the network to a third party service API, all it needs to know is the repo_client is a Repository instance that was configured with an adapter that implements methods like create, delete and find_all.

Define Your ReST API Middleware

At this point, you’ve covered 70% of the backend. You are ready to implement the HTTP endpoints and the JWT middleware which will secure your ReST API against unauthenticated requests.

You can start by creating a directory where HTTP related files should be placed.

mkdir -p app/http/api


Within this directory, you will have two files, endpoints.py and middlewares.py. To create them run the following commands:

touch app/http/api/__init__.py
touch app/http/api/endpoints.py
touch app/http/api/middlewares.py


The requests made to your ReST API are JWT-authenticated, which means you need to make sure that every single request carries a valid json web token. pyjwt will take care of the validation for us. To install it run the following command:

pipenv install pyjwt==1.7.1


Now that you understand the role of the JWT middleware, you need to write it. Paste the following content to the middlewares.py file.

from functools import wraps
from flask import request, g, abort
from jwt import decode, exceptions
import json

def login_required(f):
   @wraps(f)
   def wrap(*args, **kwargs):
       authorization = request.headers.get("authorization", None)
       if not authorization:
           return json.dumps({'error': 'no authorization token provied'}), 403, {'Content-type': 'application/json'}

       try:
           token = authorization.split(' ')[1]
           resp = decode(token, None, verify=False, algorithms=['HS256'])
           g.user = resp['sub']
       except exceptions.DecodeError as identifier:
           return json.dumps({'error': 'invalid authorization token'}), 403, {'Content-type': 'application/json'}

       return f(*args, **kwargs)

   return wrap


Flask provide a module called g which is a global context shared across the request life cycle. This middleware is checking whether or not the request is valid, if so, the middleware will extract the authenticated user details and persist them in the global context.

Define Your ReST API Endpoints

The HTTP handlers should be easy now, since you have already done the important pieces, it’s just a matter of putting everything together.

Since your end goal is to create a JavaScript application that will run on web browsers, you need to make sure that web browsers are happy when a preflight is performed, you can learn more about it here. In order to implement CORS our your ReST API, you are going to install flask_cors.

pipenv install flask_cors==3.0.7


Next, implement your endpoints. Go ahead and paste the content above into the app/http/api/endpoints.py file.

from .middlewares import login_required
from flask import Flask, json, g, request
from app.kudo.service import Service as Kudo
from app.kudo.schema import GithubRepoSchema
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/kudos", methods=["GET"])
@login_required
def index():
 return json_response(Kudo(g.user).find_all_kudos())

@app.route("/kudos", methods=["POST"])
@login_required
def create():
   github_repo = GithubRepoSchema().load(json.loads(request.data))

   if github_repo.errors:
     return json_response({'error': github_repo.errors}, 422)

   kudo = Kudo(g.user).create_kudo_for(github_repo)
   return json_response(kudo)

@app.route("/kudo/<int:repo_id>", methods=["GET"])
@login_required
def show(repo_id):
 kudo = Kudo(g.user).find_kudo(repo_id)

 if kudo:
   return json_response(kudo)
 else:
   return json_response({'error': 'kudo not found'}, 404)

@app.route("/kudo/<int:repo_id>", methods=["PUT"])
@login_required
def update(repo_id):
   github_repo = GithubRepoSchema().load(json.loads(request.data))

   if github_repo.errors:
     return json_response({'error': github_repo.errors}, 422)

   kudo_service = Kudo(g.user)
   if kudo_service.update_kudo_with(repo_id, github_repo):
     return json_response(github_repo.data)
   else:
     return json_response({'error': 'kudo not found'}, 404)

@app.route("/kudo/<int:repo_id>", methods=["DELETE"])
@login_required
def delete(repo_id):
 kudo_service = Kudo(g.user)
 if kudo_service.delete_kudo_for(repo_id):
   return json_response({})
 else:
   return json_response({'error': 'kudo not found'}, 404)

def json_response(payload, status=200):
 return (json.dumps(payload), status, {'content-type': 'application/json'})


Brilliant! It’s all in place now! You should be able to run your ReST API with the command below:

FLASK_APP=$PWD/app/http/api/endpoints.py FLASK_ENV=development pipenv run python -m flask run --port 4433


Create the React Client-Side App

To create your React Client-Side App, you will use Facebook’s awesome create-react-app tool to bypass all the webpack hassle.

Installing create-react-app is simple. In this tutorial you will use yarn. Make sure you either have it installed or use the dependency manager of your preference.

To install create-react-app, run the command:

yarn global add create-react-app


You will need a directory to place your React application, go ahead and create the web directory within the pkg/http folder.

mkdir -p app/http/web


Now, create a React application:

cd app/http/web
create-react-app app


create-react-app might take a few minutes to generate the boilerplate application. Go to the recently created app directory and run npm start

By default, the React app generated by create-react-app will run listening on port 3000. Let’s change it to listen to the port 8080.

Change the start command on the file app/http/web/app/package.json to use the correct port.

Then, run the React app.

cd app
npm start


Running npm start will start a web server listening to the port 8080. Open http://localhost:8080/ in your browser. Your browser should load React and render the App.js component created automatically by create-react-app.

Your goal now is to use Material Design to create a simple and beautiful UI. Thankfully, the React community has created https://material-ui.com/ which basically are the Material Design concepts translated to React components.

Run the following commands to install what you will need from Material Design.

yarn add @material-ui/core
yarn add @material-ui/icons


Great, now you have components like: Grid, Card, Icon, AppBar and many more ready to be imported and used. You will use them soon. Let’s talk about protected routes.

Add Authentication to Your React App with Okta

Writing secure user authentication and building login pages are easy to get wrong and can be the downfall of a new project. Okta makes it simple to implement all the user management functionality quickly and securely. Get started by signing up for a free developer account and creating an OpenID Connect application in Okta.

Once logged in, create a new application by clicking Add Application.

Select the Single-Page App platform option.

The default application settings should be the same as those pictured.

Great! With your OIDC application in place, you can now move forward and secure the routes that requires authentication.

Create Your React Routes

React Router is the most used library for routing URLs to React components. React Router has a collection a components that can be used to help the user to navigate in you application.

Your React application will have two routes:

/ The root route does not require the user to be logged in, it actually is the landing page of your application. A user should be able to access this page in order to log in. You will use the Okta React SDK to integrate react-router with Okta’s OpenID Connect API.

/home The Home route will render most of the React components you application will have. It should implement the following user stories.

An authenticated user should be able to search through the Github API the open source projects of his/her preferences An authenticated user should be able to bookmark open source projects that pleases him/her An authenticated user should be able to see in different tabs his/her previously bookmarked open source projects and the search results

To install react-router run the command:

yarn add react-router-dom


And to install the Okta React SDK run the command:

yarn add @okta/okta-react


Now, go head and create your Main component.

mkdir  -p src/Main


Then, within the Main directory create a file named index.js.

touch src/Main/index.js


And paste the following content into the recently created file:

import React, { Component } from 'react';
import { Switch, Route, BrowserRouter as Router } from 'react-router-dom'
import { Security, ImplicitCallback, SecureRoute } from '@okta/okta-react';

import Login from '../Login'
import Home from '../Home'

class Main extends Component {
 render() {
   return (
     <Router>
       <Security
         issuer={yourOktaDomain}
         client_id={yourClientId}
         redirect_uri={'http://localhost:8080/implicit/callback'}
         scope={['openid', 'profile', 'email']}>

         <Switch>
           <Route exact path="/" component={Login} />
           <Route path="/implicit/callback" component={ImplicitCallback} />
           <SecureRoute path="/home" component={Home} />
         </Switch>
       </Security>
     </Router>
   );
 }
}

export default Main;


Don’t worry for now about the Home and Login components. You will work on them soon. Focus on the Security, SecureRoute, and ImplicitCallback components.

For routes to work properly in React, you need to wrap your whole application in a router. Similarly, to allow access to authentication anywhere in the app, you need to wrap the app in a Security component provided by Okta. Okta also needs access to the router, so the Security component should be nested inside the router.

For routes that require authentication, you will define them using the SecureRoute Okta component. If an unauthenticated user tries to access /home, he/she will be redirect to the / root route.

The ImplicitCallback component is the route/URI destination to which the user will be redirected after Okta finishes the sign in process.

Go ahead and change the src/index.js to mount your Main component.

import React from 'react';
import ReactDOM from 'react-dom';
import { Router } from 'react-router-dom'
import { createBrowserHistory } from 'history'

import Main from './Main';

const history = createBrowserHistory();

ReactDOM.render((
  <Router history={history}>
    <Main history={history} />
  </Router>
), document.getElementById('root'))


Your are now ready to create the Login component. As mentioned previously, this component will be accessible to all users (not only authenticated users). The main goal of the Login component is to authenticate the user.

Inside the directory app, you will find a directory called src which stands for source. Go ahead and create a directory named Login.

mkdir  -p src/Login


Then, within the Login directory create a file named index.js.

touch src/Login/index.js


And paste the following content into the file:

import React from 'react'
import Button from '@material-ui/core/Button';
import { Redirect } from 'react-router-dom'
import { withAuth } from '@okta/okta-react';

class Login extends React.Component {
 constructor(props) {
   super(props);
   this.state = { authenticated: null };
   this.checkAuthentication = this.checkAuthentication.bind(this);
   this.login = this.login.bind(this);
 }

 async checkAuthentication() {
   const authenticated = await this.props.auth.isAuthenticated();
   if (authenticated !== this.state.authenticated) {
     this.setState({ authenticated });
   }
 }

 async componentDidMount() {
   this.checkAuthentication()
 }

 async login(e) {
   this.props.auth.login('/home');
 }

 render() {
   if (this.state.authenticated) {
     return <Redirect to='/home' />
   } else {
     return (
       <div style={{height: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center'}}>
         <Button variant="contained" color="primary" onClick={this.login}>Login with Okta</Button>
       </div>
     )
   }
 }
}

export default withAuth(Login);


In order to see the Login page working, you need to create a placeholder for the Home component.

Go ahead and create a directory called Home.

mkdir -p src/Home


Then, within that directory, create a file named index.js.

touch src/Home/index.js


And paste the following content into it:

import React from 'react'

const home = (props) => {
  return (
    <div>Home</div>
  )
};

export default home;


Now try running npm start and open http://localhost:8080 in your browser. You should see the page below.

In the Login component you are using the Okta React SDK to check whether the user has signed in… If the user has already signed in, they should be redirected to the /home route, otherwise he/she could click Login With Okta to be redirected to Okta, authenticate and be sent to the the home page.

For now, the home page is blank, but eventually here’s what you’ll want the home page to look like:

The Home component is composed of Material Design components like: Tab, AppBar, Button, and Icon as well as a few custom components you will have to create.

For your app, you need to list all the bookmarked open source projects as well as the search results. As you can see in the image above, the Home component is using a tabs to separate bookmarked open source projects from search results, the first tab is listing all the open source projects bookmarked by the user whereas the second tab will list the search results.

You can create a component to represent an open source project in both “Kudos” and “Search Results” lists, that’s the beauty of React components they are highly flexible and reusable.

Go ahead and create a directory called GithubRepo

mkdir -p src/GithubRepo


Then, within that directory, create a file named index.js

touch src/GithubRepo/index.js


And paste the following content into it:

import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Card from '@material-ui/core/Card';
import CardHeader from '@material-ui/core/CardHeader';
import CardContent from '@material-ui/core/CardContent';
import CardActions from '@material-ui/core/CardActions';
import IconButton from '@material-ui/core/IconButton';
import Typography from '@material-ui/core/Typography';
import FavoriteIcon from '@material-ui/icons/Favorite';

const styles = theme => ({
  card: {
    maxWidth: 400,
  },
  media: {
    height: 0,
    paddingTop: '56.25%', // 16:9
  },
  actions: {
    display: 'flex',
  }
});

class GithubRepo extends React.Component {
  handleClick = (event) =>  {
    this.props.onKudo(this.props.repo)
  }

  render() {
    const { classes } = this.props;

    return (
      <Card className={classes.card}>
        <CardHeader
          title={this.props.repo.full_name}
        />
        <CardContent>
          <Typography component="p" style={{minHeight: '90px', overflow: 'scroll'}}>
            {this.props.repo.description}
          </Typography>
        </CardContent>
        <CardActions className={classes.actions} disableActionSpacing>
          <IconButton aria-label="Add to favorites" onClick={this.handleClick}>
            <FavoriteIcon color={this.props.isKudo ? "secondary" : "primary"} />
          </IconButton>
        </CardActions>
      </Card>
    );
  }
}

export default withStyles(styles)(GithubRepo);


The GithubRepo is a quite simple component, it receives two props: A repo object which holds a reference to a Github repository and an isKudo boolean flag that indicates whether the repo has been bookmarked or not.

The next component you will need is the SearchBar. It will have two responsibilities: log the user out and call React on every press of the Enter key in the search text field.

Create a directory called SearchBar

mkdir -p src/SearchBar


Then, within the directory, create a file named index.js

touch src/SearchBar/index.js


Paste the following content:

import React from 'react';
import PropTypes from 'prop-types';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import InputBase from '@material-ui/core/InputBase';
import Button from '@material-ui/core/Button';
import { fade } from '@material-ui/core/styles/colorManipulator';
import { withStyles } from '@material-ui/core/styles';
import SearchIcon from '@material-ui/icons/Search';
import { withAuth } from '@okta/okta-react';

const styles = theme => ({
  root: {
    width: '100%',
  },
  MuiAppBar: {
    alignItems: 'center'
  },
  grow: {
    flexGrow: 1,
  },
  title: {
    display: 'none',
    [theme.breakpoints.up('sm')]: {
      display: 'block',
    },
  },
  search: {
    position: 'relative',
    borderRadius: theme.shape.borderRadius,
    backgroundColor: fade(theme.palette.common.white, 0.15),
    '&:hover': {
      backgroundColor: fade(theme.palette.common.white, 0.25),
    },
    marginRight: theme.spacing.unit * 2,
    marginLeft: 0,
    width: '100%',
    [theme.breakpoints.up('sm')]: {
      marginLeft: theme.spacing.unit * 3,
      width: 'auto',
    },
  },
  searchIcon: {
    width: theme.spacing.unit * 9,
    height: '100%',
    position: 'absolute',
    pointerEvents: 'none',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
  },
  inputRoot: {
    color: 'inherit',
    width: '100%',
  },
  inputInput: {
    paddingTop: theme.spacing.unit,
    paddingRight: theme.spacing.unit,
    paddingBottom: theme.spacing.unit,
    paddingLeft: theme.spacing.unit * 10,
    transition: theme.transitions.create('width'),
    width: '100%',
    [theme.breakpoints.up('md')]: {
      width: 400,
    },
  },
  toolbar: {
    alignItems: 'center'
  }
});

class SearchBar extends React.Component {
  constructor(props) {
    super(props);
    this.logout = this.logout.bind(this);
  }

  async logout(e) {
    e.preventDefault();
    this.props.auth.logout('/');
  }

  render() {
    const { classes } = this.props;

    return (
      <div className={classes.root}>
        <AppBar position="static" style={{alignItems: 'center'}}>
          <Toolbar>
            <div className={classes.search}>
              <div className={classes.searchIcon}>
                <SearchIcon />
              </div>
              <InputBase
                placeholder="Search for your OOS project on Github + Press Enter"
                onKeyPress={this.props.onSearch}
                classes={{
                  root: classes.inputRoot,
                  input: classes.inputInput,
                }}
              />
            </div>
            <div className={classes.grow} />
            <Button onClick={this.logout} color="inherit">Logout</Button>
          </Toolbar>
        </AppBar>
      </div>
    );
  }
}

SearchBar.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styles)(withAuth(SearchBar));


The SearchBar component receives one prop called onSearch which is the function that should be called in each keyPress event triggered in the search text input.

The SearchBar uses the withAuth helper provided by Okta React SDK which will inject the auth object in the props of the component. The auth object has a method called logout that will wipe out all user related data from the session. This is exactly what you want in order to log the user out.

Now it’s time to work on the Home component. One of the dependencies the component has is the react-swipeable-views library which will add nice animations when the user changes tabs.

To install react-swipeable-views, run the command:

yarn add react-swipeable-views


You will also need to make HTTP calls to your Python ReST API as well as to the Github ReST API. The Github HTTP client will need to have a method or function to make a request to this URL: https://api.github.com/search/repositories?q=USER-QUERY. You are going to use the q query string to pass the term the user wants to query against Github’s repositories.

Create a file named githubClient.js.

touch src/githubClient.js


Paste the following content in it:

export default {
 getJSONRepos(query) {
   return fetch('https://api.github.com/search/repositories?q=' + query).then(response => response.json());
 }
}


Now, you need to create an HTTP client to make HTTP calls to the Python ReST API you implemented in the first section of this tutorial. Since all the requests made to your Python ReST API require the user to be authenticated, you will need to set the Authorization HTTP Header with the accessToken provided by Okta.

Go ahead and create a file named apiClient.js

touch src/apiClient.js


And install axios to help you to perform HTTP calls to your flask API.

yarn add axios


Then, paste the following content:

import axios from 'axios';

const BASE_URI = 'http://localhost:4433';

const client = axios.create({
 baseURL: BASE_URI,
 json: true
});

class APIClient {
 constructor(accessToken) {
   this.accessToken = accessToken;
 }

 createKudo(repo) {
   return this.perform('post', '/kudos', repo);
 }

 deleteKudo(repo) {
   return this.perform('delete', `/kudos/${repo.id}`);
 }

 getKudos() {
   return this.perform('get', '/kudos');
 }

 async perform (method, resource, data) {
   return client({
     method,
     url: resource,
     data,
     headers: {
       Authorization: `Bearer ${this.accessToken}`
     }
   }).then(resp => {
     return resp.data ? resp.data : [];
   })
 }
}

export default APIClient;


Great! Your APIClient’s method perform is adding the user’s accessToken to the Authorization HTTP header of every request, which means, it’s authenticating every request. When the server receives these HTTP requests your Okta middleware will be able to verify the token and to extract user details from it as well.

Normally, you might create separate components for getting the user’s bookmarks and for searching for github repos. For simplicity’s sake you’ll put them all in the HomeComponent

Paste the following content in the src/Home/index.js file.

import React from 'react';
import { withStyles } from '@material-ui/core/styles';
import SwipeableViews from 'react-swipeable-views';
import Tabs from '@material-ui/core/Tabs';
import Tab from '@material-ui/core/Tab';
import Grid from '@material-ui/core/Grid';
import { withAuth } from '@okta/okta-react';

import GithubRepo from "../GithubRepo"
import SearchBar from "../SearchBar"

import githubClient from '../githubClient'
import APIClient from '../apiClient'

const styles = theme => ({
 root: {
   flexGrow: 1,
   marginTop: 30
 },
 paper: {
   padding: theme.spacing.unit * 2,
   textAlign: 'center',
   color: theme.palette.text.secondary,
 },
});

class Home extends React.Component {
 state = {
   value: 0,
   repos: [],
   kudos: []
 };

 async componentDidMount() {
   const accessToken = await this.props.auth.getAccessToken()
   this.apiClient = new APIClient(accessToken);
   this.apiClient.getKudos().then((data) =>
     this.setState({...this.state, kudos: data})
   );
 }

 handleTabChange = (event, value) => {
   this.setState({ value });
 };

 handleTabChangeIndex = index => {
   this.setState({ value: index });
 };

 resetRepos = repos => this.setState({ ...this.state, repos })

 isKudo = repo => this.state.kudos.find(r => r.id == repo.id)
  onKudo = (repo) => {
   this.updateBackend(repo);
 }

 updateBackend = (repo) => {
   if (this.isKudo(repo)) {
     this.apiClient.deleteKudo(repo);
   } else {
     this.apiClient.createKudo(repo);
   }
   this.updateState(repo);
 }

 updateState = (repo) => {
   if (this.isKudo(repo)) {
     this.setState({
       ...this.state,
       kudos: this.state.kudos.filter( r => r.id !== repo.id )
     })
   } else {
     this.setState({
       ...this.state,
       kudos: [repo, ...this.state.kudos]
     })
   }
 }

 onSearch = (event) => {
   const target = event.target;
   if (!target.value || target.length < 3) { return }
   if (event.which !== 13) { return }

   githubClient
     .getJSONRepos(target.value)
     .then((response) => {
       target.blur();
       this.setState({ ...this.state, value: 1 });
       this.resetRepos(response.items);
     })
 }
  renderRepos = (repos) => {
   if (!repos) { return [] }
   return repos.map((repo) => {
     return (
       <Grid item xs={12} md={3} key={repo.id}>
         <GithubRepo onKudo={this.onKudo} isKudo={this.isKudo(repo)} repo={repo} />
       </Grid>
     );
   })
 }

 render() {
   return (
     <div className={styles.root}>
       <SearchBar auth={this.props.auth} onSearch={this.onSearch} />
        <Tabs
         value={this.state.value}
         onChange={this.handleTabChange}
         indicatorColor="primary"
         textColor="primary"
         fullWidth
       >
         <Tab label="Kudos" />
         <Tab label="Search" />
       </Tabs>

       <SwipeableViews
         axis={'x-reverse'}
         index={this.state.value}
         onChangeIndex={this.handleTabChangeIndex}
       >
         <Grid container spacing={16} style={{padding: '20px 0'}}>
           { this.renderRepos(this.state.kudos) }
         </Grid>
         <Grid container spacing={16} style={{padding: '20px 0'}}>
           { this.renderRepos(this.state.repos) }
         </Grid>
       </SwipeableViews>
     </div>
   );
 }
}

export default withStyles(styles)(withAuth(Home));


Now run npm start and open http://localhost:8080 in your browser. You should be able to login, search for GitHub repos, and favorite a repo and see it in your Kudos list!

 

If you want to see what the finished project looks like, you can see the code on GitHub.

Originally published by Kleber Correia at developer.okta.com

 

What is GEEK

Buddha Community

Build a Simple CRUD App with Python, Flask, and React
Autumn  Blick

Autumn Blick

1598839687

How native is React Native? | React Native vs Native App Development

If you are undertaking a mobile app development for your start-up or enterprise, you are likely wondering whether to use React Native. As a popular development framework, React Native helps you to develop near-native mobile apps. However, you are probably also wondering how close you can get to a native app by using React Native. How native is React Native?

In the article, we discuss the similarities between native mobile development and development using React Native. We also touch upon where they differ and how to bridge the gaps. Read on.

A brief introduction to React Native

Let’s briefly set the context first. We will briefly touch upon what React Native is and how it differs from earlier hybrid frameworks.

React Native is a popular JavaScript framework that Facebook has created. You can use this open-source framework to code natively rendering Android and iOS mobile apps. You can use it to develop web apps too.

Facebook has developed React Native based on React, its JavaScript library. The first release of React Native came in March 2015. At the time of writing this article, the latest stable release of React Native is 0.62.0, and it was released in March 2020.

Although relatively new, React Native has acquired a high degree of popularity. The “Stack Overflow Developer Survey 2019” report identifies it as the 8th most loved framework. Facebook, Walmart, and Bloomberg are some of the top companies that use React Native.

The popularity of React Native comes from its advantages. Some of its advantages are as follows:

  • Performance: It delivers optimal performance.
  • Cross-platform development: You can develop both Android and iOS apps with it. The reuse of code expedites development and reduces costs.
  • UI design: React Native enables you to design simple and responsive UI for your mobile app.
  • 3rd party plugins: This framework supports 3rd party plugins.
  • Developer community: A vibrant community of developers support React Native.

Why React Native is fundamentally different from earlier hybrid frameworks

Are you wondering whether React Native is just another of those hybrid frameworks like Ionic or Cordova? It’s not! React Native is fundamentally different from these earlier hybrid frameworks.

React Native is very close to native. Consider the following aspects as described on the React Native website:

  • Access to many native platforms features: The primitives of React Native render to native platform UI. This means that your React Native app will use many native platform APIs as native apps would do.
  • Near-native user experience: React Native provides several native components, and these are platform agnostic.
  • The ease of accessing native APIs: React Native uses a declarative UI paradigm. This enables React Native to interact easily with native platform APIs since React Native wraps existing native code.

Due to these factors, React Native offers many more advantages compared to those earlier hybrid frameworks. We now review them.

#android app #frontend #ios app #mobile app development #benefits of react native #is react native good for mobile app development #native vs #pros and cons of react native #react mobile development #react native development #react native experience #react native framework #react native ios vs android #react native pros and cons #react native vs android #react native vs native #react native vs native performance #react vs native #why react native #why use react native

Top Python App Development Company in USA

AppClues Infotech is one of the leading Python app development company in USA. We are a one-stop solutions provider for mobile consulting, experience design, app development, IoT development, and cloud solutions for businesses varying in size from start-up to enterprise.

Our Python App Development Solutions
• Machine Learning Solutions
• Custom Python Development
• Python Mobile App Development
• Python CMS Development
• Python Up-gradation & Migration
• Django Framework Development

For more info:
Website: https://www.appcluesinfotech.com/
Email: info@appcluesinfotech.com
Call: +1-978-309-9910

#python app development #top python app development company in usa #hire python app developers in usa #how to develop python mobile app #best python app development services #custom python app development

Top 10 React Native App Development Companies in USA

React Native is the most popular dynamic framework that provides the opportunity for Android & iOS users to download and use your product. Finding a good React Native development company is incredibly challenging. Use our list as your go-to resource for React Native app development Companies in USA.

List of Top-Rated React Native Mobile App Development Companies in USA:

  1. AppClues Infotech
  2. WebClues Infotech
  3. AppClues Studio
  4. WebClues Global
  5. Data EximIT
  6. Apptunix
  7. BHW Group
  8. Willow Tree:
  9. MindGrub
  10. Prismetric

A Brief about the company details mentioned below:

1. AppClues Infotech
As a React Native Mobile App Development Company in USA, AppClues Infotech offers user-centered mobile app development for iOS & Android. Since their founding in 2014, their React Native developers create beautiful mobile apps.

They have a robust react native app development team that has high knowledge and excellent strength of developing any type of mobile app. They have successfully delivered 450+ mobile apps as per client requirements and functionalities.
Website: https://www.appcluesinfotech.com/

2. WebClues Infotech
WebClues Infotech is the Top-Notch React Native mobile app development company in USA & offering exceptional service worldwide. Since their founding in 2014, they have completed 950+ web & mobile apps projects on time.

They have the best team of developers who has an excellent knowledge of developing the most secure, robust & Powerful React Native Mobile Apps. From start-ups to enterprise organizations, WebClues Infotech provides top-notch React Native App solutions that meet the needs of their clients.
Website: https://www.webcluesinfotech.com/

3. AppClues Studio
AppClues Studio is one of the top React Native mobile app development company in USA and offers the best service worldwide at an affordable price. They have a robust & comprehensive team of React Native App developers who has high strength & extensive knowledge of developing any type of mobile apps.
Website: https://www.appcluesstudio.com/

4. WebClues Global
WebClues Global is one of the best React Native Mobile App Development Company in USA. They provide low-cost & fast React Native Development Services and their React Native App Developers have a high capability of serving projects on more than one platform.

Since their founding in 2014, they have successfully delivered 721+ mobile app projects accurately. They offer versatile React Native App development technology solutions to their clients at an affordable price.
Website: https://www.webcluesglobal.com/

5. Data EximIT
Hire expert React Native app developer from top React Native app development company in USA. Data EximIT is providing high-quality and innovative React Native application development services and support for your next projects. The company has been in the market for more than 8 years and has already gained the trust of 553+ clients and completed 1250+ projects around the globe.

They have a large pool of React Native App developers who can create scalable, full-fledged, and appealing mobile apps to meet the highest industry standards.
Website: https://www.dataeximit.com/

6. Apptunix
Apptunix is the best React Native App Development Company in the USA. It was established in 2013 and vast experience in developing React Native apps. After developing various successful React Native Mobile Apps, the company believes that this technology helps them incorporate advanced features in mobile apps without influencing the user experience.
Website: https://www.apptunix.com/

7. BHW Group
BHW Group is a Top-Notch React Native Mobile App Development Company in the USA. The company has 13+ years of experience in providing qualitative app development services to clients worldwide. They have a compressive pool of React Native App developers who can create scalable, full-fledged, and creative mobile apps to meet the highest industry standards.
Website: https://thebhwgroup.com/

8. Willow Tree:
Willow Tree is the Top-Notch React Native Mobile App Development Company in the USA & offering exceptional React Native service. They have the best team of developers who has an excellent knowledge of developing the most secure, robust & Powerful React Native Mobile Apps. From start-ups to enterprise organizations, Willow Tree has top-notch React Native App solutions that meet the needs of their clients.
Website: https://willowtreeapps.com/

9. MindGrub
MindGrub is a leading React Native Mobile App Development Company in the USA. Along with React Native, the company also works on other emerging technologies like robotics, augmented & virtual reality. The Company has excellent strength and the best developers team for any type of React Native mobile apps. They offer versatile React Native App development technology solutions to their clients.
Website: https://www.mindgrub.com/

10. Prismetric
Prismetric is the premium React Native Mobile App Development Company in the USA. They provide fast React Native Development Services and their React Native App Developers have a high capability of serving projects on various platforms. They focus on developing customized solutions for specific business requirements. Being a popular name in the React Native development market, Prismetric has accumulated a specialty in offering these services.
Website: https://www.prismetric.com/

#top rated react native app development companies in usa #top 10 react native app development companies in usa #top react native app development companies in usa #react native app development technologies #react native app development #hire top react native app developers in usa

Fredy  Larson

Fredy Larson

1595059664

How long does it take to develop/build an app?

With more of us using smartphones, the popularity of mobile applications has exploded. In the digital era, the number of people looking for products and services online is growing rapidly. Smartphone owners look for mobile applications that give them quick access to companies’ products and services. As a result, mobile apps provide customers with a lot of benefits in just one device.

Likewise, companies use mobile apps to increase customer loyalty and improve their services. Mobile Developers are in high demand as companies use apps not only to create brand awareness but also to gather information. For that reason, mobile apps are used as tools to collect valuable data from customers to help companies improve their offer.

There are many types of mobile applications, each with its own advantages. For example, native apps perform better, while web apps don’t need to be customized for the platform or operating system (OS). Likewise, hybrid apps provide users with comfortable user experience. However, you may be wondering how long it takes to develop an app.

To give you an idea of how long the app development process takes, here’s a short guide.

App Idea & Research

app-idea-research

_Average time spent: two to five weeks _

This is the initial stage and a crucial step in setting the project in the right direction. In this stage, you brainstorm ideas and select the best one. Apart from that, you’ll need to do some research to see if your idea is viable. Remember that coming up with an idea is easy; the hard part is to make it a reality.

All your ideas may seem viable, but you still have to run some tests to keep it as real as possible. For that reason, when Web Developers are building a web app, they analyze the available ideas to see which one is the best match for the targeted audience.

Targeting the right audience is crucial when you are developing an app. It saves time when shaping the app in the right direction as you have a clear set of objectives. Likewise, analyzing how the app affects the market is essential. During the research process, App Developers must gather information about potential competitors and threats. This helps the app owners develop strategies to tackle difficulties that come up after the launch.

The research process can take several weeks, but it determines how successful your app can be. For that reason, you must take your time to know all the weaknesses and strengths of the competitors, possible app strategies, and targeted audience.

The outcomes of this stage are app prototypes and the minimum feasible product.

#android app #frontend #ios app #minimum viable product (mvp) #mobile app development #web development #android app development #app development #app development for ios and android #app development process #ios and android app development #ios app development #stages in app development

Carmen  Grimes

Carmen Grimes

1595491178

Best Electric Bikes and Scooters for Rental Business or Campus Facility

The electric scooter revolution has caught on super-fast taking many cities across the globe by storm. eScooters, a renovated version of old-school scooters now turned into electric vehicles are an environmentally friendly solution to current on-demand commute problems. They work on engines, like cars, enabling short traveling distances without hassle. The result is that these groundbreaking electric machines can now provide faster transport for less — cheaper than Uber and faster than Metro.

Since they are durable, fast, easy to operate and maintain, and are more convenient to park compared to four-wheelers, the eScooters trend has and continues to spike interest as a promising growth area. Several companies and universities are increasingly setting up shop to provide eScooter services realizing a would-be profitable business model and a ready customer base that is university students or residents in need of faster and cheap travel going about their business in school, town, and other surrounding areas.

Electric Scooters Trends and Statistics

In many countries including the U.S., Canada, Mexico, U.K., Germany, France, China, Japan, India, Brazil and Mexico and more, a growing number of eScooter users both locals and tourists can now be seen effortlessly passing lines of drivers stuck in the endless and unmoving traffic.

A recent report by McKinsey revealed that the E-Scooter industry will be worth― $200 billion to $300 billion in the United States, $100 billion to $150 billion in Europe, and $30 billion to $50 billion in China in 2030. The e-Scooter revenue model will also spike and is projected to rise by more than 20% amounting to approximately $5 billion.

And, with a necessity to move people away from high carbon prints, traffic and congestion issues brought about by car-centric transport systems in cities, more and more city planners are developing more bike/scooter lanes and adopting zero-emission plans. This is the force behind the booming electric scooter market and the numbers will only go higher and higher.

Companies that have taken advantage of the growing eScooter trend develop an appthat allows them to provide efficient eScooter services. Such an app enables them to be able to locate bike pick-up and drop points through fully integrated google maps.

List of Best Electric Bikes for Rental Business or Campus Facility 2020:

It’s clear that e scooters will increasingly become more common and the e-scooter business model will continue to grab the attention of manufacturers, investors, entrepreneurs. All this should go ahead with a quest to know what are some of the best electric bikes in the market especially for anyone who would want to get started in the electric bikes/scooters rental business.

We have done a comprehensive list of the best electric bikes! Each bike has been reviewed in depth and includes a full list of specs and a photo.

Billy eBike

mobile-best-electric-bikes-scooters https://www.kickstarter.com/projects/enkicycles/billy-were-redefining-joyrides

To start us off is the Billy eBike, a powerful go-anywhere urban electric bike that’s specially designed to offer an exciting ride like no other whether you want to ride to the grocery store, cafe, work or school. The Billy eBike comes in 4 color options – Billy Blue, Polished aluminium, Artic white, and Stealth black.

Price: $2490

Available countries

Available in the USA, Europe, Asia, South Africa and Australia.This item ships from the USA. Buyers are therefore responsible for any taxes and/or customs duties incurred once it arrives in your country.

Features

  • Control – Ride with confidence with our ultra-wide BMX bars and a hyper-responsive twist throttle.
  • Stealth- Ride like a ninja with our Gates carbon drive that’s as smooth as butter and maintenance-free.
  • Drive – Ride further with our high torque fat bike motor, giving a better climbing performance.
  • Accelerate – Ride quicker with our 20-inch lightweight cutout rims for improved acceleration.
  • Customize – Ride your own way with 5 levels of power control. Each level determines power and speed.
  • Flickable – Ride harder with our BMX /MotoX inspired geometry and lightweight aluminum package

Specifications

  • Maximum speed: 20 mph (32 km/h)
  • Range per charge: 41 miles (66 km)
  • Maximum Power: 500W
  • Motor type: Fat Bike Motor: Bafang RM G060.500.DC
  • Load capacity: 300lbs (136kg)
  • Battery type: 13.6Ah Samsung lithium-ion,
  • Battery capacity: On/off-bike charging available
  • Weight: w/o batt. 48.5lbs (22kg), w/ batt. 54lbs (24.5kg)
  • Front Suspension: Fully adjustable air shock, preload/compression damping /lockout
  • Rear Suspension: spring, preload adjustment
  • Built-in GPS

Why Should You Buy This?

  • Riding fun and excitement
  • Better climbing ability and faster acceleration.
  • Ride with confidence
  • Billy folds for convenient storage and transportation.
  • Shorty levers connect to disc brakes ensuring you stop on a dime
  • belt drives are maintenance-free and clean (no oil or lubrication needed)

**Who Should Ride Billy? **

Both new and experienced riders

**Where to Buy? **Local distributors or ships from the USA.

Genze 200 series e-Bike

genze-best-electric-bikes-scooters https://www.genze.com/fleet/

Featuring a sleek and lightweight aluminum frame design, the 200-Series ebike takes your riding experience to greater heights. Available in both black and white this ebike comes with a connected app, which allows you to plan activities, map distances and routes while also allowing connections with fellow riders.

Price: $2099.00

Available countries

The Genze 200 series e-Bike is available at GenZe retail locations across the U.S or online via GenZe.com website. Customers from outside the US can ship the product while incurring the relevant charges.

Features

  • 2 Frame Options
  • 2 Sizes
  • Integrated/Removable Battery
  • Throttle and Pedal Assist Ride Modes
  • Integrated LCD Display
  • Connected App
  • 24 month warranty
  • GPS navigation
  • Bluetooth connectivity

Specifications

  • Maximum speed: 20 mph with throttle
  • Range per charge: 15-18 miles w/ throttle and 30-50 miles w/ pedal assist
  • Charging time: 3.5 hours
  • Motor type: Brushless Rear Hub Motor
  • Gears: Microshift Thumb Shifter
  • Battery type: Removable Samsung 36V, 9.6AH Li-Ion battery pack
  • Battery capacity: 36V and 350 Wh
  • Weight: 46 pounds
  • Derailleur: 8-speed Shimano
  • Brakes: Dual classic
  • Wheels: 26 x 20 inches
  • Frame: 16, and 18 inches
  • Operating Mode: Analog mode 5 levels of Pedal Assist Thrott­le Mode

Norco from eBikestore

norco-best-electric-bikes-scooters https://ebikestore.com/shop/norco-vlt-s2/

The Norco VLT S2 is a front suspension e-Bike with solid components alongside the reliable Bosch Performance Line Power systems that offer precise pedal assistance during any riding situation.

Price: $2,699.00

Available countries

This item is available via the various Norco bikes international distributors.

Features

  • VLT aluminum frame- for stiffness and wheel security.
  • Bosch e-bike system – for their reliability and performance.
  • E-bike components – for added durability.
  • Hydraulic disc brakes – offer riders more stopping power for safety and control at higher speeds.
  • Practical design features – to add convenience and versatility.

Specifications

  • Maximum speed: KMC X9 9spd
  • Motor type: Bosch Active Line
  • Gears: Shimano Altus RD-M2000, SGS, 9 Speed
  • Battery type: Power Pack 400
  • Battery capacity: 396Wh
  • Suspension: SR Suntour suspension fork
  • Frame: Norco VLT, Aluminum, 12x142mm TA Dropouts

Bodo EV

bodo-best-electric-bikes-scootershttp://www.bodoevs.com/bodoev/products_show.asp?product_id=13

Manufactured by Bodo Vehicle Group Limited, the Bodo EV is specially designed for strong power and extraordinary long service to facilitate super amazing rides. The Bodo Vehicle Company is a striking top in electric vehicles brand field in China and across the globe. Their Bodo EV will no doubt provide your riders with high-level riding satisfaction owing to its high-quality design, strength, breaking stability and speed.

Price: $799

Available countries

This item ships from China with buyers bearing the shipping costs and other variables prior to delivery.

Features

  • Reliable
  • Environment friendly
  • Comfortable riding
  • Fashionable
  • Economical
  • Durable – long service life
  • Braking stability
  • LED lighting technology

Specifications

  • Maximum speed: 45km/h
  • Range per charge: 50km per person
  • Charging time: 8 hours
  • Maximum Power: 3000W
  • Motor type: Brushless DC Motor
  • Load capacity: 100kg
  • Battery type: Lead-acid battery
  • Battery capacity: 60V 20AH
  • Weight: w/o battery 47kg

#android app #autorent #entrepreneurship #ios app #minimum viable product (mvp) #mobile app development #news #app like bird #app like bounce #app like lime #autorent #best electric bikes 2020 #best electric bikes for rental business #best electric kick scooters 2020 #best electric kickscooters for rental business #best electric scooters 2020 #best electric scooters for rental business #bird scooter business model #bird scooter rental #bird scooter rental cost #bird scooter rental price #clone app like bird #clone app like bounce #clone app like lime #electric rental scooters #electric scooter company #electric scooter rental business #how do you start a moped #how to start a moped #how to start a scooter rental business #how to start an electric company #how to start electric scooterrental business #lime scooter business model #scooter franchise #scooter rental business #scooter rental business for sale #scooter rental business insurance #scooters franchise cost #white label app like bird #white label app like bounce #white label app like lime