[bisq-network/bisq-docs] Produce the simplest-possible getting started guide for the Bisq HTTP API (#54)

Chris Beams notifications at github.com
Thu May 17 13:01:44 UTC 2018


cbeams commented on this pull request.

NACK. This is already getting close to the mark, @blabno. I got excited walking through this guide myself. As I read and worked through it with my 'new user' hat on, I started to get a sense of the power that this API could afford me, and the possibilities started spinning. Good stuff. We can make it even tighter now, so that it's virtually all signal, no noise, gets the reader in and out quickly with working code at the end, and hungry to do more afterward.

You'll see I've done a fair bit of editing already in my review commits. Please do go through each one, read the commit comment and study the diff so we can align on common practices, style, etc.

I've left a number of review comments below as well, with checkboxes for convenience.

Thanks. I'm stoked about getting this out there for people. And what's great about the way we're doing it is that we can publish this doc literally as soon as this editing process is finished. We don't need to integrate anything into the canonical `bisq-*` repositories, etc. We can get it out there for people to allow them to try this stuff out _right now_, with minimum fuss, such that they can provide provide maximum feedback _before_ we attempt to roll it all up into Bisq proper.

> @@ -0,0 +1,327 @@
+= Monitoring Bisq offers with Http API
+
+This guide walks you through the process of creating a bot that monitors available offers and sends email notifications.

I'd like to drop the email notifications. It makes sense for a script you'd actually want to run in real life, but here in a "let's build the simplest possible bot that could actually work for the purposes of getting our heads around the Bisq HTTP API" guide, all the stuff around GMail and email libraries and usernames and passwords and the code required to bootstrap it all is just noise and makes the whole thing longer and more complicated than it needs to be. As I walked through this guide myself, I punted when I got to this point; I just didn't want to deal. Because: (a) I never use my GMail account, (b) it's set up for 2FA anyway so a simple username / password won't work, (c) I don't want to set up a test account just for the purposes of this guide that told me it would take 15 minutes and is now in fact going to suck up more of my time than I want it to.

As an alternative, just print interesting offers (i.e. those that match the filter) to the command line whenever they show up, or if for some reason that is not idiomatic, then to a file that the user can tail.

> +
+== List available offers
+
+Open offers are available at http://localhost:8080/api/v1/offers.
+
+The response should look like this:
+
+[source,json]
+----
+{
+    "offers": [OfferDetail],
+    "total": integer
+}
+----
+
+Where `offers` is an array with individual offers and `total` is number of all offers. The model for each individual `OfferDetail` is defined as follows:

I'm not sure there's a lot of value in including the whole model here. As a reader, I feel like I'm supposed to _do_ something with this, when in fact it's just for informational purposes. As an alternative, I'd deep-link the user to the swagger API docs that show this same information, and possibly do it in an INFO admonition so that the reader understands this is "just if they care / want to go deeper", and that it's not part of the critical path of the step-by-step guide.

> +Now let's assume that we want to buy bitcoin, and let's define "interesting" offers as those that:
+
+ . sell bitcoin at a discount 1% or more under the current market price, and
+ . accept payment in Euros to a Polish SEPA account
+
+First we need to filter those offers using following static criteria:
+
+[source,json]
+----
+{
+    baseCurrencyCode: 'BTC',
+    counterCurrencyCode: 'EUR',
+    direction: 'SELL',
+    paymentMethodId: 'SEPA'
+}
+----

This result and the "we need to filter those offers" language above again make me as a reader feel like I'm supposed to _do_ something with this information. There is actually no "step" here, it's just for informational / context purposes, and that's fine, but it should be made more clear. For example, you can say something like:

> We'll need to filter our offers using the static criteria you see below:
>
> [json snippet]
>
> In the sections that follow, we'll do just that with a combination of data returned from Bisq HTTP API endpoint calls and programmatic filtering.

(Very quickly written, but you get the idea)

> +In order to get the market price of BTC in EUR, execute the following query:
+
+    curl http://localhost:8080/api/v1/currencies/prices?currencyCodes=EUR
+
+You should receive a response like the following:
+
+[source,json]
+----
+{
+  "prices": {
+    "EUR": 7035.62
+  }
+}
+----
+
+== The JavaScript part

I'd retitle this as something like "Write the monitoring bot code" or "Build the monitoring bot".

"The JavaScript part" sounds boring or like some random detail, whereas "Writing the bot" sounds like what I came here to do.

> +[source,json]
+----
+{
+  "prices": {
+    "EUR": 7035.62
+  }
+}
+----
+
+== The JavaScript part
+
+Let's install some dependencies:
+
+    npm install lodash http-as-promised nodemailer
+
+In general our script will look like this:

In the sections that follow, I recommend that all source code snippets:

- [ ] get sourced from an actual, e.g. 'bisqmon.js' source file checked into the repository. Or perhaps `http-api-monitor-offers.js` to align with the naming of this file. We'll probably need to think more about how to structure companion sources along with these docs in a flat namespace, but it doesn't matter much at this point: what does matter is that the code below should get extracted as snippets from real source code that actually works. Asciidoctor has great tools to help here, see https://asciidoctor.org/docs/user-manual/#include-partial.

 - [ ] get labeled such that they show the name of the file they're coming from (it's fine if all three are labeled as coming from the same file. The point is that this guide needs to be an extremely literal, step-by-step process of going from zero to working code. So if there is code that the user should write, you should tell them where to write it (i.e. in a file named `bisqmon.js`) and in which order to write it. Add this statement, add this function, and that function, and you're done.

> +
+The `getPriceFilter` function creates the actual filter function and looks like this:
+
+[source,javascript]
+----
+function getPriceFilter(marketPrice) {
+    const maxPrice = marketPrice * (1 - threshold) * 10000;
+    return offer => {
+        if (offer.useMarketBasedPrice)
+            return offer.marketPriceMargin >= threshold;
+        return offer.price < maxPrice;
+    }
+}
+----
+
+We are multiplying `marketPrice` by `10000` because that is the format in which the API returns the price.

 - [ ] Somewhere right about here, you should instruct the user to actually run `node bisqmon.js` (or whatever the correct invocation should be), and then show them what they should expect to see as correct output. This is the big payoff. They've hung with us for 15 minutes, reading our instructions, taking in the context, and following each step faithfully. Now they get what they came for: working code that does exactly what we said it would.

> +                counterCurrencyCode: 'EUR',
+                direction: 'SELL',
+                paymentMethodId: 'SEPA'
+            })
+            .filter(i => _.includes(i.acceptedCountryCodes, 'PL'))
+            .filter(getPriceFilter(marketPrice))
+            .map(i => _.pick(i, 'baseCurrencyCode', 'counterCurrencyCode', 'direction', 'paymentMethodId', 'id', 'useMarketBasedPrice', 'price', 'marketPriceMargin', 'amount', 'minAmont'))
+            .map(i => ({amount: i.amount, margin: i.useMarketBasedPrice ? i.marketPriceMargin : marketPrice / i.price}))
+            .value();
+}
+
+Promise.all([getOffers(), getMarketPrice()])
+        .then(filterOffers)
+        .then(notify)
+        .catch(e => console.error(e));
+----

