Back to Blog

Tauri HTTP Requests Tutorial - Build a Quote of the Day App | React + Rust

Sandy LaneSandy Lane

Video: Tauri HTTP Requests Tutorial - Build a Quote of the Day App | React + Rust by Taught by Celeste AI - AI Coding Coach

Watch full page →

Tauri HTTP Requests Tutorial - Build a Quote of the Day App | React + Rust

In this tutorial, you’ll learn how to integrate HTTP requests into a Tauri desktop app using React and Rust. We build a Quote of the Day app that fetches random inspirational quotes from an external API, handling loading states, errors, and JSON parsing along the way.

Code

// src-tauri/src/main.rs
#![cfg_attr(
  all(not(debug_assertions), target_os = "windows"),
  windows_subsystem = "windows"
)]

use tauri::{Builder};
use tauri_plugin_http::{Builder as HttpBuilder};

fn main() {
  Builder::default()
    // Enable HTTP plugin for making requests
    .plugin(HttpBuilder::default().build())
    .run(tauri::generate_context!())
    .expect("error while running tauri application");
}

// src/App.tsx (React + TypeScript)
import React, { useState, useEffect } from 'react';
import { fetch } from '@tauri-apps/plugin-http';

interface Quote {
  content: string;
  author: string;
}

function App() {
  const [quote, setQuote] = useState<Quote | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  async function fetchQuote() {
    setLoading(true);
    setError(null);
    try {
      // Fetch a random quote from dummyjson API
      const response = await fetch('https://dummyjson.com/quotes/random');
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
      const data = await response.json();
      setQuote({ content: data.quote, author: data.author });
    } catch (err: any) {
      setError(err.message || 'Failed to fetch quote');
    } finally {
      setLoading(false);
    }
  }

  // Fetch a quote on component mount
  useEffect(() => {
    fetchQuote();
  }, []);

  return (
    <div style={{ padding: 20, fontFamily: 'Arial, sans-serif', minHeight: '100vh', backgroundColor: '#121212', color: '#eee' }}>
      <h1>Quote of the Day</h1>
      {loading && <p>Loading...</p>}
      {error && <p style={{ color: 'red' }}>Error: {error}</p>}
      {quote && !loading && (
        <div style={{ marginTop: 20, padding: 20, borderRadius: 8, backgroundColor: '#1e1e1e' }}>
          <p style={{ fontStyle: 'italic', fontSize: 24 }}>"{quote.content}"</p>
          <p style={{ marginTop: 10, fontSize: 18, color: '#888' }}>- {quote.author}</p>
        </div>
      )}
      <button
        onClick={fetchQuote}
        disabled={loading}
        style={{
          marginTop: 30,
          padding: '10px 20px',
          fontSize: 16,
          borderRadius: 5,
          cursor: loading ? 'not-allowed' : 'pointer'
        }}
      >New Quote</button>
    </div>
  );
}

export default App;

// tauri.conf.json (excerpt showing HTTP permissions)
{
  "tauri": {
    "allowlist": {
      "http": {
        "all": true
      }
    },
    "security": {
      "csp": null
    },
    "plugins": {
      "http": {
        "scope": ["https://dummyjson.com"]
      }
    }
  }
}

Key Points

  • Use the tauri-plugin-http in Rust backend to enable HTTP requests securely.
  • Configure explicit HTTP permissions in tauri.conf.json to allow network access only to trusted domains.
  • Leverage the plugin’s fetch function in React to request external APIs and handle JSON responses.
  • Manage loading and error states in React for a smooth user experience during asynchronous data fetching.
  • Combine React’s useEffect hook with state hooks to fetch data on app startup and on demand.