Skip to main content

Walkthrough: Build a backend to a React app

Watch a demo video of this project:

Getting started

Darklang allows you to build backends (API endpoints, workers, cron, and data storage) by writing only your business logic, using production traces.

You can access you canvas at (we recommend USERNAME-signin for this project).

First, on that canvas build a hello world API endpoint to get a feel for Darklang:


All the major handlers work the same way, but the key for many requests is working directly with incoming data.

This Guide - Office Sign-in

We’re building this app: It’s an Office Sign-in SPA, built in React. From the form, you pick a host, announce your name as the visitor).

The application backend will have an API, data storage, and asynchronous background workers to talk to external APIs (Twilio & Slack). You will need Twilio & Slack tokens, which we explain how to get below during that portion of the tutorial.

Yours will live at []; to work on it go to [].

Quick start

We’ll need some setup on your machine to upload the react app. Run these commands on OSX to install. To read a longer version explaining what each of these commands do, go here:

Hosting Static Assets in Darklang

Note, replace anywhere that says USERNAME and PASSWORD with your Darklang username and password.

git clone
cd dark-signin
npm install
npm run build-for USERNAME-signin
npm run get-dark-cli
./dark-cli-apple --canvas USERNAME-signin --user USERNAME --password PASSWORD build

If you get “Not found” on the last step, you’ll need to visit [] first in your browser.

Serving Hosted Assets

When you go back to Darklang, your assets will be available (in this case, our compiled Javascript application).


Now, let’s put the assets at the base of our API by creating a new route named / from the omnibox, or the side bar:


Once the route is created, we can specify it’s a GET method, and start writing code.



The finished API will look like this, and you can open it from the hamburger on the right (the tutorial copy is at, and your copy is at


When you open the page it looks like this:


Building the API - Trace Driven Development

Now, we can build a backend based on the frontend we have. The react app has two requirements:

  • GET Hosts - Providing the list of available hosts.
  • POST Visit - Checking in and triggering what needs to happen when a visitor arrives.

Setting Up the /hosts Endpoint (API, Datastore, REPL)

From Darklang, we can see the failed request.


If you do not see a failed request, verify that your host URL in your frontend matches where you’ve hosted the application.

Hit the + button to create the route. The route will have the trace from when we opened the page.


Now we have our endpoint (you can try it out by making a list ["name1", "name2"] and refreshing the React application:


But for the longer term, we’ll need other backend components (in particular a datastore) to support the endpoint.

Create a datastore which lists all hosts. We can create it from the omnibox or the left side bar, and rename it. We can also choose other parameters. In this case, I’ve chosen phone numbers and Slack IDs to send texts and DMs.

Datastores in Darklang are key-value based, not relational. This tutorial will include step by step instructions, but more information on datastores is available here.


We can add data to the datastore by using a REPL, an internal tool for the application.

We can name the REPL (or it will have a default adjective-animal name) and then


When we write DB::set into the handler, we’re given three parameters for the expression. The value, the unique identifier for the record, and the table.

Here’s the finished REPL:


In this case, I chose to define slackid as a variable so I could reuse it as a unique key. You can do this after the fact using Cmd/Ctrl-\ on the value to extract a variable, or just rewrite starting from the top.

Please Use your own name, phone number, and Slack ID. Your Slack ID is found in your profile in the … menu. You will need permission to install Slack apps on a Slack to do this.


Press the “play” button to insert the value into the datastore (more on interactivity with play buttons).

After this, when I select my datastore, I will see that it has locked and has a connection to the REPL, and the number of items/most recent item (if you do not see the DB stats on the left, refreshing the tab should work).


Then, you can update the hosts API to use our data storage.


In this case we did a DB::getAll hosts (and played the request). Then, we took that result (a list of objects) and passed it as a parameter into List::map, then took the name for each host.

To see how this works, click first on DB::getAll to see the list of objects, then click on \val to see an example object, and then will show you the name field. Functional aspects of Darklang has more information on pipelines and maps, but for the tutorial copying this code will work.

If you are stuck:

  1. Make sure to hit the play button for DB::getAll so you’ll have real data.
  2. Shift-enter or |> will open the pipeline.
  3. Typing \ in the block field will open the \val operator.

Setting up the /visits Endpoint (API, Datastore, Workers)

First, we do the same thing and go back to our React application, select a host, then type in a visitor name and hit the “sign in” button. This will result in another 404 that we can create, and see the trace for.


First, we’ll store the visit in a datastore as we did from the REPL when creating hosts. Like before, we can create a new datastore, and then use the DB::set expression.

If we match the datastore schema to our incoming request body, we can do it like this:


If our schema does not match exactly, we can still use our incoming request. Here’s a version that also stores the time of the visit:


In either case, taking advantage of live values and traces is very helpful. When our cursor is in host, we can see what the trace evaluates to for that value on the left-hand side:


Then, as before, we can run the outstanding functions and insert this trace into our datastore (in this case, we’re building from this specific trace. In the future, when a new sign in happened, this handler would run at that time).

If you’re having trouble, make sure you’ve hit the play buttons and do not have red underlines. The finished handler & datastore once you’ve run and inserted the visit will look like this:


Background Workers & External API connections

For this section you will need a Twilio SID & Token and/or a Slack Token, depending on if you want to send Texts, DMs, or both.


To create a new Twilio account, the SID & Token are in your console on the right hand side.


Once you have an account, you’ll need a number that can send texts,


To create a Slack token, go to, create a new application, add a bot from the “basic information” add features & functionality section, and install the app in your workspace. After doing so, you’ll get two tokens back, one of which is the format "xoxb-*".


Twilio Text Message Integration

Back in our post visits handler, hit enter at the end of the line to write more code (This converts our DB::set action into a statement. Not necessary reading now, but more on implicit returns is in the functional aspects of Darklang).

To send information to be used asynchronously (like for API calls) we can use the keyword emit to emit to an async background worker with a queue.

Here, we emit the request.body (seen in a live value on the left) to a worker named sendText. Hitting play will create a 404 for that worker, much like how we created our visit and host endpoints.


When created, the worker will have the event information as a trace:


For this worker, we need to get the host’s phone number and then send them a text. This is very similar to the code we wrote before to get the host’s name.

In this case we use DB::queryOne to get only one response, and look by hostname. Then we can play the query, and make a variable for the field.


The last step is adding the Twilio::sendText function, which takes five parameters. The SID, Token, and number you got from Twilio, the hostphone above, and the message you’d like to send.


When you’ve added yours, it will look like this (but with your tokens).


When you hit “play” on sendText, you will be able to see the API response as a live value, and should receive a text message.


Slack DM Integration

We go back to our /visit endpoint to add the Slack worker. We can even copy most of the code from the beginning of the Twilio handler to get our Slack ID.


For this, we’ll be using Slack’s chat.postMessage API method, which requires the method URL: and pass a header with a content type and a token.

There are built in methods for formatting headers in the HttpClient library.


Finally, we have to make the post request, which takes four parameters, including a body.


You can fill them in as follows from the above code:


When you hit play, you should receive a DM from your Slackbot, as well as an inline API response.


If it isn’t working, check that all parameters (including {} in the query field) are correct, and read the API response message to debug.

That’s it!

Now you should have a working React application with an API, persistent data storage, and asynchronous background workers, hosted at []. When you go back to your React app and submit a new visit, you should receive both a Slack and a Text.

(Interested more in Slack apps? We have a guide for that!)