Learn how to add Thin Backend to your ReScript application
This guide covers how to use Thin as the Backend for your ReScript application. This Guide assumes you're using React.js for your view layer.
If you don't have a ReScript project yet, it's easiest to start out with the ReScript + Thin Backend template:
# Clone the template
npx degit digitallyinduced/ihp-backend-rescript-starter my-rescript-app
# Switch to template dir
cd my-rescript-app
# Install deps
npm install
After generating the project, we need to manually configure the BACKEND_URL
to your project's url. For that create a new file .env
and put this into it:
BACKEND_URL=https://<YOUR PROJECTS BACKEND_URL>
You can also add Thin Backend to your existing ReScript project:
First install the ihp-backend
package:
npm install thin-backend
Change your react entrypoint to call IHPBackend.init
:
// Entry point of the application
// This needs to be called before `ReactDOM.render` is called
IHPBackend.init({ host: "https://<YOUR PROJECTS BACKEND_URL>" })
switch(ReactDOM.querySelector("#app")){
| Some(root) => ReactDOM.render(<App />, root)
| None => () // do nothing
}
Wrap your app's main component with the <ThinBackend>
component:
open IHPBackend
@react.component
let make = () => {
<IHPBackend>
<MyAppContent />
</IHPBackend>
}
Add the rescript-ihp-backend
package in bs-dependencies
of your project's bsconfig.json
:
// bsconfig.json
{
// ..
"bs-dependencies": [
"@rescript/react",
"rescript-ihp-backend" // <-- ADD THIS
],
}
The rescript-ihp-backend
dependency provides the type signatures for the ihp-backend
backend. We will install this rescript-ihp-backend
package in a few moments. For now ignore any compiler warnings.
Thin Backend generates ReScript type definitions based on your database schema. The type definitions can be installed into a project by installing a project-specific rescript-ihp-backend
npm package. This npm package is specifically generated for your project and tagged with a secret url, so only you can access it.
To install your project's Types, open the Schema Designer. Click the Type Definitions
tab. Now you see a npm install ..
command:
Run this command locally in your project directory. After that the types will be automatically available in your project.
When you make changes to the database schema, a new type definition package will be generated. To use the latest types, open the Type Definitions
tab again and install the latest package listed there.
Now that the types are installed, your app should be in a runnable state again.
If you've used the ReScript project template, use these commands to start your local dev server:
# Start compiler
npm run rescript:dev
# Start server, Run this in a second terminal window
npm run dev
A good starting point is to display the current logged in user and a logout button in your app. You can use useCurrentUser()
for this.
Create a new file src/UserStatus.res
:
open IHPBackend
@react.component
let make = () => {
let user = useCurrentUser()
let isLoggedIn = useIsLoggedIn()
let onLogoutClick = _ => {
let _ = logout()
}
let onLoginClick = _ => {
let _ = loginWithRedirect()
}
switch isLoggedIn {
| Some(false) => <div>
<button onClick={onLoginClick}>{React.string("Login")}</button>
</div>
| Some(true) => switch user {
| Some(user) => <div>
{React.string(user.email)}
<button onClick={onLogoutClick}>{React.string("Logout")}</button>
</div>
| None => <div>{React.string("Loading")}</div>
}
| None => <div>{React.string("Loading")}</div>
}
}
The logout
function used in the onClick
is provided by Thin Backend. It deletes the locally stored JWT for the current user session and then redirects the user back to the login page.
Call the new UserStatus
component from the App.res
component:
open IHPBackend
@react.component
let make = () => {
<IHPBackend>
<UserStatus/>
</IHPBackend>
}
You can use the useQuery
hook to access your project's database. Let's say your building a todo list app and you've previously created a tasks
table in the Schema Designer. The following code will show all tasks:
// src/Tasks.res
open IHPBackend
open IHPBackend.Task
@react.component
let make = () => {
let tasks = useQuery(queryTasks->orderByCreatedAtDesc)
switch tasks {
| Some(tasks) => Belt.Array.map(tasks, task => <Task key={task.id} task/>)->React.array
| None => React.string("loading")
}
}
The useQuery(query('todos'))
call in our TodoList
sets up a subscription behind the scences. Whenever the result set of our query('todos')
we fired here changes, it will trigger a re-render of our component.
You also need to create a new Task component at src/Task.res
:
// src/Task.res
open IHPBackend
@react.component
let make = (~task: task) => {
<div>{React.string(task.title)}</div>
}
The task
type is provided by Thin Backend and has all fields of your tasks
table.
You can call createSomething(someObject)
insert something into your database:
// src/NewTaskButton.res
open IHPBackend
open IHPBackend.Task
@react.component
let make = () => {
let addTask = _ => {
let _ = createTask({
title: %raw("window.prompt('Enter title')")
})
}
<button onClick={addTask}>{React.string("Add Task")}</button>
}
Don't forget to call this new component from your main component, otherwise it will not show up.
Check out the Database Guide for a full list of all database operations you can do with Thin.
Most of the examples in the docs use JavaScript. Some functions are called a little bit different form ReScript than from JavaScript. Here's a comparison table that might be helpful:
JavaScript | ReScript |
---|---|
|
|
|
|
|
|
|
|
If you check out the compiled JS output of the rescript compiler, you will see that ReScript calls are transformed to the above JS calls.
If you need any help or input, feel free to ask in the Thin Community Forum.
Additional Resources: