Skip to main content

Create a new use case

Use case specifies input and result parameters, and error behavior of the API integration. Use case inputs and result should not contain any provider specific parameters and provider implementation details like authentication credentials.

Use cases are defined through a Comlink profile. A profile is a set of use cases that serve the same business need. The Comlink profile is a file with .supr extension.

This guide will walk you through the process of defining a new use case within a Comlink profile. You will use the Superface CLI to bootstrap a new profile and learn the syntax.

Setup

This guide assumes you have set up a Node.js project with Superface and OneSDK. If you need to set up a new project, please see the Setup Guide.

Create New Profile

Choose Profile Name

Profile's name must consist of lowercase letters, numbers, characters, dashes and underscores.

  • Valid: my_profile, myprofile123, my-profile
  • Invalid: my profile, my+profile, MyProfile

While single profile file can contain multiple use cases, we generally recommend to keep single use case per profile. So the profile can be named after the use case, for example:

  • Get weather: get-weather
  • Make payment: make-payment
  • Send email: send-email
Scoped profiles

Profile name can contain scope for grouping profiles together. To scope a profile, add scope-name/ before profile name, for example: communication/send-email.

Bootstrap With CLI

You can use the Superface CLI to set up an empty Comlink profile:

superface create:profile <use_case_name>

Where <use_case_name> is the name of use case you wish to create.

CLI Help

Use the --help flag for more options and examples:

superface create:profile --help

The CLI creates use_case_name.supr file in current directory and links to it from the superface/super.json.

The newly created profile will contain some example content, and it will look like this:

"""
Usecase Name
TODO: What "Usecase Name" does
"""
name = "usecase-name"
version = "1.0.0"
// Comlink Profile specification: https://superface.ai/docs/comlink/profile

"""
Usecase Name
TODO: What "Usecase Name" does
"""
usecase UsecaseName unsafe { // change safety to `safe`, `idempotent` or `unsafe`
input {
"Foo title"
field! string!
}

result {
outputField string
}

error DomainError

example Success {
input {
field = "example"
}
result {
outputField = "result"
}
}

example Fail {
input {
input = "error"
}
error {
title = "Not Found"
detail = "Entity not found"
}
}
}

model DomainError {
"""
Title
A short, human-readable summary of the problem type.
"""
title! string!

"""
Detail
A human-readable explanation specific to this occurrence of the problem.
"""
detail string!
}

Define the use case

With the Comlink profile ready, you can now define your business use case. A "use case" is a task that needs to be done. You can think of it as a function with specified input and output parameters. The use case can also specify its safety.

Overview

Let's take a look at the created use case. At the outer level, the use case is documented with descriptions in triple quotes. The definition itself starts with the usecase keyword, the use case itself is named UsecaseName and is marked as unsafe, which means that executing it may modify something (see below for more info on safety).

