Expo HTTP Server

0.1.13 · active · verified Sun Apr 19

expo-http-server is an Expo module that provides a simple HTTP server implementation exclusively for iOS and Android React Native applications. It is currently at version 0.1.13 and sees active development with recent updates for Expo 53 compatibility and feature enhancements like custom headers. The module leverages native libraries, Criollo for iOS and AndroidServer for Android, offering local network communication capabilities directly from the mobile device. A key differentiator is its focus on embedding a server within a mobile app, enabling scenarios like local API mocking, inter-app communication, or serving local assets without a remote backend. It notably does not support web environments, which is a crucial limitation to understand.

Common errors

Warnings

Install

Imports

Quickstart

This example demonstrates how to set up an HTTP server on port 9666, define two routes ('/' and '/html'), and handle incoming GET requests to serve JSON and HTML content, respectively, within an Expo React Native app.

import * as server from 'expo-http-server';
import { useEffect, useState } from 'react';
import { Text, View } from 'react-native';

export default function App() {
  const [lastCalled, setLastCalled] = useState<number | undefined>();

  const html = `
	<!DOCTYPE html>
	<html>
		<body style="background-color:powderblue;">
			<h1>expo-http-server</h1>
			<p>You can load HTML!</p>
		</body>
	</html>`;

  const obj = { app: 'expo-http-server', desc: 'You can load JSON!' };

  useEffect(() => {
    server.setup(9666, (event: server.StatusEvent) => {
      if (event.status === 'ERROR') {
        console.error('Server error:', event.message);
      } else {
        console.log('Server status:', event.status);
      }
    });
    server.route('/', 'GET', async (request) => {
      console.log('Request to / (GET)', request);
      setLastCalled(Date.now());
      return {
        statusCode: 200,
        headers: {
          'Custom-Header': 'Bazinga',
        },
        contentType: 'application/json',
        body: JSON.stringify(obj),
      };
    });
    server.route('/html', 'GET', async (request) => {
      console.log('Request to /html (GET)', request);
      setLastCalled(Date.now());
      return {
        statusCode: 200,
        statusDescription: 'OK - CUSTOM STATUS',
        contentType: 'text/html',
        body: html,
      };
    });
    server.start();
    return () => {
      server.stop();
    };
  }, []);

  return (
    <View
      style={{
        flex: 1,
        backgroundColor: '#fff',
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>
        {lastCalled === undefined
          ? 'Request webserver to change text'
          : 'Called at ' + new Date(lastCalled).toLocaleString()}
      </Text>
    </View>
  );
}

view raw JSON →