Fetch API

OneJS provides a fetch function for HTTP requests.

Basic GET Request

async function loadData() {
    const response = await fetch("https://api.example.com/data")
    const data = await response.json()
    console.log(data)
}

POST Request

async function submitScore(score) {
    const response = await fetch("https://api.example.com/scores", {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
        },
        body: JSON.stringify({ score }),
    })

    if (response.ok) {
        console.log("Score submitted!")
    }
}

With React

function UserProfile({ userId }) {
    const [user, setUser] = useState(null)
    const [loading, setLoading] = useState(true)
    const [error, setError] = useState(null)

    useEffect(() => {
        async function loadUser() {
            try {
                const res = await fetch(`https://api.example.com/users/${userId}`)
                if (!res.ok) throw new Error("Failed to load user")
                const data = await res.json()
                setUser(data)
            } catch (e) {
                setError(e.message)
            } finally {
                setLoading(false)
            }
        }
        loadUser()
    }, [userId])

    if (loading) return <Label text="Loading..." />
    if (error) return <Label text={`Error: ${error}`} />

    return (
        <View>
            <Label text={user.name} style={{ fontSize: 24 }} />
            <Label text={user.email} style={{ color: "#999" }} />
        </View>
    )
}

Request Options

const response = await fetch(url, {
    method: "POST",           // GET, POST, PUT, DELETE, HEAD
    headers: {
        "Content-Type": "application/json",
        "Authorization": "Bearer token123",
    },
    body: JSON.stringify(data),
})

Response Methods

const response = await fetch(url)

// Get JSON
const json = await response.json()

// Get text
const text = await response.text()

// Check status
if (response.ok) {
    // 200-299
}

console.log(response.status)     // 200
console.log(response.statusText) // "OK"

Error Handling

async function fetchWithRetry(url, retries = 3) {
    for (let i = 0; i < retries; i++) {
        try {
            const response = await fetch(url)
            if (!response.ok) {
                throw new Error(`HTTP ${response.status}`)
            }
            return await response.json()
        } catch (error) {
            if (i === retries - 1) throw error
            await new Promise(r => setTimeout(r, 1000 * (i + 1)))
        }
    }
}

Loading States Hook

function useFetch(url) {
    const [data, setData] = useState(null)
    const [loading, setLoading] = useState(true)
    const [error, setError] = useState(null)

    useEffect(() => {
        let cancelled = false

        async function load() {
            try {
                setLoading(true)
                const res = await fetch(url)
                const json = await res.json()
                if (!cancelled) setData(json)
            } catch (e) {
                if (!cancelled) setError(e)
            } finally {
                if (!cancelled) setLoading(false)
            }
        }

        load()
        return () => { cancelled = true }
    }, [url])

    return { data, loading, error }
}

// Usage
function LeaderboardScreen() {
    const { data, loading, error } = useFetch("/api/leaderboard")

    if (loading) return <Label text="Loading..." />
    if (error) return <Label text="Failed to load" />

    return (
        <ScrollView>
            {data.map((entry, i) => (
                <Label key={i} text={`${i + 1}. ${entry.name}: ${entry.score}`} />
            ))}
        </ScrollView>
    )
}

Polling

function usePolling(url, interval = 5000) {
    const [data, setData] = useState(null)

    useEffect(() => {
        async function poll() {
            const res = await fetch(url)
            const json = await res.json()
            setData(json)
        }

        poll() // Initial fetch
        const id = setInterval(poll, interval)
        return () => clearInterval(id)
    }, [url, interval])

    return data
}

Notes

  • Uses Unity's UnityWebRequest under the hood
  • Works in Editor, Standalone, and WebGL builds
  • CORS restrictions may apply in WebGL
  • For local development, ensure your API server allows cross-origin requests