Arka uç için NodeJs
ve veritabanımız olarak Postgres'i kullanacağız. Ön uçta ReactJs
vite
ile kullanıyoruz.
Bunun için biri backend
, diğeri frontend
için olmak üzere 2 ayrı depo oluşturmamız gerekecek.
Şimdi başlayalım.
Şablonumuz temel bir Node.js
uygulamasını ve yerleşik bir PostgreSQL
veritabanını kapsar.
İşte kurulumumuza karşılık gelen docker-compose.yaml
dosyası 🐳:
version: "3" services: app: build: context: . target: development env_file: .env volumes: - ./src:/usr/src/app/src ports: - 8081:80 depends_on: - db db: image: postgres:14 restart: always environment: POSTGRES_USER: admin POSTGRES_PASSWORD: admin POSTGRES_DB: my-startup-db volumes: - postgres-data:/var/lib/postgresql/data ports: - 5432:5432 volumes: postgres-data:
npm install bcrypt cookie-parser cors jsonwebtoken pg-hstore stripe
Burada demo için Test Mode
kullanıyor olacağız.
İşte bu proje için ihtiyaç duyacağımız ortam değişkenlerinin listesi.
.env.example
STRIPE_PUBLISHABLE_KEY= STRIPE_SECRET_KEY= POSTGRES_DB_URI= secretKey= CLIENT_URL=
models/userModel.js
module.exports = (sequelize, DataTypes) => { const User = sequelize.define( "user", { email: { type: DataTypes.STRING, unique: true, isEmail: true, //checks for email format allowNull: false, }, password: { type: DataTypes.STRING, allowNull: false, }, tier: { type: DataTypes.STRING, allowNull: true, }, }, { timestamps: true } ); return User; };
POST /login
- Kullanıcının oturum açmasına ve oturumu kaydetmesine yardımcı olur
POST /signup
- Yeni bir hesap oluşturmaya yardımcı olur
POST /create-checkout-session
- Şerit ödeme sayfası bağlantısını oluşturur ve döndürür
routes/userRoutes.js
const express = require("express"); const userController = require("../controllers/userController"); const { signup, login } = userController; const userAuth = require("../middleware/userAuth"); const router = express.Router(); router.post("/signup", userAuth.saveUser, signup); router.post("/login", login); module.exports = router;
routes/stripeRoute.js
const express = require("express"); const { updatePlan } = require("../controllers/stripeController"); const router = express.Router(); router.post("/create-checkout-session", updatePlan); module.exports = router;
middleware/userAuth.js
//importing modules const express = require("express"); const db = require("../models"); const User = db.users; const saveUser = async (req, res, next) => { console.log("here"); try { const checkEmail = await User.findOne({ where: { email: req.body.email, }, }); if (checkEmail) { return res.json(409).send("Authentication failed"); } next(); } catch (error) { console.log(error); } }; module.exports = { saveUser, };
controllers/userController.js
const bcrypt = require("bcrypt"); const db = require("../models"); const jwt = require("jsonwebtoken"); const User = db.users; const signup = async (req, res) => { try { const { email, password } = req.body; console.log(email); const data = { email, password: await bcrypt.hash(password, 10), }; //saving the user const user = await User.create(data); if (user) { let token = jwt.sign({ id: user.id }, process.env.secretKey, { expiresIn: 1 * 24 * 60 * 60 * 1000, }); res.cookie("jwt", token, { maxAge: 1 * 24 * 60 * 60, httpOnly: true }); console.log("user", JSON.stringify(user, null, 2)); console.log(token); return res.status(201).send(user); } else { return res.status(409).send("Details are not correct"); } } catch (error) { console.log(error); } }; // Login Authentication const login = async (req, res) => { try { const { email, password } = req.body; const user = await User.findOne({ where: { email: email, }, }); if (user) { const isSame = await bcrypt.compare(password, user.password); if (isSame) { let token = jwt.sign({ id: user.id }, process.env.secretKey, { expiresIn: 1 * 24 * 60 * 60 * 1000, }); res.cookie("jwt", token, { maxAge: 1 * 24 * 60 * 60, httpOnly: true }); //send user data return res.status(201).send(user); } else { return res.status(401).send("Authentication failed"); } } else { return res.status(401).send("Authentication failed"); } } catch (error) { console.log(error); } }; module.exports = { signup, login, };
Stripe Checkout
uygulamamıza entegre edeceğimiz yer burasıdır.
Ödemeleri yönetmek ve kullanıcı aboneliklerini yönetmek için Stripe API
kullanacağız.
controllers/stripeController.js
const db = require("../models"); const Stripe = require("stripe"); const User = db.users; require("dotenv").config(); const stripe = Stripe(process.env.STRIPE_SECRET_KEY); const updatePlan = async (req, res) => { try { const { email, product } = req.body; const session = await stripe.checkout.sessions.create({ payment_method_types: ["card"], line_items: [ { price_data: { currency: "usd", product_data: { name: product.name, }, unit_amount: product.price * 100, }, quantity: product.quantity, }, ], mode: "payment", success_url: `${process.env.CLIENT_URL}/success`, cancel_url: `${process.env.CLIENT_URL}/`, }); //find a user by their email const user = await User.findOne({ where: { email: email, }, }); if (user) { await user.update({ tier: product.name }); return res.send({ url: session.url }); } else { return res.status(401).send("User not found"); } } catch (error) { console.log(error); } }; module.exports = { updatePlan, };
Son olarak tüm rotalarımızı giriş noktamız olan server.js
eklememiz gerekecek.
server.js
const cors = require("cors"); const express = require("express"); require("dotenv").config(); const cookieParser = require("cookie-parser"); const db = require("./models"); const userRoutes = require("./routes/userRoutes"); const PORT = process.env.PORT || 8080; const stripeRoute = require("./routes/stripeRoute"); const app = express(); // Middlewares app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use(cookieParser()); app.use(cors()); // Routes app.use("/api/v1/users", userRoutes); app.use("/api/v1/stripe", stripeRoute); app.listen(PORT, () => { console.log("Server started at port 8080"); try { db.sequelize.sync({ force: true }).then(() => { console.log("db has been re sync"); }); } catch (error) {} });
Şimdi devam edelim ve bunu FL0
üzerinde konuşlandırmayı deneyelim. 🔼
Burada yeni bir proje oluşturmamız gerekecek, örneğin stripe-fl0
adını verelim.
Bu, React-Vite
projemizi çalışır duruma getirmek için ihtiyacımız olan her şeyi içerir.
npm install @heroicons/react axios react-router-dom npm install postcss tailwindcss autoprefixer --save-dev
src/components/PricingPlans.jsx
... const handleCheckout = (product) => { axios .post( `//stripe-fl0-backend-dev.fl0.io/api/v1/stripe/create-checkout-session`, { email, product, } ) .then((res) => { if (res.data.url) { setTier(product.name); localStorage.setItem("tier", product.name); window.location.href = res.data.url; } }) .catch((err) => navigate("/cancel")); }; ...
Bu işlev arka uçumuzun /create-checkout-session
rotasını çağırır, bir bağlantı alır ve kullanıcıyı ödeme sayfasına yönlendirir. 📄
Bunun dışında signup
ve login
sayfalarımızı da ilgili rotalara bağlamamız ve kullanıcı verilerini localstorage
saklamamız gerekiyor.
Daha sonra, arka ucumuzun URL'sine ayarlanması gereken ön uç dağıtımına VITE_APP_API_BASE_URL
ortam değişkenini eklememiz gerekir.
Ayrıca arka uçtaki CLIENT_URL
ortam değişkenini ön ucun barındırılan URL'sine ayarlamamız gerekir.
Bu eğitimde Stripe Checkout
tam kapsamlı uygulamalarımıza kolayca entegre ederek ödeme sayfalarının nasıl oluşturulacağını öğrendik. 🎉