- [ ] As per the comments above re email, I'd yank all of that and just print to the console.

- [ ] It's probably a good idea to recap the whole file here, I agree, so that the reader can take the whole thing in, see that it (a) makes sense, (b) is short, and (c) can easily copy and paste it if they have failed to copy and paste the individual snippets one-by-one in the steps above.

> +                direction: 'SELL',
+                paymentMethodId: 'SEPA'
+            })
+            .filter(i => _.includes(i.acceptedCountryCodes, 'PL'))
+            .filter(getPriceFilter(marketPrice))
+            .map(i => _.pick(i, 'baseCurrencyCode', 'counterCurrencyCode', 'direction', 'paymentMethodId', 'id', 'useMarketBasedPrice', 'price', 'marketPriceMargin', 'amount', 'minAmont'))
+            .map(i => ({amount: i.amount, margin: i.useMarketBasedPrice ? i.marketPriceMargin : marketPrice / i.price}))
+            .value();
+}
+
+Promise.all([getOffers(), getMarketPrice()])
+        .then(filterOffers)
+        .then(notify)
+        .catch(e => console.error(e));
+----
+

 - [ ] This is right where you should have them invoke `node bisqmon.js` (or whatever).

> +                paymentMethodId: 'SEPA'
+            })
+            .filter(i => _.includes(i.acceptedCountryCodes, 'PL'))
+            .filter(getPriceFilter(marketPrice))
+            .map(i => _.pick(i, 'baseCurrencyCode', 'counterCurrencyCode', 'direction', 'paymentMethodId', 'id', 'useMarketBasedPrice', 'price', 'marketPriceMargin', 'amount', 'minAmont'))
+            .map(i => ({amount: i.amount, margin: i.useMarketBasedPrice ? i.marketPriceMargin : marketPrice / i.price}))
+            .value();
+}
+
+Promise.all([getOffers(), getMarketPrice()])
+        .then(filterOffers)
+        .then(notify)
+        .catch(e => console.error(e));
+----
+
+If there are any matching offers you should receive an mail like this:

 - [ ] If email is out of the picture, they'd now see "something like the following" at the command line.

> +        .then(notify)
+        .catch(e => console.error(e));
+----
+
+If there are any matching offers you should receive an mail like this:
+
+    5 interesting BTC offers from Bisq
+    0.0625 BTC (-2%)
+    0.01 BTC (-2%)
+    0.01 BTC (-5%)
+    0.033 BTC (-3%)
+    0.02 BTC (-1.5%)
+    0.25 BTC (-6%)
+
+[NOTE]
+If you would like to use something else that gmail then you will need a bit different mail transport configuration. For reference look at https://nodemailer.com/smtp/.

