By Marshall Chikari
The Rapyd Collect API simplifies online payments on your website while also handling payments from all over the world with different currencies and methods. Rapyd is an API first company that allows you to collect, hold, and disburse funds in various countries using local payment methods.
In this tutorial, you'll use a travel agency website as an example to see just how easy it is to use this API. By the end of the tutorial, you'll know how to integrate an effective payment system that you can use in many other web development projects. You'll be using Python Flask for the backend, React.js for the frontend, and SQLite for the database, so you'll be well equipped to handle payments for any online venture.
Prerequisites
Before you begin, make sure you have the following:
- Python and Flask
- React.js
- SQLite for the database
- Rapyd Client Portal account for accessing the Collect API
Setting Up the Project Structure
Let's start by setting up the project structure.
First, create a new project directory:
mkdir python-react-rapyd
cd python-react-rapyd
Initialize a virtual environment for Flask:
python -m venv venv
source venv/bin/activate # On Windows, use `venv\Scripts\activate`
Virtual environments are essential for isolating Python dependencies used in different projects. By creating a virtual environment named venv
, you ensure that the packages and dependencies required for our Flask backend won't interfere with other Python projects on the system. Activating the virtual environment with the source venv/bin/activate
or venv\Scripts\activate on Windows
ensures that any installed packages are contained within this environment.
Create a Flask project:
pip install flask flask-sqlalchemy flask-bcrypt PyJWT flask-cors requests
mkdir python-backend
touch python-backend/app.py
Flask is a lightweight and flexible Python web framework that you'll use to build the backend of the travel agency website. By installing Flask and creating a dedicated directory for the backend python-backend
, you establish the foundation for your server-side logic. You'll place all Flask-related code and files within this directory. The app.py file created within python-backend
will serve as the entry point for our Flask application, where you define routes, database models, and other server-side functionality.
Adding User Registration and Login (Flask Backend)
You'll next enhance the Flask backend to include user registration and login functionality. Visit the GitHub repository for the complete code.
You need to define a user model in python-backend/app.py
to represent user data. Add the following code within your Flask app:
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(50), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
You'll now create a new route for user registration. Add the following code to your app.py file to create a user registration endpoint:
@app.route('/api/register', methods=['POST'])
def register():
data = request.get_json()
username = data.get('username')
password = data.get('password')
if not username or not password:
return jsonify({'message': 'Username and password are required'}), 400
hashed_password = bcrypt.generate_password_hash(password).decode('utf-8')
new_user = User(username=username, password=hashed_password)
db.session.add(new_user)
try:
db.session.commit()
return jsonify({'message': 'User registered successfully'}), 201
except Exception as e:
db.session.rollback()
if 'UNIQUE constraint failed' in str(e):
return jsonify({'message': 'Username already exists'}), 400
else:
return jsonify({'message': 'An error occurred'}), 500
To create a user login endpoint, add this code to app.py:
@app.route('/api/login', methods=['POST'])
def login():
data = request.get_json()
username = data.get('username')
password = data.get('password')
if not username or not password:
return jsonify({'message': 'Username and password are required'}), 400
user = User.query.filter_by(username=username).first()
if user and bcrypt.check_password_hash(user.password, password):
token = generate_token(username)
return jsonify({'user_id': user.id, 'token': token, 'message': 'Login successful'}), 200
else:
return jsonify({'message': 'Invalid username or password'}), 401
To run the Flask app, use the following command in your terminal while you're in the directory python-backend
:
python app.py
This creates an instance of the database and the necessary tables, as you can see in the following screenshot:
Create React Frontend
Open your terminal and navigate to your project's root directory (python-react-rapyd
).
Run the following command to create a new React application called react-frontend
:
npx create-react-app react-frontend
This command sets up a new React project with the default project structure.
Remove Unnecessary Files
By default, create-react-app
generates many files and folders that you might not need for this project. Let's clean up the project structure.
Navigate to the react-frontend
directory, go into the src
directory, and remove all files from the components
directory except for App.js. Your src
directory should now contain only the following files:
App.js
index.js
index.css
You'll next create the necessary components for login, registration, and trip listing. Inside the src
directory, create a new folder called components
:
mkdir src/components
Inside the src/components
directory, add the following files to create the new components:
Login.js
Register.js
TripList.js
Now that you have the necessary components, update src/App.js
to include routing for login, registration, and trip listing pages. You can use the react-router-dom
library for this purpose.
Install react-router-dom
by running the following command inside the react-frontend
directory:
npm install react-router-dom
Update src/App.js
to include routing for the components by adding the following code:
import React from "react";
import { BrowserRouter as Router, Route, Redirect, Switch } from "react-router-dom";
import Login from "./components/Login";
import Register from "./components/Register";
import TripList from "./components/TripList";
function App() {
return (
<Router>
<Switch>
<Route exact path="/login">
<Login />
</Route>
<Route exact path="/register">
<Register />
</Route>
<Route exact path="/trips">
<TripList />
</Route>
<Redirect to="/login" />
</Switch>
</Router>
);
}
export default App;
Implement the login functionality in the Login.js component. This component will include a form where users can enter their username and password to log in. When the user submits the form, it will make an API request to the Flask backend for authentication.
Here's the code for the Login.js component:
import React, { useState } from "react";
import { useCookies } from "react-cookie";
import axios from "axios";
function Login() {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [cookies, setCookie] = useCookies(["token"]);
const [loginError, setLoginError] = useState("");
async function handleSubmit(event) {
event.preventDefault();
try {
const response = await axios.post("http://localhost:5000/v1/login", {
username,
password,
});
const { token, user_id } = response.data;
setCookie("token", token, { path: "/" });
setCookie("user_id", user_id, { path: "/" });
window.location.href = "/";
} catch (error) {
if (error.response && error.response.data.message) {
setLoginError(error.response.data.message);
} else {
setLoginError("Login failed. Please try again.");
}
}
}
return (
<div>
<h2>Login</h2>
{loginError && <p style={{ color: "red" }}>{loginError}</p>}{" "}
<form onSubmit={handleSubmit}>
<label>
Username:
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
</label>
<br />
<label>
Password:
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</label>
<br />
<input type="submit" value="Submit" />
</form>
</div>
);
}
export default Login;
In the code above, you use the axios
library to make an API request to the Flask backend when the user submits the login form. In the handleSubmit
function, you use axios.post to send a POST request to the Flask login endpoint (http://localhost:5000/v1/login
). You then pass the username and password from the component's state as the request data. If the login is successful, you receive a response that typically includes a token and user ID, like in the image below:
To run the React application, run the following command in the directory react-frontend
:
npm start
Here is a demonstration of the features of the base application, which involves creating a user account and making a booking.
Integrate the Hosted Checkout Page in Your App
Before you can use Rapyd's payment services, you need to obtain API keys.
Visit the Rapyd Client Portal and retrieve your access keys by navigating to the Developers section:
Set Up the Checkout Page
You can also update your checkout page to fit your brand. Just head over to the Branding section in the Rapyd Client Portal under Settings > Branding.
Here, you can pick the type of hosted page you want, like the hosted checkout, and add your company's logo to make it truly yours. You can even play with button colors, set up a fallback URL for a smoother user experience, and explore other branding options that fit your style. Don't forget to hit Save to put your changes into action. Whether you run a travel agency or any online business, these tweaks will help you craft a checkout experience that feels just right for your customers.
Implement Checkout in React
You'll now incorporate Rapyd Checkout into your travel agency website, allowing your users to securely make payments on a Rapyd hosted checkout page. Begin by integrating the provided code snippet into your TripList.js component:
import React, { useState, useEffect } from "react";
import axios from "axios";
import { useCookies } from "react-cookie";
function TripList() {
const [trips, setTrips] = useState([]);
const [cookies] = useCookies(["token"]);
const [bookingMessage, setBookingMessage] = useState(""); // State to track booking message
useEffect(() => {
const token = cookies.token;
if (!token) {
console.error("Token is missing");
return;
}
// Fetch the list of trips when the component mounts
axios
.get("http://localhost:5000/v1/trips", {
headers: {
Authorization: token,
},
})
.then((response) => {
setTrips(response.data.trips);
})
.catch((error) => {
console.error("Error fetching trips:", error);
});
}, [cookies.token]);
const handleBookTrip = (tripId) => {
const token = cookies.token;
const userId = cookies.user_id;
if (!token || !userId) {
console.error("Token or user ID is missing");
return;
}
// Make a POST request to your backend to initiate the Rapyd payment
axios
.post(
"http://localhost:5000/v1/bookings",
{ trip_id: tripId, user_id: userId },
{
headers: {
Authorization: token,
},
}
)
.then((response) => {
if (response.status === 201) {
if (
response.data.payment_response &&
response.data.payment_response.redirect_url
) {
const redirectUrl = response.data.payment_response.redirect_url;
// Redirect the user to the Rapyd hosted checkout page
window.location.href = redirectUrl;
} else {
setBookingMessage("Redirect URL not provided in the response!");
}
} else {
setBookingMessage("Booking failed");
}
})
.catch((error) => {
setBookingMessage("Error booking a trip");
console.log("Error booking trip:", error);
});
};
return (
<div>
<h2>Trip List</h2>
<ul>
{trips.map((trip) => (
<li key={trip.id}>
{trip.name} - ${trip.price} - {""}
<button onClick={() => handleBookTrip(trip.id)}>Book</button>
</li>
))}
</ul>
{bookingMessage && <p>{bookingMessage}</p>}{" "}
{/* Display booking success message */}
</div>
);
}
export default TripList;
This component, TripList.js, uses the useEffect
hook to fetch a list of trips from your backend API when it mounts. It uses the axios
library to make a GET request to the /v1/trips
endpoint, passing the authorization token in the header. The handleBookTrip
function is called when the user clicks the Book button for a specific trip. It makes a POST
request to your backend's /v1/bookings
endpoint, passing the trip_id
and user_id
to initiate the booking process. When the POST
request is successful (HTTP status code 201
), it receives a response containing payment details, including the redirect_url
. If the redirect_url
is provided, the user is redirected to the Rapyd hosted checkout page.
If there's an error during the booking process, appropriate error messages are displayed using the bookingMessage
state.
Rapyd Utility Functions
The rapyd_utils.py file contains utility functions for interacting with the Rapyd API. These functions help with generating signatures and timestamps and making requests to Rapyd's API.
Here's a brief explanation of the key functions:
-
generate_salt
: generates a random string that is used as a salt -
get_unix_time
: returns the current Unix timestamp -
update_timestamp_salt_sig
: generates a signature for the API request based on the HTTP method, path, body, and API keys -
current_sig_headers
: creates headers including access key, salt, timestamp, signature, and idempotency for the API request -
pre_call
: prepares data (body, salt, timestamp, and signature) before making an API call -
create_headers
: creates headers for the API request -
make_request
: makes an HTTP request to the Rapyd API using the provided HTTP method, path, and body
These utility functions are used in your Flask backend to interact with the Rapyd API and initiate the payment process. Make sure to replace 'SECRET_KEY' and 'ACCESS_KEY' with your actual Rapyd API keys in the rapyd_utils.py file when you integrate it with your backend.
Here is a demo image of the integration:
Get the Code
Get the code, build something amazing with the Rapyd API, and share it with us here in the developer community. Hit reply below if you have questions or comments.
Top comments (0)