Ana içeriğe atla

MERN Stack ile Uygulama Geliştirme

MERN Stack ile Uygulama Geliştirme

Mern ya da Mevn hepsi aynıdır. Birisi React biri Vue kullanır.

Normalde bunun için NextJS, NuxtJS gibi Fullstack geliştirme araçlarımız var ama biz onun yerine client ve server diye ayırıp öyle yapacağız.

Şundan başlayalım, 2 ayrı klasör olsa da React dosyalarını compiler edip çıktısını Nodejs ile render ediyorlar. Böylece direkt tek porttan istek atabiliyorsunuz. Kabaca.

Bir de, Server’a gidip ayrı bir port ile açıp ona istek atıyoruz yeniden.

Burada MERN Stack ne diye soracaksanız eğer: Mongodb, Express, React, Nodejs demektir.

Burada hem Arayüz hem backend gelştireceğiz.

Ama öncelikle, arayüzcüler için diyorum kolay olmayacak.

Burada basitçe örneklendirmek için fazla bir şey kullanmayacağım.

MERN Stack (Görsel, I.)

1- Proje Temelleri

İlk olarak Todo-App diye bir dosya açalım. Neden Todo-App? Basit diye mi? Hayır. Çünkü örnek verebileceğimiz bolca şeyi sağladığı için.

Todo-App

— — Client

— — Server

Böyle olacak.

Gelin arayüzü kuralım,

  • client klasörüne gir,
  • npm create vite” çalıştırıp,
  • eğer daha önce kurmadıysanız bekleyin (Uyarı çıkarsa kabul edip geçin Enter’a basın),
  • React seçin
  • Javascript’i seçin.
  • Kurulmasını bekleyin.

Sonra backend’i kuralım:

  • server klasörüne gir,
  • npm init -y” diyelim ve package.json oluşturalım
  • server’daki package.json’a “type”: “module” diye ekleyin.

Şimdi burada değinmemiz gereken bir şey var, Mono-repo kullanacağız. Ortak bir package.json’dan yöneteceğiz projeyi.

Şimdi package.json’a bu kodu ekleyelim:

"workspaces": [
"client",
"server"
],

Sonra, backend için:

npm install express mongoose cors morgan -w server

Bide her kod değişikliğimizde uygulamayı izlemek için; nodemon, ayrıca arayüz ve backend’i birlikte çalıştırmak için concurrently kuracağız

npm install -D concurrently modemon -w .

Scripts’e şunları ekleyelim:

"scripts": {
"server:start": "npm run start -w server",
"server:dev": "npm run dev -w server",
"client:dev": "npm run dev -w client",
"start": "concurrently \"npm run client:dev\" \"npm run server:start\"",
"dev": "concurrently \"npm run client:dev\" \"npm run server:dev\""
}

Burası bittikten sonra, vite.config.js’e girip, şöyle yapalım:

export default defineConfig({
plugins: [react()]
server: {
port: 8000,
proxy: {
'/api': 'http://localhost:80/api' // backend url'miz
}
}
})

Tüm temeller hazır.

Şimdi gelelim ilk olarak backend’i yapmaya, ilk olarak şunu anlamanız gerekir burada yapacağımız şey bir restful api.

Şimdi api’yi yapmaya dosya yapısı ile başlayacağız:

server

— — routers

— — — index.js

— — controllers

— — — index.js

— — models

— — — index.js

— — config

— — — index.js

— — server.js

— — .env

Biz buna MVC yapısı diyoruz, bide service de oluşturabiliriz fakat biz buna girmeyeceğiz.

Sonra alias kullanacağım server tarafında, bunun içinde package.json’a tanımlamalar yapmam gerek.

"imports": {
"#routers": "./routers/index.js",
"#models": "./models/index.js",
"#controllers": "./controllers/index.js",
"#config": "./config/index.js"
},

Neden index.js, çünkü oradan import edeceğiz.

Sonra devam edelim, bir uygulama çalışıyor mu diye ana route’a girince bize “Test” yazdıracak bir route tanımlıyor ve uygulamayı app.listen() ile açıyoruz.

server.js:


import 'dotenv/config'; // Bu ortam değişkenlerimizi yüklüyor