- [ ] Can be dropped once email is gone.

> @@ -3,6 +3,7 @@
  * *_User Docs_*
  ** <<intro#, Introduction>> — What Bisq is, why it exists and how it works
  ** <<getting-started#, Getting Started>> — Go from zero to trading in 15 minutes
+ ** <<http-api#, Getting Started - HTTP API>> — How to access Bisq programatically

 - [ ] Should be updated to link to actual doc path, and should be titled something more like "Getting Started with the Bisq HTTP API" (especially so long as this is the _only_ entry in this list. If it uses the actual title of the doc as it currently exists here ("Monitoring Bisq offers with Http API"), then it will seem too specific, and readers won't know that they should "START HERE" if they're new to the HTTP API.

> +        .then(notify)
+        .catch(e => console.error(e));
+----
+
+If there are any matching offers you should receive an mail like this:
+
+    5 interesting BTC offers from Bisq
+    0.0625 BTC (-2%)
+    0.01 BTC (-2%)
+    0.01 BTC (-5%)
+    0.033 BTC (-3%)
+    0.02 BTC (-1.5%)
+    0.25 BTC (-6%)
+
+[NOTE]
+If you would like to use something else that gmail then you will need a bit different mail transport configuration. For reference look at https://nodemailer.com/smtp/.

- [ ] Deliver a proper ending to the guide. Right now the ending is a bit abrupt. Wrap things up with a bit of prose (a 'congratulations' is fine), and I often like to do a "next steps" section at this point, where you can direct users to whatever other resources you think they may find most valuable after having just gotten started here. Of course this would include other HTTP API docs and guides as we write them, but it could also include encouraging users to come talk with the team in Slack, to provide feedback on the project via GitHub issues, etc.

> += Monitoring Bisq offers with Http API
+
+This guide walks you through the process of creating a bot that monitors available offers and sends email notifications.
+
+== What you'll build
+
+You'll build a NodeJS-based script that connects to Bisq over an HTTP API to get offers and market prices and sends email notification whenever "interesting" offers are detected.
+
+== What you’ll need
+
+* About 15 minutes
+* A favorite text editor or IDE
+* NodeJS 6+
+* Docker (to run from an image) or Git and Maven (to build from source)
+* A GMail account
+

- [ ] Right about here we should do an INFO admonition that lets the user know that the Bisq HTTP API is currently _incubating_, and that this means things may be a bit rough around the edges, that their feedback is extra appreciated, along with pointers about how to provide that feedback. You may just direct them to the "next steps" section at bottom where they can find out more about providing feedback (see my related comment about 'next steps' below).

> +
+=== Run the API using Docker
+
+The easiest way to run the API in headless mode is by using a Docker image:
+
+    docker run -it --rm -p 8080:8080 -e BISQ_API_HOST=0.0.0.0 bisq/api
+
+=== Run the API from source
+
+For more hard-core developers that want to run from source:
+
+    git clone https://github.com/mrosseel/bisq-api
+    cd bisq-api
+    mvn compile exec:java \
+        -Dexec.mainClass="io.bisq.api.app.ApiMain" \
+        -Dexec.args="--appName=bisqmon"

As I mentioned in 24ffd06, the `--appName` option and arg should be carried over to the `docker` arrangement as well. I have not done that in my edits.

> +=== Run the API using Docker
+
+The easiest way to run the API in headless mode is by using a Docker image:
+
+    docker run -it --rm -p 8080:8080 -e BISQ_API_HOST=0.0.0.0 bisq/api
+
+=== Run the API from source
+
+For more hard-core developers that want to run from source:
+
+    git clone https://github.com/mrosseel/bisq-api
+    cd bisq-api
+    mvn compile exec:java \
+        -Dexec.mainClass="io.bisq.api.app.ApiMain" \
+        -Dexec.args="--appName=bisqmon"
+

- [ ] Right about here we should do an INFO admonition that explains why they're having to run a separate instance of Bisq to experiment with the HTTP API. It's going to be confusing as hell for users who have a perfectly good Bisq client already up and running locally to spin up a different, unrelated instance, unless they have that explained to them. I'd just explain it very clearly in the context of this being an "incubating" project, and that when the the project comes out of incubation, this functionality will be integrated directly into the official Bisq client you run locally. In the meantime, you need to spin up a separate instance to experiment with (and provide feedback on!) this incubating project.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/bisq-network/bisq-docs/pull/54#pullrequestreview-121015031
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.bisq.network/pipermail/bisq-github/attachments/20180517/9d7b20ed/attachment-0002.html>


More information about the github mailing list