The use case consists of three blocks:

  • input with fields required for use case's execution,
  • result with expected fields from successful execution,
  • error describing the fields returned in case of execution error (e.g. due to failure on provider's end).

All these blocks consist of fields. The fields are documented with a single double quote (which is equivalent to triple quote, see descriptions). Most fields have their type defined (i.e. string), but the typing is optional. See Field Types for more information about possible types. Some fields are marked with exclamation mark as required (e.g. field! string), and some are marked as non-null fields (e.g. detail string!).

tip

If you prefer learning by example, you can check the source Comlink profile for all the published use cases in the catalog. Choose a use case and click "raw" to see the code.

Specify Safety of the Use Case

The use case can be marked as safe, unsafe or idempotent. If the safety is not specified, the use case is treated as unsafe by default.

  • safe: The use case doesn't change anything or doesn't perform any action. Generally reading operations can be considered safe, for example retrieving information about shipment or geocoding a postal address.
  • unsafe: The use case changes the world state and its retry may result in unintended side effects. For example, sending an email, or placing an order is unsafe: executing these use cases repeatedly results in sending multiple emails or placing multiple orders.
  • idempotent: The use case can be executed multiple times without changing the result. For example updating an article with the same data multiple times results in the same article.
HTTP Methods

If you are familiar with REST APIs and HTTP methods, you can think of the safety in this manner:

  • safe corresponds to GET and HEAD methods,
  • unsafe corresponds to POST method,
  • idempotent corresponds to PUT and DELETE methods.

For more information see Understanding Idempotency and Safety in API Design.

The safety is defined after the use case's name:

usecase ShipmentInfo safe {}

usecase SendMessage unsafe {}

usecase UpdateProfile idempotent {}

// if safety is not specified, the use case is considered unsafe
usecase SendEmail {}

While the safety information is optional, it can be used by OneSDK to treat the use case in particular manner. For example, the SDK can attempt to automatically repeat a failed request if the use case is safe.

Define Input Fields

To execute the use case, you typically need to provide some input. For example to send a text message, you need at least a recipient's phone number and the message's contents.

In Comlink profile, the use case's input is specified in the input block:

usecase UsecaseName safe {
input {
"Foo title"
field! string!
}
}

The above use case expects an object with one required, non-null input field: field with type string. See the More About Fields section for more information about these features.

If the use case doesn't need any input, the input block can be omitted.

Define Result Fields

Similar to defining the input, use case can describe its output (called result). Our Shipment info use case returns a result object with multiple fields:

usecase ShipmentInfo safe {
// ...
result {
carrier
status
origin
destination

events [{
timestamp
statusText
}]

estimatedDeliveryDate
}
}

In this example, the events field is an array of objects with the fields timestamp and statusText. The fields can also be marked as required and non-null - see More About Fields section.

The result itself can be also a an array or a scalar value:

// result is an array of objects
usecase ShipmentInfoEvents {
result [{
timestamp
statusText
}]
}

// result is a scalar value
usecase ShipmentInfoStatus {
result string
}

Define Error

The use case can define optional error fields. These will be returned when the use case execution fails:

usecase ShipmentInfo safe {
// ...
error {
title
detail
}
}

Add Human-Readable Descriptions

The use case will be consumed by computers, but humans will be the ones integrating the use case into their code. Use cases and definitions in the profile can be preceded by descriptions. A description consists of title and body surrounded either by a single double quote ", or three double quotes """ (triple quotes).

The first description in the profile should explain the overall purpose of the use case. Its title also specifies a human readable name of the profile:

delivery-tracking/shipment-info.supr
"""
Shipment information

Track your shipment. Get the latest information on your shipment status.
"""

name = "delivery-tracking/shipment-info"
version = "1.0.1"

usecase ShipmentInfo safe {}

Both single quotes and triple quotes description can contain both title and a body of the description. In the single quote variant the title is on the same line as quote:

"Retrieve Shipment Status
Get the current shipment status."
usecase ShipmentInfo safe {}

While triple quotes are separated from the description with new lines:

"""
Retrieve Shipment Status
Get the current shipment status.
"""
usecase ShipmentInfo safe {}

Individual fields can be also documented:

usecase ShipmentInfo safe {
input {
"""
Shipment tracking number
Identifier of shipment
"""
trackingNumber

"Carrier
Shipment carrier identification to narrow down the results"
carrier string!
}
}
Single Quote vs. Triple Quote

Both description formats are functionally equivalent so the choice is up to your preference. Our current practice is to use triple quotes for high-level descriptions (for the profile itself and use cases), and single quotes for individual fields. Single quotes are also convenient when you want a single-line description (i.e. just a title).

Add exmples

It is good practice to add examples showing possible inputs and outcome of the use case. You should provide at least one example of a success response, and one example of an error. Examples start with the example keyword, followed by the name of the example. The name of an example should specify its type, eg. Success or Fail. Inside the example block, input values are defined, followed by the outcome (result or error). Structure of input and result or error is defined by the rest of the use case.

More About Fields

In previous steps we have used fields to define contents of input, result and error in the use case. Fields can be defined as required and non-nullable, and can specify some particular type.

Field Types

If possible, define the types of fields your use case accepts or provides in result. The example Shipment Information use case expects the tracking number and carrier identification as strings:

usecase ShipmentInfo safe {
input {
trackingNumber string
carrier string
}
}

The types can be either scalar or collections. Scalar types are primitive values: string, number, boolean. Collections contain other collections or scalars.

Comlink supports the following collections:

  • List

    • Corresponds to Array in JavaScript or List in Python.
    • Uses square brackets, e.g. [string] defines a list of strings.
  • Object

    • Acts as a dictionary with strings for keys.
    • Corresponds to Object in JavaScript or Dictionary in Python.
    • Uses curly brackets, e.g. {myField number} defines an object with single field of type number.

Objects are commonly used to define inputs, results, and errors:

usecase UseCaseName {
input {
inputField string
}
result {
field1 string
field2 number
}
}

Lists can also contain objects, for example the following use case provides a result with a list of objects with fields timestamp and statusText:

usecase ShipmentInfoEvents {
result [{
timestamp string
statusText string
}]
}

Required Fields

By default, all fields are optional. Add ! after the field name to mark it as required. This is especially useful for specifying use case's input to avoid executing the use case unless all required fields are provided:

usecase ShipmentInfo safe {
input {
// Required field with string
trackingNumber! string

// Required, untyped field
carrier!
}
}

Non-null fields

By default, all field can be null. To mark them as non-nullable, add ! after the type definition.

In the following example, if carrier is passed in the input, it must be a string, not null:

usecase ShipmentInfo safe {
input {
trackingNumber! string!
carrier string!
}
}
danger

Note that marking the field as non-nullable doesn't make it required. To make the field required and non-nullable, you must add ! after both the field's name and type.

In the above use case the trackingNumber field is both required, and non-nullable:

usecase UseCaseName {
input {
trackingNumber! string!
}
}

Additional Resources