import express from 'express'; // Api için kullanacağımız paket
import cors from 'cors'; // İstek atarken güvenliğe takılmamak için
import morgan from 'morgan'; // İstekleri izlemek için

const app = express();

app.use(express.urlencoded({ extended: true }));
app.use(express.json());

app.use(cors({ origin: true, credentials: true }));
app.use(morgan('dev'));

app.get('/', (req, res) => {
res.send('Test');
});

const PORT = process.env.PORT || 80;

app.listen(PORT, () => {
console.log(`Sunucu localhost:${PORT} portunda çalışıyor.`);
});

Sonra .env dosyamızı oluşturuyoruz:

PORT = 80
MONGO_URI =

Önce mongodb bağlantısı için ayrı bir dosya yazalım, config/db.js:

import mongoose from 'mongoose'

const MONGO_URI = process.env.MONGO_URI

export default async function db(){

mongoose.set('sanitizeFilter', true);
try {
if(!MONGO_URI) {
console.error("MongoDB bağlantısı girilmemiş!")
return null
}
const conn = await mongoose.connect(MONGO_URI)
console.log("Veritabanına bağlandı")
return conn
} catch(err) {
console.error("Veritabanı hatası: ", err)
return null
}
}

sonra bunu çıkaracağız, benim kullandığım yöntem bu, config/index.js:

import db from "./db.js"

export {
db
}

Şimdi başlayalım backend’e:

models/Todo.js

import mongoose from "mongoose";

const todoSchema = new mongoose.Schema({
content: { type: String },
isDone: { type: Boolean, default: false },
createdAt: { type: Date, default: Date.now },
}, { timestamps: true });

export default mongoose.model("Todo", todoSchema);

models/index.js’de çıkartalım dosyayı

Şimdi todo yaratma methodu ekleyelim:

controllers/TodoController.js

import { Todo } from "#models"

const addTodo = async (req, res) => {

try {
const todo = await Todo.create(req.body)

return res.status(200).json({
success: true,
message: 'Todo Yaratıldı',
data: todo
})
} catch(err){
console.error("[ERROR]: ", err.message)
}
}

Sonra silme yapalım bide:

controllers/TodoController.js

import { Todo } from "#models"

const removeTodo = async (req, res) => {
const { id } = req.params

try {
const todo = await Todo.findByIdAndRemove(id)

return res.status(200).json({
success: true,
message: 'Todo silindi',
data: todo
})
} catch(err){
console.error("[ERROR]: ", err.message)
}
}

Güncelleme yapalım bide:

controllers/TodoController.js

import { Todo } from "#models"

const updateTodo = async (req, res) => {
const { id } = req.params
const { content, isDone } = req.body

try {
const todo = Todo.findById(id)

if(content) todo.content = content
if(isDone) todo.isDone = isDone

const result = await todo.save()

return res.status(200).json({
success: true,
message: 'Todo Güncellendi',
data: result
})
} catch(err){
console.error("[ERROR]: ", err.message)
}
}

Tümünü çekelim:

controllers/TodoController.js

import { Todo } from "#models"

const getTodos = async (req, res) => {

try {
const todo = Todo.find({})

return res.status(200).json({
success: true,
message: 'Todolar getirildi',
data: result
})

} catch(err){
console.error("[ERROR]: ", err.message)
}

}

Tümünü çekelim:

controllers/TodoController.js

import { Todo } from "#models"

const getTodo = async (req, res) => {

const { id } = req.params

try {
const todo = Todo.findById(id)

return res.status(200).json({
success: true,
message: 'Todo getirildi',
data: todo
})
} catch(err){
console.error("[ERROR]: ", err.message)
}
}

Sonra hepsini çıkaralım controller/TodoController.js:

export {
addTodo,
removeTodo,
updateTodo,
getTodos,
getTodo
}

Sonra hepsini çıkaralım controller/index.js:

export * from './todoController.js'

Sonra router’ı yapalım:

routers/TodoRoute.js

import express from 'express';

import { addTodo, removeTodo, updateTodo, getTodos, getTodo } from "#controllers"

const router = express.Router();

