Core components
Client core
FeathersJS API & real-time services
22 min
overview the feathersjs api & real time services system provides the communication layer between the ir engine client and backend server it enables the client to request data, send updates, and receive real time notifications about changes occurring on the server by leveraging feathersjs, a javascript framework designed for real time applications, the ir engine client maintains a persistent connection to the server that supports both traditional request response patterns and live event based updates this chapter explores how the client uses feathersjs to interact with server side resources and maintain synchronized state across the application core concepts client server communication modern web applications typically need to communicate with a server to retrieve data fetch information stored in databases (user profiles, content, settings) submit changes send user actions and updates to be processed and stored receive notifications get informed about events and changes from other users or system processes traditional web applications relied on manual page refreshes or periodic polling to stay updated modern applications like the ir engine use more sophisticated approaches that provide immediate updates and a smoother user experience feathersjs framework feathersjs is a lightweight web framework that simplifies client server communication service oriented server resources are organized as services (users, projects, avatars) standardized methods consistent api for common operations (find, get, create, update, remove) real time capabilities built in support for websockets and event based communication authentication integration seamless handling of user authentication and authorization the ir engine client uses feathersjs to provide a consistent, reliable communication layer that supports both traditional api calls and real time updates implementation api client setup the communication layer is initialized in the application's startup process // simplified from src/api ts import feathers from '@feathersjs/client'; import primus from 'primus client'; import primusclient from ' /util/primus client'; import config from '@ir engine/common/src/config'; // create a new feathers client instance const feathersclient = feathers(); // set up real time connection using primus (websockets) const primus = new primus(`${config client serverurl}?${/ query params /}`); feathersclient configure(primusclient(primus)); // configure authentication feathersclient configure(authentication({ storagekey 'ir engine jwt', jwtstrategy 'jwt' })); // make the client available globally api instance = feathersclient; this initialization creates a new feathersjs client instance establishes a websocket connection using primus configures authentication handling makes the client available throughout the application via api instance making service requests the client interacts with server resources through services, using standardized methods // example fetching projects from the server import { api } from '@ir engine/common'; import { projectpath } from '@ir engine/common/src/schema type module'; import { getmutablestate } from '@ir engine/hyperflux'; import { projectstate } from ' /projectstate'; async function fetchprojectsfromserver() { try { // access the 'projects' service const projectservice = api instance service(projectpath); // request a list of projects with query parameters const projectdata = await projectservice find({ query { action 'admin', allowed true, $sort { createdat 1 } } }); // store the received data in hyperflux state getmutablestate(projectstate) merge({ projects projectdata data, loaded true, loading false }); return projectdata data; } catch (error) { console error("could not fetch projects ", error); getmutablestate(projectstate) loading set(false); throw error; } } this function gets a reference to the projects service using api instance service(projectpath) calls the find() method with query parameters to filter and sort the results waits for the server response using await updates the application state with the received data using hyperflux handles any errors that might occur during the request common service methods feathersjs provides standardized methods for interacting with services find retrieves multiple records, often with filtering // get a list of active projects const activeprojects = await api instance service('projects') find({ query { status 'active', $sort { name 1 }, // sort by name ascending $limit 25 // limit to 25 results } }); get retrieves a single record by id // get a specific project by id const project = await api instance service('projects') get('project 123'); create creates a new record // create a new project const newproject = await api instance service('projects') create({ name 'new project', description 'a project created from the client', visibility 'private' }); patch updates parts of an existing record // update a project's name and description await api instance service('projects') patch('project 123', { name 'updated project name', description 'this description has been updated' }); remove deletes a record // delete a project await api instance service('projects') remove('project 123'); real time event handling one of the most powerful features of feathersjs is its real time capabilities the client can listen for events emitted by services when data changes // example setting up real time listeners for project changes import { api } from '@ir engine/common'; import { projectpath } from '@ir engine/common/src/schema type module'; import { getmutablestate } from '@ir engine/hyperflux'; import { projectstate } from ' /projectstate'; function setupprojectlisteners() { const projectservice = api instance service(projectpath); // when a project is created on the server projectservice on('created', (newproject) => { console log('new project created ', newproject); // update our local state to include the new project const currentprojects = getmutablestate(projectstate) projects value || \[]; getmutablestate(projectstate) projects set(\[newproject, currentprojects]); }); // when a project is updated on the server projectservice on('patched', (updatedproject) => { console log('project updated ', updatedproject); // update the project in our local state const currentprojects = getmutablestate(projectstate) projects value || \[]; const updatedprojects = currentprojects map(project => project id === updatedproject id ? updatedproject project ); getmutablestate(projectstate) projects set(updatedprojects); }); // when a project is removed on the server projectservice on('removed', (removedproject) => { console log('project removed ', removedproject); // remove the project from our local state const currentprojects = getmutablestate(projectstate) projects value || \[]; const filteredprojects = currentprojects filter(project => project id !== removedproject id ); getmutablestate(projectstate) projects set(filteredprojects); }); } this function gets a reference to the projects service sets up listeners for three types of events created , patched , and removed defines handler functions that update the local application state when these events occur ensures the ui stays synchronized with the server without manual refreshing request response flow the process of making a request to the server follows this sequence sequencediagram participant clientcode as client code participant api as api instance participant server as backend server participant database as server database clientcode >>api service('projects') find(query) api >>server sends http request or websocket message server >>database queries database for projects database >>server returns project data server >>api sends response with project data api >>clientcode returns data (promise resolves) clientcode >>clientcode updates hyperflux state this diagram illustrates client code calls a service method on api instance the api client sends a request to the server the server processes the request (often involving database operations) the server sends back a response with the requested data the api client resolves the promise with the received data the client code typically updates the application state with the new data real time event flow the process of receiving real time updates follows this sequence sequencediagram participant externalaction as external action participant server as backend server participant api as api instance participant eventhandler as event handler participant hyperflux as hyperflux state externalaction >>server causes data change (e g , admin updates project) server >>server updates database server >>api emits event with updated data (via websocket) api >>eventhandler calls registered event handler eventhandler >>hyperflux updates application state hyperflux >>hyperflux notifies ui components to update this diagram illustrates an external action (another user, system process) causes a data change on the server the server updates its database and determines which clients should be notified the server emits an event with the updated data to connected clients the client's api instance receives the event and calls the registered handler the handler updates the application state using hyperflux ui components react to the state change and update accordingly integration with hyperflux the feathersjs api layer works closely with hyperflux state management data fetching service methods retrieve data from the server, which is then stored in hyperflux state data submission user actions update hyperflux state and trigger service method calls to send changes to the server real time updates event handlers receive server notifications and update hyperflux state accordingly this integration creates a seamless flow of data between the server and the client ui // example of the complete data flow import { api } from '@ir engine/common'; import { getmutablestate, usemutablestate } from '@ir engine/hyperflux'; import { projectstate } from ' /projectstate'; // react component that displays and manages projects function projectmanager() { // access the project state const projectstate = usemutablestate(projectstate); const projects = projectstate projects value || \[]; const loading = projectstate loading value; // function to load projects from the server async function loadprojects() { // update loading state getmutablestate(projectstate) loading set(true); try { // fetch projects from the server const projectservice = api instance service('projects'); const result = await projectservice find({ query { status 'active' } }); // update hyperflux state with the results getmutablestate(projectstate) merge({ projects result data, loading false, loaded true }); } catch (error) { console error("failed to load projects ", error); getmutablestate(projectstate) loading set(false); } } // set up real time listeners when the component mounts useeffect(() => { const projectservice = api instance service('projects'); // listen for real time updates const createdlistener = (newproject) => { const currentprojects = getmutablestate(projectstate) projects value || \[]; getmutablestate(projectstate) projects set(\[newproject, currentprojects]); }; projectservice on('created', createdlistener); // clean up listeners when the component unmounts return () => { projectservice removelistener('created', createdlistener); }; }, \[]); // load projects when the component mounts useeffect(() => { if (!projectstate loaded value) { loadprojects(); } }, \[]); // render the component return ( \<div> \<h1>projects\</h1> {loading ? ( \<p>loading projects \</p> ) ( \<ul> {projects map(project => ( \<li key={project id}>{project name}\</li> ))} \</ul> )} \<button onclick={loadprojects}>refresh projects\</button> \</div> ); } this component demonstrates using hyperflux state to access project data and loading status fetching projects from the server and updating hyperflux state setting up real time listeners to automatically update when new projects are created rendering the ui based on the current state providing a manual refresh option benefits of feathersjs the feathersjs api & real time services system provides several key advantages standardized api consistent methods across all services simplify development real time updates automatic ui updates when server data changes reduced network traffic no need for polling or frequent refresh requests improved user experience immediate feedback and live updates simplified state management clear patterns for integrating server data with client state scalability efficient communication that works well even with many concurrent users these benefits make feathersjs an essential foundation for the ir engine client's communication layer next steps with an understanding of how the client communicates with the server, the next chapter explores how the system secures these communications and manages user identity next user authentication and authorization docid\ b331zwx7l uc1eevbee 7