In this tutorial, we’ll build a simple note-taking application using Rust for the backend and React for the frontend. Our Rust backend will handle note data and provide a RESTful API for the React frontend to interact with.

Prerequisites

Before we start, make sure you have the following installed:

Backend: Rust with Actix-web and SQLite

Step 1: Create a new Rust project

Open your terminal and create a new Rust project:

  cargo new note_taking_backend
cd note_taking_backend
  

Step 2: Add dependencies

Open Cargo.toml and add the following dependencies:

  [dependencies]
actix-web = "4.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_derive = "1.0"
sqlx = { version = "0.5", features = ["sqlite", "runtime-actix-native-tls"] }
uuid = "1.0"
dotenv = "0.15"
  

Step 3: Set up the SQLite database

Create a .env file in the root of your project with the following content:

  DATABASE_URL=sqlite:notes.db
  

Step 4: Create the backend logic

In src/main.rs, add the following code:

  use actix_web::{web, App, HttpResponse, HttpServer, Responder};
use serde::{Deserialize, Serialize};
use sqlx::{sqlite::SqlitePool, Pool};
use std::sync::Mutex;
use uuid::Uuid;
use dotenv::dotenv;
use std::env;

#[derive(Serialize, Deserialize)]
struct Note {
    id: String,
    title: String,
    content: String,
}

struct AppState {
    db_pool: Pool<sqlx::Sqlite>,
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    dotenv().ok();
    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");

    let db_pool = SqlitePool::connect(&database_url).await.unwrap();

    sqlx::query(
        "CREATE TABLE IF NOT EXISTS notes (
            id TEXT PRIMARY KEY,
            title TEXT NOT NULL,
            content TEXT NOT NULL
        )",
    )
    .execute(&db_pool)
    .await
    .unwrap();

    let app_state = web::Data::new(AppState { db_pool });

    HttpServer::new(move || {
        App::new()
            .app_data(app_state.clone())
            .route("/notes", web::get().to(get_notes))
            .route("/notes", web::post().to(add_note))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

async fn get_notes(data: web::Data<AppState>) -> impl Responder {
    let notes = sqlx::query_as!(Note, "SELECT id, title, content FROM notes")
        .fetch_all(&data.db_pool)
        .await
        .unwrap();

    HttpResponse::Ok().json(notes)
}

#[derive(Deserialize)]
struct CreateNote {
    title: String,
    content: String,
}

async fn add_note(
    data: web::Data<AppState>,
    note: web::Json<CreateNote>,
) -> impl Responder {
    let new_note = Note {
        id: Uuid::new_v4().to_string(),
        title: note.title.clone(),
        content: note.content.clone(),
    };

    sqlx::query!(
        "INSERT INTO notes (id, title, content) VALUES (?, ?, ?)",
        new_note.id,
        new_note.title,
        new_note.content
    )
    .execute(&data.db_pool)
    .await
    .unwrap();

    HttpResponse::Created().finish()
}
  

Step 5: Run the backend

Start the backend server by running:

  cargo run
  

Your backend server should now be running on http://127.0.0.1:8080.

Frontend: React

Step 1: Create a new React project

In a separate terminal window, create a new React project:

  npx create-react-app note-taking-frontend
cd note-taking-frontend
  

Step 2: Install Axios

We’ll use Axios to make HTTP requests to our backend. Install it using:

  npm install axios
  

Step 3: Create the frontend logic

Replace the content of src/App.js with the following code:

  import React, { useState, useEffect } from "react";
import axios from "axios";
import "./App.css";

function App() {
  const [notes, setNotes] = useState([]);
  const [title, setTitle] = useState("");
  const [content, setContent] = useState("");

  useEffect(() => {
    fetchNotes();
  }, []);

  const fetchNotes = async () => {
    const response = await axios.get("http://127.0.0.1:8080/notes");
    setNotes(response.data);
  };

  const addNote = async () => {
    await axios.post("http://127.0.0.1:8080/notes", {
      title,
      content,
    });
    setTitle("");
    setContent("");
    fetchNotes();
  };

  return (
    <div className="App">
      <h1>Note Taking App</h1>
      <div>
        <input
          type="text"
          placeholder="Title"
          value={title}
          onChange={(e) => setTitle(e.target.value)}
        />
        <textarea
          placeholder="Content"
          value={content}
          onChange={(e) => setContent(e.target.value)}
        ></textarea>
        <button onClick={addNote}>Add Note</button>
      </div>
      <ul>
        {notes.map((note) => (
          <li key={note.id}>
            <h2>{note.title}</h2>
            <p>{note.content}</p>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default App;
  

Step 4: Run the frontend

Start the React development server by running:

  npm start
  

Your React application should now be running on http://localhost:3000 and will display the note-taking interface.

Conclusion

In this tutorial, we created a simple note-taking application with a Rust backend using Actix-web and SQLite for data storage, and a React frontend. This setup can be expanded with additional features like authentication, search functionality, and more to create a fully-featured note-taking application. Happy coding!

Learn How To Build AI Projects

Now, if you are interested in upskilling in 2024 with AI development, check out this 6 AI advanced projects with Golang where you will learn about building with AI and getting the best knowledge there is currently. Here’s the link.

Last updated 17 Aug 2024, 12:31 +0200 . history