router.get('/', getTodos)
router.post('/', addTodo)
router.get('/:id', getTodo)
router.put('/:id', updateTodo)
router.delete('/:id', removeTodo)

export default router;

Sonra hepsini çıkaralım routers/index.js:

import todoRoute from './todoRoute.js'

export {
todoRoute
}

Sonra ana dosyamıza gelelim:

main.js

import { todoRoute } from '#routers'

app.use('/todos', todoRoute)

Backend’imiz bu kadardı.

Şimdi arayüze geçelim:

Arayüzde ise, şöyle yapacağız:

ilk başta vite ile kurulum yaptık zâten, her /api dediğimizde ise vite.config.js’de tanımladığımız backend url’imizi alacak.

Native istek atma kütüphaneleri yerine, axios’u kullanacağız. npm i axios -w client komutunu kullanıp projemize kuruyoruz.

Şimdi API isteklerimizi bir yerden erişebilecek şekilde ayarlayalım:

src/API.js

const API = {
GetTodos: ()=> axios.get(`/api/todos`).then((res)=> res.data).catch((err)=> console.error(err)),
GetTodo: (id)=> axios.get(`/api/todos/${id}`).then((res)=> res.data).catch((err)=> console.error(err)),

AddTodo: (data)=> axios.post("/api/todos", data).then((res)=> res.data).catch((err)=> console.error(err)),
RemoveTodo: (id)=> axios.delete(`/api/todos/${id}`).then((res)=> res.data).catch((err)=> console.error(err)),
UpdateTodo: (id, data)=> axios.put(`/api/todos/${id}`, data).then((res)=> res.data).catch((err)=> console.error(err)),
}
export default API

İlk başta Todos.jsx diye bir component oluşturalım:

src/Todos.jsx

import { useState } from 'react'
import axios from 'axios'
import API from './API.js'

function Todos() {
const [todos, setTodos] = useState([])

return (
<ul>
{todos?.map((todo, i)=> <li key={i}>
{todo.content} - <button onClick={()=> API.removeTodo(todo._id)}>Sil</button>
</li>)}
</ul>

)
}

export default Todos

Şimdi todo ekleme ekranı yapalım:

İlk başta TodoCreate.jsx diye bir component oluşturalım:

src/TodoCreate.jsx

import { useState } from 'react'
import axios from 'axios'

import API from './API.js'

function TodoCreate() {
const [content, setContent] = useState('')
const [isDone, setIsDone] = useState(false)

return (
<>
<input type="text" value={content} onChange={(e)=> setContent(e.target.value)}/>
<input type="checkbox" checked={isDone} onChange={(e)=> setIsDone(!isDone)}/>
<button onClick={()=> API.AddTodo({ content, isDone })}>Ekle</button>
</>

)
}
export default CreateTodo

İlk başta TodoCreate.jsx diye bir component oluşturalım:

src/TodoCreate.jsx

import { useState } from 'react'
import axios from 'axios'

import API from './API.js'

function TodoUpdate({todo}) {
const [content, setContent] = useState('')
const [isDone, setIsDone] = useState(false)

useEffect(()=>{
setIsDone(todo.isDone)
setContent(todo.content)
}, [todo])

return (
<>
<input type="text" value={content} onChange={(e)=> setContent(e.target.value)}/>
<input type="checkbox" checked={isDone} onChange={(e)=> setIsDone(!isDone)}/>
<button onClick={()=> API.UpdateTodo(todo._id, {content, isDone})}>Güncelle</button>
</>

)
}
export default TodoUpdate

Bu kadardı.

Tek tek state kullanmamın nedeni daha basit olmasını sağlamaktı. Aslında burada react router da kullanabilirdik. Fakat daha basit tutalım.

Burada MERN Stack’imizi tamamladık.

Hepsini App.jsx’e çağırıp, kullanabiliriz.

İyi günler!

Yorumlar

Bu blogdaki popüler yayınlar

