Skip to main content

Getting Started

Installation

MacOS - Install from Terminal to /usr/local/bin:

curl -fsSL https://nanobus.io/install.sh | /bin/bash

Alternatively, you can also install manually from releases or build from source from this GitHub repo.

Getting Started

Prerequisites

  • Apex CLI: A project template and code generation tool.
  • just: A task runner similar to Make.

Hello World!

Use the apex CLI to start a new project from the starter template:

apex install https://deno.land/x/nanobus_templates/mod.ts
apex list templates
Output
┌──────────────────────┬──────────────────────┬─────────────────────────────────────────────┐
│ Name │ Version │ Description │
└──────────────────────┴──────────────────────┴─────────────────────────────────────────────┘
@nanobus/init v0.0.23 NanoBus barebones Iota
@nanobus/init-ts v0.0.23 NanoBus barebones Iota with TypeScript
@nanobus/tinygo v0.0.23 NanoBus TinyGo Iota
apex new @nanobus/init my-app

The starter template includes up a nanobus configuration with one sample interface and an action that takes an input named name.

id: "my-app"
version: 0.0.1
interfaces:
Greeter:
sayHello:
steps:
- name: Say Hello!
uses: expr
with:
value: '"Hello, " + input.name'

Run our action with the nanobus invoke command with sample input piped from echo:

echo '{"name": "World!"}' | nanobus invoke bus.yaml Greeter::sayHello
Output
"Hello, World!"

Making a web service

To expose our interface to something other than the command line, we use a transport. Transports are ways of attaching interfaces to event-based resources, like a web servers, message queues, or schedulers. There are several transports baked into nanobus.

To spin up an HTTP server, use the transport nanobus.transport.http.server/v1. Use the configuration below to configure it to use port 8080 and use the internal router nanobus.transport.http.router/v1

transports:
http:
uses: nanobus.transport.http.server/v1
with:
address: ":8080"
routers:
- uses: nanobus.transport.http.router/v1
with:
routes:
- method: POST
uri: /hello
handler: Greeter::sayHello

Each route is configured with its method, uri, handler and optional encoding. By default, the encoding is set to the content-type or application/json but you can specify other formats with the encoding property.

Our full configuration now looks like this:

id: "my-app"
version: 0.0.1
transports:
http:
uses: nanobus.transport.http.server/v1
with:
address: ":8080"
routers:
- uses: nanobus.transport.http.router/v1
with:
routes:
- method: POST
uri: /hello
handler: Greeter::sayHello
interfaces:
Greeter:
sayHello:
steps:
- name: Say Hello!
uses: expr
with:
value: '"Hello, " + input.name'

Start our web service by running nanobus and watch nanobus initialize our HTTP server and routes automatically.

nanobus run --debug --developer-mode
Output
INFO    Running in Developer Mode!
INFO Initializing codec {"name": "text/plain", "type": "text/plain"}
INFO Initializing codec {"name": "text/html", "type": "text/html"}
INFO Initializing codec {"name": "json", "type": "json"}
INFO Initializing codec {"name": "msgpack", "type": "msgpack"}
INFO Initializing codec {"name": "cloudevents+avro", "type": "cloudevents+avro"}
INFO Initializing codec {"name": "cloudevents+json", "type": "cloudevents+json"}
INFO Initializing transport {"name": "http"}
INFO Serving route {"uri": "/hello", "methods": "POST", "handler": "Greeter::sayHello"}
INFO HTTP server listening {"address": ":8080"}

Make a request with a tool like curl to see the output:

curl 127.0.0.1:8080/hello \
-H "Content-Type: application/json" \
-d '{"name": "World!"}'
Output (prettified)
{
"type": "permission_denied",
"code": "permission_denied",
"status": 403,
"path": "/hello",
"timestamp": "2023-02-01T15:21:50.067821Z"
}

Permission denied!

An important part of nanobus is making it difficult to cut corners that can lead to catastrophes later. It's too easy to build APIs that ignore authentication and authorization. Adding it as a layer on top of an existing application leads to security holes and major vulnerabilities. Every action in nanobus is deny-by-default. You must explicitly configure what is public and – if it's private – what permissions and roles can access what actions. We haven't run into this error yet because nanobus invoke on the command line bypasses configured auth requirements.

Add an authorization block to our configuration and set up our action as unauthenticated.

authorization:
Greeter:
sayHello:
unauthenticated: true

Our full web service configuration now looks like this:

id: "my-app"
version: 0.0.1
transports:
http:
uses: nanobus.transport.http.server/v1
with:
address: ":8080"
routers:
- uses: nanobus.transport.http.router/v1
with:
routes:
- method: POST
uri: /hello
handler: Greeter::sayHello
authorization:
Greeter:
sayHello:
unauthenticated: true
interfaces:
Greeter:
sayHello:
steps:
- name: Say Hello!
uses: expr
with:
value: '"Hello, " + input.name'

Run it with the command nanobus and issue a curl command to see our output.

curl 127.0.0.1:8080/hello \
-H "Content-Type: application/json" \
-d '{"name": "World!"}'
Output
"Hello, World!"

Congrats! You just put together a web service with nothing more than yaml. We've barely scratched the surface. Extending nanobus with more serious logic is where the power really takes off.