on master help sign in
Merge pull request #488 from tylershuster/api-documentation

Api documentation

commit076a745d706d7aaa1b21c3febb70aad8faab659a authorDavid Kerschner <david@tlon.io> dateTue 3 Nov 2020, 14:37 (6 years ago) parente41d26526e4bf3
3 files changed+254−11
content/using/develop.md+29−10 content/using/integrating-api.md+224 templates/index.html+1−1
content/using/develop.md+29−10
@@ -6,7 +6,11 @@ template = "page_indiced.html"
66aliases = ["/docs/using/creating-a-development-ship/", "/docs/getting-started/contributing"]
77+++
88
9−There are roughly two kinds of development on Urbit: core development and application development. Urbit applications are still young, but can be fun to experiment with. The kernel is much more stable, but generally more challenging from an engineering standpoint.
9+You can develop on Urbit in three ways:
10+
11+- [Applications using Urbit](#api), which use Urbit as the back-end to store data and communicate with others
12+- [Urbit Applications](#application), which are written in [Hoon](/docs/glossary/hoon/), and run as part of Urbit
13+- [Urbit Core](#core), which involves contributing to Urbit's operating system ([Arvo](https://github.com/urbit/urbit/tree/master/pkg/arvo)) or runtime ([Vere](https://github.com/urbit/urbit/tree/master/pkg/urbit))
1014
1115This guide will start by getting you set up to run an Urbit ship, and then tell you everything you need to know to do either.
1216
@@ -18,21 +22,23 @@ Once you’re ready, you can get started on the network right away and take some
1822
1923When developing, however, we recommend [booting a development ship](#creating-a-development-ship) and working locally -- you may need to make changes that could, in the wrong hands, destroy the ship’s environment, and it’s best to do so in a safe, separate place.
2024
21−## Core development {#core}
22−
23−Working on the core means improving the Urbit project itself, working with the existing community of Urbit developers.
25+## Applications using Urbit {#api}
2426
25−Just arrived and unsure what to work on? An ideal way to get started is by experimenting with the system, talking to other developers, and reading (or [contributing to](https://github.com/urbit/docs)) the [documentation](/docs/).
27+Urbit ships with its own set of apps written in its own language, Hoon. However it is also meant to integrate with applications written in other languages via an API. The clearest example of an application using Urbit is Landscape, the default client. Although it does currently ship with Urbit, its front-end is a separate piece of software that uses Urbit's HTTP APIs to interact with an Urbit ship. You can create your own application that uses Urbit to store data and interact with other Urbit ships without writing any Hoon code thanks to Urbit's HTTP APIs. This could be a chat client, a writing app, a game, or anything else that can communicate over HTTP.
2628
27−Prefer learning with an instructor? We also offer an online course that covers the basics of Urbit development called [Hoon School](@/community/hoonschool.md). If course-based learning works well for you, we recommend you sign up.
29+To get started quickly with the language of your choice, see the following libraries that provide HTTP interfaces to Urbit:
2830
29−The Urbit developer community congregates around [the urbit-dev mailing list](https://groups.google.com/a/urbit.org/forum/#!forum/dev), the `~bitbet-bolbel/urbit-community` group on Landscape, and [Urbit’s GitHub repository](https://github.com/urbit/urbit). It’s a good idea to sign up, see what people are talking about, and introduce yourself.
31+ - [Python](https://github.com/baudtack/urlock-py) (Stable)
32+ - [Swift](https://github.com/dclelland/UrsusAirlock) (Under development)
33+ - [Haskell](https://github.com/bsima/urbit-airlock) (Under active development)
34+ - [JavaScript](https://www.npmjs.com/package/urbit) (Under active development)
35+ - Go (Pending release)
3036
31−Once you’re comfortable working with Urbit, check out the [project’s issues on GitHub](https://github.com/urbit/urbit/issues) or some of our [contribution bounties](https://grants.urbit.org/).
37+[View details about using the API or creating your own implementation here.](/using/integrating-api/)
3238
33−If you’re looking for some guidance, need help, or would prefer direct communication for your ideas, you can also always reach out to us directly at [support@urbit.org](mailto:support@urbit.org).
39+## Urbit Applications {#application}
3440
35−## Application development {#application}
41+Urbit applications are still young, but can be fun to experiment with.
3642
3743When creating user applications on Urbit, you aren’t tied to any particular user interface. They can work without providing a response to the user, or by printing to the Dojo, or with an interface in Landscape, which uses [Eyre](@/docs/tutorials/arvo/eyre.md) (the Arvo vane that serves HTTP to serve a React-based interface to the application through a web browser).
3844
@@ -40,6 +46,19 @@ When writing applications, you will often make use of [Gall](@/docs/tutorials/ho
4046
4147If you want to see examples of Urbit applications with common functionality requirements, you can see our [examples](https://github.com/urbit/examples) repository. If you want to get started building applications with a Landscape interface, check out our [create-landscape-app](https://github.com/urbit/create-landscape-app) repository.
4248
49+## Urbit Core {#core}
50+
51+Working on the core means improving the Urbit project itself, working with the existing community of Urbit developers. The kernel is much more stable, but generally more challenging from an engineering standpoint.
52+
53+Just arrived and unsure what to work on? An ideal way to get started is by experimenting with the system, talking to other developers, and reading (or [contributing to](https://github.com/urbit/docs)) the [documentation](/docs/).
54+
55+Prefer learning with an instructor? Our community runs an online course that covers the basics of Urbit development called [Hooniversity](https://hooniversity.org/). If course-based learning works well for you, we recommend you sign up.
56+
57+The Urbit developer community congregates around [the urbit-dev mailing list](https://groups.google.com/a/urbit.org/forum/#!forum/dev), the `~bitbet-bolbel/urbit-community` group on Landscape, and [Urbit’s GitHub repository](https://github.com/urbit/urbit). It’s a good idea to sign up, see what people are talking about, and introduce yourself.
58+
59+Once you’re comfortable working with Urbit, check out the [project’s issues on GitHub](https://github.com/urbit/urbit/issues) or some of our [contribution bounties](https://grants.urbit.org/).
60+
61+If you’re looking for some guidance, need help, or would prefer direct communication for your ideas, you can also always reach out to us directly at [support@urbit.org](mailto:support@urbit.org).
4362
4463## Creating a development ship {#creating-a-development-ship}
4564
content/using/integrating-api.mdnew file+224
@@ -0,0 +1,224 @@
1++++
2+title = "Integrating with Urbit for Developers"
3+description = "How to use Urbit's API."
4+weight = 4
5+template = "page_indiced.html"
6++++
7+
8+This guide is aimed at developers who have a working knowledge of HTTP grammar (`PUT`, `GET`), and should not require any special knowledge of Urbit's internals. To learn more about a specific application within Urbit, please search for that with the docs once you have finished this guide.
9+
10+## Authentication
11+
12+The first step in creating an application *on* Urbit (to be distinguished from an Urbit application) is to authenticate with the desired ship. This can be a planet, comet, or any other Urbit ship. For the purposes of this example, we will be running a "fakezod" on port 8080. Run this code, subsituting the appropriate path to your Urbit binary:
13+
14+```bash
15+/path/to/urbit -p 8080 -F zod
16+```
17+
18+(for the unfamiliar, this will create a folder named "zod" in your working directory, from which the ship will run. Use `/path/to/urbit -p 8080 zod` in the future)
19+
20+You can run `+code` in the dojo to get the key, but a fakezod's key is always `lidlut-tabwed-pillex-ridrup`. This is our password, our API token that we will use.
21+
22+Run this code in your bash terminal (requires cURL):
23+
24+```bash
25+curl -i localhost:8080/~/login -X POST -d "password=lidlut-tabwed-pillex-ridrup"
26+```
27+Let's explain what this does:
28+
29+ - `-i` displays the headers, so that you can see the cookie that gets sent
30+ - `localhost:8080/~/login` is the URL to which you are POSTing. You will note this is also the URL you visit when you log into Landscape.
31+ - `-X POST` specifies that you are POSTing data, not GETting.
32+ - `-d "password=lidlut-tabwed-pillex-ridrup"` specifies the key for your Urbit that we retrieved above. It is sent as form data, as if it were sent from an HTML form input field (which it is in Landscape)
33+
34+You should see the following:
35+
36+```bash
37+HTTP/1.1 200 ok
38+Date: Sun, 01 Jan 2020 00:00:00 GMT
39+Connection: keep-alive
40+Server: urbit/vere-0.10.8
41+set-cookie: urbauth-~zod=0v3.fvaqc.nnjda.vude1.vb5l6.kmjmg; Path=/; Max-Age=604800
42+transfer-encoding: chunked
43+```
44+
45+The `Date` and `set-cookie` will be slightly different of course.
46+
47+Take a look at the `set-cookie` line. This is now your session authentication, and will need to be sent with any future requests. It consists of three parts:
48+
49+ - `urbauth` is a prefix that Eyre uses to check for presence of authentication
50+ - `~zod` is the name of the ship you are logging in as
51+ - `0v3.fvaqc.nnjda.vude1.vb5l6.kmjmg` is the actual authentication token.
52+
53+At present there is no way to separate these parts — you must pass a cookie *as* a cookie. This string must be in the `Cookie` header. The `set-cookie` header is only used for this request upon response. It is what browsers expect when receiving a cookie.
54+
55+## Interacting with Urbit
56+
57+Once authenticated, you will perform all your operations on a channel. You may open as many channels as needed using the same authentication token, but this will increase complexity and memory usage on your Urbit ship.
58+
59+Interacting with Urbit comprises two parts:
60+
61+1. Sending information via PUT requests, which receive HTTP status code `204` (no content) upon success. We will not receive updated information (as in a POST request).
62+2. Receiving data on channels, which must first be subscribed to via an initial request. These come in the form of SSEs ([Server-Sent Events](https://www.w3.org/TR/eventsource/))
63+
64+These can be used independently, i.e. you may choose to only send information or only receive information from your Urbit, based on your application. Both can take place on the same channel.
65+
66+### Creating a Channel
67+
68+For this example, we will use the following channel:
69+
70+```
71+http://localhost:8080/~/channel/1601844290-ae45b
72+```
73+
74+Let's exampine the parts. A channel is simply a URL in this pattern: `{url}/~/channel/{uid}` where `{uid}` is a string of your choosing. Most libraries default to the current unix time plus six hexadecimal characters. Your program should determine a channel for its current session and store that in its state.
75+
76+The channel does not yet exist in Urbit, however. To subscribe to events on this URL, you must first make a request (PUT) to Urbit on this URL. The simplest way to do this is to `hi` ourselves, as if we had entered `|hi our` in the dojo. A `hi` is analogous to a ping, and does not manipulate state. Let's learn how to make requests using this as an example.
77+
78+### Making Requests
79+
80+All requests will take the form of sending a message. Messages can take different forms, such as `subscribe`s, `ack`s, and `poke`s. These are called actions and there are more than these, but these will cover most basic use cases. You can think of them as a somewhat more sophisticated HTTP grammar. A messsage always requires an `id` and an `action`. Other fields depend on the specific action.
81+
82+Let's look at the structure of a message by examining the most basic `hi` we will send.
83+
84+```js
85+{
86+ 'id': 1, // Required. A sequential ID. Keep track of which messages you have sent.
87+ 'action': 'poke', // Required. The action to take. poke is the most basic way of sending data, like HTTP POST
88+ 'ship': 'zod', // Required by poke. The ship on which to perform the poke. You can only poke foreign ships with JSON, but this is the authenticated ship.
89+ 'app': 'hood', // Required by poke. The Urbit app to which to send the data.
90+ 'mark': 'helm-hi', // Required by poke. The "mark," or type, of data being sent.
91+ 'json': 'Opening airlock' // Required by poke. The actual data being sent.
92+}
93+```
94+
95+Let's open our channel by sending the following request using cURL (**remember to change the cookie**):
96+
97+```bash
98+curl --header "Content-Type: application/json" \
99+ --cookie "urbauth-~zod=0v3.fvaqc.nnjda.vude1.vb5l6.kmjmg" \
100+ --request PUT \
101+ --data '[{"id":1,"action":"poke","ship":"zod","app":"hood","mark":"helm-hi","json":"Opening airlock"}]' \
102+ http://localhost:8080/~/channel/1601844290-ae45b
103+```
104+
105+If you switch to your fakezod's dojo, you should see `< ~zod: Opening airlock`.
106+
107+Note that in the JSON that we sent via `--data`, the payload is wrapped in `[]`. This is because we can send multiple messages in a single payload, and Eyre expects a list of items, even if we are only sending one.
108+
109+You will always receive a `204` status code if the `PUT` request successfully reached Urbit, authentication succeeded, and the payload was valid. This is merely an HTTP status code, however. If the request failed within Urbit itself, however, you will receive a "nack" event that you will have to process separately.
110+
111+Let's look at how to receive events from Urbit.
112+
113+### Subscribing to Events
114+
115+Now that Urbit has opened an Eyre channel at our URL, we can watch for events on that URL by sending a `subscribe` message. Let's look at the anatomy of a `susbcribe`:
116+
117+```js
118+{
119+ 'id': 2, // Required. This is the next message we are sending, so we give it the next ID.
120+ 'action': 'subscribe', // Required.
121+ 'ship': 'zod', // Required by subscribe.
122+ 'app': 'chat-view', // Required by subscribe. In this case, we want to watch events that occur in the chat-view app, which is responsible for handling incoming chats.
123+ 'path': '/primary' // Required by subscribe. All apps have different path structures. In the case of chat-view, this is where we see all incoming chats.
124+}
125+```
126+
127+This is all we need to send Urbit to say "On this URL through which I am sending information, send me SSEs whenever something occurs on this app at this path."
128+
129+You should be able to send this information if you were able to send the above cURL example. However, we now need to be able to listen to the SSEs. The `EventSource` object is available for JavaScript in the browser context, as this is why SSEs were invented, but there should be a library for it in your chosen language. Take a look at a Browser JavaScript example:
130+
131+```js
132+const eventSource = new EventSource('http://localhost:8080/~/channel/1601844290-ae45b', {
133+ withCredentials: true // Required, sends your cookie
134+});
135+
136+eventSource.addEventListener('message', function (event) {
137+ ack(Number(event.lastEventId)); // See section below
138+ const payload = JSON.parse(event.data); // Data is sent in JSON format
139+ payload.id === event.lastEventId; // The SSE spec includes event IDs. This information is duplicated in the payload.
140+ const data = payload.json; // Beyond this, the actual data will vary between apps
141+});
142+
143+eventSource.addEventListener('error', function (event) {
144+ handleError(event);
145+});
146+
147+```
148+
149+### Handling Received Events
150+
151+Once you have received an event, it is expected that you will "ack" or "acknowledge" that you have received them. To do so, simply send a message in the following format:
152+
153+```js
154+{
155+ 'id': 3, // Required. Picking up where we left off
156+ 'action': 'ack', // Required.
157+ 'event-id': 15, // Required by ack. Whichever SSE of which you are acknowledging receipt
158+}
159+```
160+
161+### Unsubscribing from Events
162+
163+You may want to stop receiving events from a particular app path, but you don't want to close the channel altogether yet. Let's look at how to do that. Take a look at the example for subscribing. We sent that message with `id: 2`. We will use that ID to cancel the relevant subscription:
164+
165+```javascript
166+{
167+ 'id': 4, // Required. We always increment the ID as we send messages.
168+ 'action': 'unsubscribe', // Required.
169+ 'subscription': 2 // Required by unsubscribe. This corresponds to the id of a subscribe message sent earlier.
170+}
171+```
172+
173+### Deleting a Channel
174+
175+You should clean up your channel when able. To do so, simply send a `delete` message and Eyre will handle the rest so your program can safely exit.
176+
177+```javascript
178+{
179+ 'id': 5, // Required.
180+ 'action': 'delete' // Required.
181+}
182+```
183+
184+## Other Operations
185+
186+There are other operations which require authentication but do not require the use of a channel. Some operations are app-specific and will not be enumerated here, but there are two operations that exist across Urbit: `scry` and `spider`.
187+
188+### Scrying
189+
190+Scrying lets you see what an app has exposed at a particular path. It does not manipulate state.
191+
192+It takes the form `{url}/~/scry/{app}{path}.{mark}`
193+
194+ Let's get the base hash of our fakezod in the same way that Landscape does it.
195+
196+```bash
197+curl --header "Content-Type: application/json" \
198+ --cookie "urbauth-~zod=0v3.fvaqc.nnjda.vude1.vb5l6.kmjmg" \
199+ --request GET \
200+ http://localhost:8080/~/scry/file-server/clay/base/hash.json
201+```
202+
203+Note the use of a `GET` request.
204+
205+In this example we're scrying the `file-server` app at the path `/clay/base/hash` and using the `json` mark, which is most common. We receive `"0"` which is correct because we are at the top level of the hierarchy using a fake ship.
206+
207+Scry will fail with a 500 or return a 404 if no data is found.
208+
209+### Running Threads with Spider
210+
211+Running threads is an exception to the rule that we outlined in the section on channels. It uses a `POST` request and both manipulates state and receives information back. It also exposes the ability to send a sequence of commands, i.e. a "thread," hence the name.
212+
213+It takes the form `{url}/spider/{inputMark}/{threadname}/{outputmark}.json`
214+
215+This should be considered an advanced technique, but the basic structure of a request can be seen here:
216+
217+```bash
218+curl --header "Content-Type: application/json" \
219+ --cookie "urbauth-~zod=0v3.fvaqc.nnjda.vude1.vb5l6.kmjmg" \
220+ --request POST \
221+ --data '[{"foo": "bar"}]' \
222+ http://localhost:8080/spider/graph-view-action/graph-create/json.json
223+
224+```
templates/index.html+1−1
@@ -22,7 +22,7 @@
2222
2323<section class="full lh-copy c2-7-md c3-7-lg mt6 mb6">
2424 <p class="mt0 mb4"><strong>Urbit</strong> is a clean-slate OS and network for the 21st century.</p>
25− <p><strong>Urbit OS</strong> is a reimagining of the operating system as an 'overlay OS.'</p>
25+ <p><strong>Urbit OS</strong> is a reimagining of the operating system as an ‘overlay OS.’</p>
2626 <p class="mb4">It's a compact system for an individual to run their own permanent personal server on any Unix machine with an internet connection.</p>
2727 <p class="mb4"><strong>Urbit ID</strong> is a decentralized digital identity system. Your
2828 Urbit ID is a username, network address, and crypto wallet.</p>