Skip to main content

Frontend

This document describes techniques that you can use to implement a frontend for a reSolve application. The following techniques are available:

Client Application Entry Point​

Basic Entry Point​

A client script should export a function that is the script's entry point. This function takes the reSolve context as the parameter.

const main = async resolveContext => {
...
}
export default main

To register the entry point, assign the path to the file that contains the entry point definition to the clientEntries configuration option:

clientEntries: ['client/index.js']

Use the resolveContext object to initialize a client library. The code samples below demonstrate how to configure the entry point for different client libraries.

@resolve-js/client:

import { getClient } from '@resolve-js/client'
const main = async resolveContext => {
await new Promise(resolve => domready(resolve))
const client = getClient(resolveContext)
const { data } = await client.query({
name: 'chat',
aggregateIds: '*'
})
...
}

@resolve-js/redux:

import { createResolveStore, ResolveReduxProvider } from '@resolve-js/redux'

const entryPoint = (clientContext) => {
const store = createResolveStore(clientContext, {
serializedState: window.__INITIAL_STATE__,
redux: getRedux(),
})
const routes = getRoutes()
render(
<ResolveReduxProvider context={clientContext} store={store}>
<BrowserRouter>{renderRoutes(routes)}</BrowserRouter>
</ResolveReduxProvider>,
document.getElementById('app-container')
)
}
export default entryPoint

@resolve-js/react-hooks:

import { ResolveProvider } from '@resolve-js/react-hooks'
...
const entryPoint = (clientContext) => {
const appContainer = document.createElement('div')
document.body.appendChild(appContainer)
render(
<ResolveProvider context={clientContext}>
<BrowserRouter>{renderRoutes(routes)}</BrowserRouter>
</ResolveProvider>,
appContainer
)
}
export default

SSR Handlers​

To use Server-Side Rendering (SSR) in your application, you need to implement one or more handlers that pre-render the client application's markup on the server.

An SSR handler is an asynchronous function that receives the resolveContext along with a request and response objects. As the result of its execution, an SSR handler should send a response that contains the rendered markup:

const ssrHandler = async (
resolveContext,
req,
res
) => {
...
const markupHtml =
`<!doctype html>`
`<html ${helmet.htmlAttributes.toString()}>` +
...
'</html>'
await res.end(markupHtml)
}

To enable server-side rendering, specify an array of server-side rendering scripts that target different environments in the clientEntries configuration section:

clientEntries: [
'client/index.js',
[
'client/ssr.js',
{
outputFile: 'common/local-entry/ssr.js',
moduleType: 'commonjs',
target: 'node',
},
],
[
'client/ssr.js',
{
outputFile: 'common/cloud-entry/ssr.js',
moduleType: 'commonjs',
target: 'node',
},
],
]

For more information on these settings, refer to the Application Configuration article.

To serve SSR markup to the client, you need to register the live-require-handler.js API handler in the apiHandlers configuration section:

config.app.js:

...
apiHandlers: [
{
handler: {
module: {
package: '@resolve-js/runtime-base',
import: 'liveRequireHandler',
},
options: {
modulePath: './ssr.js',
moduleFactoryImport: false
}
},
path: '/:markup*',
method: 'GET'
}
],
...

HTTP API​

A reSolve exposes HTTP API that you can use to send aggregate commands and query Read Models. The following endpoints are available.

PurposeEndpointMethod
Send a commandhttp://{host}:{port}/api/commandsPOST
Query a Read Modelhttp://{host}:{port}/api/query/{readModel}/{resolver}POST
Query a View Modelhttp://{host}:{port}/api/query/{viewModel}/{aggregateIds}GET

Example​

The code sample below demonstrates how you can implement JavaScript functions used to communicate with a reSolve server through its HTTP API:

const apiCommandsUrl = '/api/commands'
const apiQueryUrl = '/api/query'

const sendCommand = async ({
aggregateName,
aggregateId,
type,
payload,
jwt,
}) => {
await fetch(apiCommandsUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${jwt}`,
},
body: JSON.stringify({
aggregateName,
aggregateId,
type,
payload,
}),
})
}

const queryReadModel = async (readModelName, resolver, parameters, jwt) => {
const requestUrl = `${apiQueryUrl}/${readModelName}/${resolver}`
const res = await fetch(requestUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${jwt}`,
},
body: JSON.stringify(parameters),
})
return await res.json()
}

const queryViewModel = async (viewModelName, aggregateIds, jwt) => {
const requestUrl = `${apiQueryUrl}/${viewModelName}/${aggregateIds.join(',')}`
const res = await fetch(requestUrl, {
method: 'GET',
headers: {
Authorization: `Bearer ${jwt}`,
},
})
return await res.json()
}

For more information on the HTTP API, refer to the following help topic: API Reference.

You can extend a reSolve server's API with API Handlers. Refer to the following help topic for more information: API Handlers.

@resolve-js/client library​

The @resolve-js/client library exposes an interface that you can use to communicate with the reSolve backend from JavaScript code. To initialize the client, call the library's getClient function. This function takes a reSolve context as a parameter and returns an initialized client object. This object exposes the following functions:

FunctionDescription
commandSends an aggregate command to the backend.
queryQueries a Read Model.
getStaticAssetUrlGets a static file's full URL.
getOriginPathReturns an absolute URL within the application for the given relative path.
subscribeSubscribes to View Model updates.
unsubscribeUnsubscribes from View Model updates.

Example​

The with-vanilajs template project demonstrates how to use the @resolve-js/client library to implement a frontend for a reSolve application in pure JavaScript.

@resolve-js/redux library​

The reSolve framework includes the client @resolve-js/redux library used to connect a client React + Redux app to a reSolve-powered backend.

Use the following @resolve-js/redux library's hooks and Higher-Order Components (HOCs) to connect react components to the backend.

React Hooks​

Function NameDescription
useReduxCommandCreates a hook to execute a command.
useReduxReadModelCreates a hook to query a Read Model.
useReduxReadModelSelectorCreates a hook to access a Read Model query result.
useReduxViewModelCreates a hook to receive a View Model's state updates and reactive events.
useReduxViewModelSelectorCreates a hook to access a View Model's current state on the client.

Higher-Order Components​

Function NameDescription
connectViewModelConnects a React component to a reSolve View Model.
connectReadModelConnects a React component to a reSolve Read Model.
connectRootBasedUrlsFixes URLs passed to the specified props so that they use the correct root folder path.
connectStaticBasedUrlsFixes URLs passed to the specified props so that they use the correct static resource folder path.

Example​

The shopping-list-redux-hoc example application demonstrates how to use the @resolve-js/redux library to implement a react-redux frontend for a reSolve application.

@resolve-js/react-hooks library​

The @resolve-js/react-hooks library includes React hooks that you can use to connect React components to a reSolve backend. The following hooks are included:

HookDescription
useΠ‘lientReturns the @resolve-js/client library's client object.
useCommandInitializes a command that can be passed to the backend.
useCommandBuilderAllows a component to generate commands based on input parameters.
useViewModelEstablishes a WebSocket connection to a reSolve View Model.
useQueryAllows a component to send queries to a reSolve Read Model or View Model.
useQueryBuilderAllows a component to generate queries based on input parameters.
useOriginResolverResolves a relative path to an absolute URL within the application.
useStaticResolverResolves a relative path to a static resource's full URL.

Example​

The shopping-list-with-hooks example application demonstrates how to use the @resolve-js/react-hooks library to communicate with a reSolve backend.