Let's make sure you're set up to deploy Unison code to the Cloud and are familiar with the basic workflow. In this exercise, you'll deploy a simple, pre-made HTTP service that responds with a greeting message.

📚 What we'll cover

  • Deploying an HTTP service to the Cloud
  • Identifying a service by hash and by name
  • Log viewing in the Cloud admin panel

🐥 Getting Started

Make sure you've done the following:

Then enter ucm in your terminal to start Unison and authorize your account to run on the Cloud with the auth.login command:

scratch/main> auth.login

Great! Your UCM console is set up to deploy to Unison Cloud.

Create a repository for the cloud-start project and pull the latest release to retrieve the stubs and tests.

scratch/main> project.create-empty cloud-start
cloud-start/main> pull @unison/cloud-start/releases/latest

Editing the deploy function

You'll implement the ex1_quickstart.deploy function, which will deploy a service to the Cloud and return a URI to call it.

📝 Instructions

To get started, run the edit command in the UCM:

cloud-start/main> edit exercises.ex1_quickstart.deploy

Copy the following into your scratch.u file as the deploy function implementation, or follow along with each step below:

exercises.ex1_quickstart.deploy : '{IO, Exception} URI
exercises.ex1_quickstart.deploy = Cloud.main do
  serviceHash = deployHttp exercises.env() ex1_quickstart.helloWorld.logic
  serviceName = ServiceName.named "hello-world"
  ServiceName.assign serviceName serviceHash

The deploy function does the following:

  • It provides the Cloud.main handler for the Cloud ability, so the service can be run on the Cloud
  • It deploys helloWorld.logic as an HTTP service with deployHttp
  • It creates a static name for the service with ServiceName.named
  • It assigns the name to the deployed service with ServiceName.assign

We'll discuss each component in detail next.

🌥️ Handling Cloud interactions

Our goal is to deploy an HTTP service to the web by running a Unison program. This interaction is expressible as a regular program because of the Cloud ability—which is our way of describing interactions with Unison Cloud infrastructure in code.

The first lines of the deploy function need to set us up to interact with the Cloud:

exercises.ex1_quickstart.deploy : '{IO, Exception} URI
exercises.ex1_quickstart.deploy = Cloud.main do
  todo "wip"

Cloud.main is a function from the Unison Cloud client library. It expects a delayed code block, opened with the do keyword. Inside the code block provided to Cloud.main, we can call other functions that create and use Unison Cloud resources.

📦 HTTP services in Unison

Unison HTTP services are functions with the basic form HttpRequest -> HttpResponse.

We've already written the HTTP service you'll be deploying. It's called helloWorld.logic and responds to the path /:name. Its implementation isn't important for now, but the function looks like this:

helloWorld.logic : HttpRequest ->{Exception, Log} HttpResponse
helloWorld.logic = Route.run do
  use Text ++
  name = Route.route GET Parser.text
  info "request for greeting" [("name", name)]
  ok.text ("👋 hello " ++ name ++ "\n")

You can view it in the UCM with:

cloud-start/main> view exercises.ex1_quickstart.helloWorld.logic

Our deployment function should indicate that helloWorld.logic is the service we want to expose. We'll do that by passing it as an argument to the deployHttp function next:

exercises.ex1_quickstart.deploy : '{IO, Exception} URI
exercises.ex1_quickstart.deploy = Cloud.main do
  serviceHash = deployHttp exercises.env() ex1_quickstart.helloWorld.logic
  todo "wip"

deployHttp takes two arguments:

  • An Environment — a way of grouping Cloud resources into a configuration environment for basic access management.
  • The HTTP service to deploy — in this case, helloWorld.logic.

We've provided a helper function, exercises.env, for use in this project. exercises.env is a delayed computation, so it's forced with (), like exercises.env().

deployHttp returns a ServiceHash which we've assigned to a variable.

A ServiceHash is a typed hash that uniquely identifies the service code being deployed.

If you change the implementation of the service argument, (for example, by adding another endpoint, or updating an error message) you'll get a new hash, so a ServiceHash identifies a service deployment by its service code.

🏷️ Assigning the service a name

The final lines of the deploy function create a name for the service with ServiceName.named and assign the service hash to the name with ServiceName.assign.

exercises.ex1_quickstart.deploy : '{IO, Exception} URI
exercises.ex1_quickstart.deploy = Cloud.main do
  serviceHash = deployHttp exercises.env() ex1_quickstart.helloWorld.logic
  serviceName = ServiceName.named "hello-world"
  ServiceName.assign serviceName serviceHash

ServiceName.named creates a human-readable, static name for a service. In this case, we're calling it "hello-world".

ServiceName.assign links the service hash from the previous step to the name we just created. This allows the service implementation to change over time—resulting in a different hash—while the name remains stable. When run, it returns a URI where the HTTP service can be accessed.

Remember to save your scratch file and update your codebase.

cloud-start/main> update

Deployments are kicked off with the run command in the UCM. This will run the deploy function and return a URI you can visit to call the service:

cloud-start/main> run exercises.ex1_quickstart.deploy

😎 Don't forget that the HTTP service expects a path parameter /:name to return a greeting.

For validation, run the submit.ex1_quickstart function in the UCM, which will programmatically call your service and check the response!

cloud-start/main> run submit.ex1_quickstart
Solution

Altogether, your ex1_quickstart.deploy function should look something like this when viewed in the UCM:

exercises.ex1_quickstart.deploy : '{IO, Exception} URI
exercises.ex1_quickstart.deploy = Cloud.main do
  serviceHash = deployHttp exercises.env() ex1_quickstart.helloWorld.logic
  serviceName = ServiceName.named "hello-world"
  ServiceName.assign serviceName serviceHash

📋 Visit the Cloud admin panel

Once your service is deployed, you can view it on the Unison Cloud admin page at app.unison.cloud

You should see your service listed in the "Named Services" tab. Service logs are automatically collected and displayed in the activity tab for the service.

You can use a browser or CURL to call the URI returned by the deploy function since your service is now live! ⭐️