Filistin’in iki yüzü: PKK ve ASALA

  Filistin’in iki yüzü: PKK ve ASALA Diyeceksiniz ki: “ Ama insanlar ölüyor, yazık değil mi! Ne acımasızsın! ” falan filan.. Hayır efendim, hayır! Elbette çocukların ölmesine üzülüyorum, bende bir insanım lâkin FKÖ’nün eğittiği PKK’nın kaç Türk çocuğunun canını aldığını ez mi geçiceğiz? Burada Suriye’nin PKK’ya verdiği desteği yazmayacağım çünkü zâten blogu’mda “ Sosyalist Bedevî: Esad ailesi, atalarının izinde ” diye bir yazı yazıp detaylıca anlatmıştım. Ayrıca FKÖ’nün kurucularından ve Filistin devlet başkanı Mahmut Abbas hakkında da burada bahsetmeyeceğiz. Çünkü daha önce bahsetmiştik, bakınız: “ Solcu bir Bedevî: Mahmud Abbas ” Gelgelelim, Filistin ve PKK ilişkilerine, şöyle anlatayım: PKK, Suriye-Filistin-Lübnan kampların’da eğitim görmüştü. PKK, Suriye Hükûmeti tarafından Bekaa Vadisi’ne yerleştirilmişti. Burada yetişmişler burada militanlaşmışlardı. Bizzat büyük Türkiye dostu (!) Yaser Arafat tarafından desteklenmişlerdi. (1) İsrail’e karşı operasyonlar da kullanılmışla...

Yıldırım Beyazıd ve Emir Timurlenk Savaşı

YILDIRIM BEYAZID VE EMİR TİMUR LENK SAVAŞI Ankara Savaşı (28 Temmuz 1402) Cengiz Han'ın vârisi olma iddiası ile çıkan Emir Timur. Beyazı'dın egemen olmasını kabul etmiyor. Onu küçümsüyor. Timur'un tahtını ele geçirmek için isyan başlatan   ve Timur Hindistan seferinden gelince bizzat kendisi tarafından kovulan Diyarbakır Beyi İlhan Ahmet Celâyir, Osmanlı'ya sığınmıştı. Epey Timur ve Beyazıd'ın arası gergindi. Fakat Timur kendi ırkından, dininden olan Osmanlı’ya saldırmak istemiyordu.   Timur’a tabî olan Mutahharten’ın ailesini Bursa’ya esir olarak gönderen Beyazid ile Timur’un arası açılmıştı.   “ Timur, kendisini sadece dünya üzerinde ulaşabileceği yere kadar hırsını doyurmak için Allah tarafından gönderilen “Allah’ın kulu” olarak değil, Türk halkının da gerçek ve tek temsilcisi olarak görüyordu. Yörüklerin bol paçalı şalvarları içinde, başında yüksek keçe başlığı ile tam bir Türk gibi giyinirdi.. Sarayı’nda sadece Türkçe konuşulur ve Türkçe yazı yazılır...

Kürtler ve Medler

KÜRTLER VE MEDLER Kürt Tarihçilerin çoğu kendini Medlere dayandırır. Kürt dilinin gelişmesinde Medlerin rol oynadığını söylerler. (Minorsky - Kürtler, İslam Ansiklopedisi, VI. cilt, s. 1089-1114) Ve Medlerin torunlarıdır. (Amir Hassanpour - Kürdistanda Milliyetçilik ve Dil; s. 120.) » Kürtlerin tek kurduğu ulusal devlet olarak Medler İmparatorluğunu kabul ederler. (Wadie Jwaideh - Kürt Miliyetçiliğinin Tarihi , Kökenleri ve Gelişimi, s. 17.) » Ve bazı Kürt Tarihçilerde şöyle savunur: “bütün tarih boyunca Medleri Kürtlerden ayrı gösterecek bir hadise bulamazsınız.." (Zinnar Silopi - Doza Kurdistan; s. 9.) » Medler proto-Kürt’tür. (Philip Kreyenbroek & Christine Allison - Kürt Kimliği ve Kültürü, s. 25.) » “Dolaylı değil doğrudan Kürtlerin Medlerle bağlantıları vardır.” (Ali Hüseyin Kerim - Balkan Yarımadasında Kürtler, s. 49.) Medlerin İmparatorluğunu yıkan, Perslerdi. (William Aegleton - Mehabad Kürt Cumhuriyeti; s. 18.) Ve şunu söylemektedirler: Medler yıkıldık...