lokapi v0.0.17
-- ispell-local-dictionary: "english" --
#+SETUPFILE: ~/.emacs.d/etc/setup/default.setup #+SETUPFILE: ~/.emacs.d/etc/setup/latex.setup #+SETUPFILE: ~/.emacs.d/etc/setup/html-readtheorg-local.setup
#+TITLE: Lokavaluto's LokAPI #+LATEX: \pagebreak
LokAPI is a javascript library intended to be used in mobile applications or web application to abstract all logics with lokavaluto's server.
#+LATEX: \pagebreak #+LATEX: \pagebreak
- Adding =lokapi= to your project
From the root of your project:
#+begin_src sh npm install --save lokapi #+end_src
Or better, as =lokapi= is still in early release,
#+begin_src sh npm install --save Lokavaluto/lokapi#master #+end_src
To be sure to get the latest version, relaunch this last command whenever you want to update.
- Setting up =lokapi=
** Subclassing main LokAPIAbstract
Lokapi will require a way to make HTTP request, access to a permanent store, or various other tasks. Depending on your platform or environment, you might have different way to implement these.
To inject these exchangeable dependency, you are invited to subclass LokAPIAbstract and define these objects:
- httpRequest :: an implementation of =HTTPRequest=
- base64Encode :: a function to encode a string to base64
persistentStore :: an object implementing this interface:
#+begin_src typescript export interface IPersistentStore { get(key: string, defaultValue?: string): string set(key: string, value: string): void del(key: string): void } #+end_src
(optional) requestLogin :: a function to trigger a login screen on authorization failed.
** Instanciating lokapi
On instantiation time, =LokAPI= class will require you to provide:
host :: as a =string= (example: "lokavaluto.fr")
database :: as a =string= (example: "myodoodb")
*** Example for node
Using node's core =https= as HTTP requestion implementation:
#+begin_src typescript
import https from "https"
import { LokAPIAbstract, e as LokAPIExc, t as LokAPIType } from "lokapi"
class cookieStore implements LokAPIType.IPersistentStore { constructor() { VueCookieNext.config({ expire: '7d' }) } get(key: string, defaultValue?: string): string { return VueCookieNext.getCookie("lokapi" + key) } set(key: string, value: string): void { VueCookieNext.setCookie("lokapi" + key, value) } del(key: string): void { VueCookieNext.removeCookie("lokapi_" + key) } }
class NodeLokAPI extends LokApiAbstract {
httpRequest = (opts: LokAPIType.coreHttpOpts) => {
if (opts.protocol !== 'https') {
throw new Error(`Protocol ${opts.protocol} unsupported by this implementation`)
}
const httpsOpts: LokAPIType.coreHttpOpts = {
host: opts.host,
path: opts.path,
method: opts.method,
headers: opts.headers,
}
return new Promise((resolve, reject) => {
let req = https.request(httpsOpts, (res) => {
const { statusCode } = res
let rawData = ''
res.on('data', (chunk) => { rawData += chunk })
res.on('end', () => {
if (!statusCode || statusCode.toString().slice(0, 1) !== '2') {
res.resume();
reject(new LokAPIExc.HttpError(statusCode, res.statusMessage, "", res))
return
} else {
resolve(rawData)
}
});
})
if (opts.data) req.write(JSON.stringify(opts.data))
req.end();
req.on('error', (err) => {
console.error(`Encountered an error trying to make a request: ${err.message}`);
reject(new LokAPIExc.RequestFailed(err.message))
});
})
}
base64Encode = (s: string) => Buffer.from(s).toString('base64')
persistentStore = new cookieStore()
}
if (!process.env.VUE_APP_LOKAPI_HOST) { throw new Error("Please specify VUE_APP_LOKAPI_HOST in '.env'") }
if (!process.env.VUE_APP_LOKAPI_DB) { throw new Error("Please specify VUE_APP_LOKAPI_DB in '.env'") }
var lokAPI = new LokAPI( process.env.VUE_APP_LOKAPI_HOST, process.env.VUE_APP_LOKAPI_DB, ) #+end_src
*** Example for =nativescript=
Using =@nativescript-community/https= as HTTP request implementation:
#+begin_src typescript import * as https from '@nativescript-community/https';
import { LokAPIAbstract, e as LokAPIExc, t as LokAPIType } from "lokapi"
import { getString, remove as removeSetting, setString } from '@nativescript/core/application-settings';
class applicationSetting implements LokAPIType.IPersistentStore { get(key: string, defaultValue?: string): string { return getString("lokapi" + key, defaultValue) } set(key: string, value: string): void { setString("lokapi" + key, value) } del(key: string): void { removeSetting(key) } }
class NativeLokAPI extends LokAPIAbstract {
httpRequest = async (opts: LokAPIType.coreHttpOpts) => {
const nativeRequestOpts = {
url: opts.protocol + "://" + opts.host + opts.path,
method: opts.method,
headers: opts.headers,
body: opts.data,
useLegacy: true,
}
let response
try {
response = await https.request(nativeRequestOpts)
} catch (err) {
console.error(
`Encountered an error trying to make a request: ${err.message}`);
reject(new LokAPIExc.RequestFailed(err.message))
}
const statusCode = response.statusCode;
let rawData = await response.content.toStringAsync();
if (!statusCode || statusCode.toString().slice(0, 1) !== '2') {
throw new LokAPIExc.HttpError(statusCode, response.reason, "", response)
}
return rawData
}
base64Encode = base64Encode
persistentStore = new applicationSetting()
}
var lokAPI = new NativeLokAPI(APP_HOST, APP_DB)
#+end_src
- Usage
** Login
You must log in to the server with an existing Odoo Lokavaluto account:
#+begin_src typescript await lokApi.login("myuser", "mypassword") #+end_src
** Accessing accounts
We assume that you've instanciated =LokAPI= as stated in the previous section, and you have logged in.
#+begin_src typescript let accounts = await lokAPI.getAccounts()
let balance = await accounts0.getBalance() let symbol= await accounts0.getSymbol()
console.log(balance in first account: ${balance} ${symbol}
)
#+end_src
=backend.getAccounts()= is the list of accounts in that connection (warning, this is a promise).
=account.getBalance()= is the balance of the account
=account.getSymbol()= is the currency symbol for the account
** Looking for recipients
Recipient are possible receiving end of a transfer of
money. These are connected to identities in lokapi
.
#+begin_src typescript let recipients = await lokAPI.searchRecipients("Alain")
recipients.forEach(recipient => {
console.log(name: ${recipient.name}
)
})
#+end_src
** Transfer money between an account to a recipient
Transfering money is done from an account of the logged-in user to a recipient:
#+begin_src typescript // Get my accounts let accounts = await lokAPI.getAccounts()
// Fetch recipients named 'Alain' let recipients = await lokAPI.searchRecipients("Alain")
await lokAPI.transfer(accounts0, recipients0, "12", "Dinner Party participation") // or: await accounts0.transfer(recipients0, "13", "Coffee")
#+end_src
** Requesting info on given partner
The method =lokAPI.getUserInfo(userId?: number)= allows you to get back user info given it's user id. If you don't provide this user id, you'll get your own information. This is useful especially if you don't know yet your own =userId=:
#+begin_src typescript
let partnerId = 9
let userInfo = await lokAPI.getUserInfo(partnerId)
console.log(Partner 9 name: ${userInfo.name}
)
// My own information
let myOwnInfo = await lokAPI.getUserInfo()
console.log(My user id: ${myOwnInfo.id}
)
#+end_src
** Setting/Unsetting Favorite status of a contact
You can set or unset the "favorite" state of a given contact with the =lokAPI.setFavorite(..)=, =lokAPI.unsetFavorite(..)=, or =lokAPI.toggleFavorite(..)= method. The argument can be a recipient (from =.searchRecipients()=) or a contact (from =.getUserInfo()=).
It'll return a new contact with the updated information.
#+begin_src typescript let recipients = await lokAPI.searchRecipients("Alain")
await lokAPI.setFavorite(recipients2) await lokAPI.unsetFavorite(recipients3) #+end_src
** List transactions
List past transactions for the current logged in user.
#+begin_src typescript let transactions = await $lokapi.getTransactions()
transactions.forEach((tr:any) => {
console.log(${tr.date} ${tr.amount} ${tr.currency}
)
})
#+end_src
** Direct request to odoo api
You can use =lokapi= instance to query directly the odoo api trough the =get=, =post=, =put=, =delete= methods and their authenticated counterparts, =$get=, =$post=, =$put=, =$delete=.
#+begin_src typescript
// All 8 methods have this signature: // type restMethod = (path: string, data?: any, headers?: any) => any
// Notice that the next call is an example, but you don't need to // use this endpoint as it is used by the lokAPI.login() and // manages token for you. lokAPI.post('/auth/authenticate', { api_version: 2, db: 'mydb', params: 'lcc_app' }, { 'Authorization': '', })
lokAPI.$post(/partner/${userId}
)
lokAPI.$post(/partner/favorite
)
lokAPI.$post(/partner/${userId}/toggle_favorite
)
#+end_src