Skip to content

proper js API#11

Merged
johan-bjareholt merged 6 commits intoActivityWatch:masterfrom
mathieudutour:proper-js-api
Jul 19, 2018
Merged

proper js API#11
johan-bjareholt merged 6 commits intoActivityWatch:masterfrom
mathieudutour:proper-js-api

Conversation

@mathieudutour
Copy link
Copy Markdown
Contributor

  • clearer name for the package (more explicit and drop the js since we know it's an npm package)
  • clean up dependencies
  • convert timestamps to js Date
  • fix a bug causing the baseURL not to be used
  • use an options object argument instead of a list of arguments
  • the methods now returns the data directly instead of the axios response
  • add an ensureBucket method and let the create method fails if the bucket already exists
  • change info to getInfo to be consistent with getBucketInfo
  • change query to accept an array of {start, end} objects instead of a letting the user do the job of creating the string themselves
  • generate the types declarations file

I took the liberty of publishing the package on npm (I don't think you would mind since it's a different name than the one before). Happy to give you all access to it.

Copy link
Copy Markdown
Member

@johan-bjareholt johan-bjareholt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! :)

This PR makes it pretty clear that it's our first time making a API library in JavaScript :p

Just a few minor comments on the change

Before merging this we need to fix compatibility with aw-webui and aw-watcher-vscode. Hopefully the API is good enough after this that we won't have to break compatibility.

Comment thread package.json Outdated
@@ -1,24 +1,25 @@
{
"name": "aw-client-js",
"name": "activity-watch-client",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All other activitywatch libraries are named "aw-x", please don't rename it

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, name should be aw-client

Copy link
Copy Markdown
Contributor Author

@mathieudutour mathieudutour Jul 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just to explain a bit more why I renamed it: I keep reading aw-client as aws-client which also have AWSClient class. I was tempted to rename it to just activity-watch (same reason as for dropping the js). I understand that the other libraries are aw-* but they are mostly internals. I think using a more explicit name would help a lot to improve code readability of third party code where aw-* could co-exist with aws-* (and let's be honest, aws is a giant beast and much more likely to appear ;) )

That being said, happy to change it back if the consensus is to keep aw-client

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aws-client is extremely unlikely to appear in the same codebase as aw-client. aw-client is what we're going with.

Comment thread package.json Outdated
"scripts": {
"compile": "tsc",
"test": "./test.sh"
"compile": "(rm -rf out || true) && tsc",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to rm the dir, so don't.

Comment thread src/aw-client.ts Outdated
} = {};

constructor(clientname: string, testing: boolean, baseurl: string | undefined = undefined) {
constructor(clientname: string, options?: {testing?: boolean, baseURL?: string}) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why options object instead?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aha, so it's rather that the limitation of not being of able to use kwargs in JS can make it hard to read since you cannot annotate the args in a nice manner. In that case it seems sane.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, as a rule of thumb, if you have more than 2 arguments (especially if they are optional), a options object will be more readable

Comment thread src/aw-client.ts

createBucket(bucket_id: string, type: string, hostname: string) {
return this.req.post('/0/buckets/' + bucket_id, {
ensureBucket(bucketId: string, type: string, hostname: string): Promise<{ alreadyExist: boolean }> {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! :)

Comment thread src/aw-client.ts
});
type,
hostname,
}).then(() => undefined);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the point of .then(() => undefined)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

otherwise it's returning the axios response which is an implementation detail and shouldn't be exposed

@johan-bjareholt
Copy link
Copy Markdown
Member

I took the liberty of publishing the package on npm (I don't think you would mind since it's a different name than the one before). Happy to give you all access to it.

It's fine, I'd preferably want a official one named aw-client or aw-client-js later though.
Automatic CI package updates would also be cool.

@ErikBjare
Copy link
Copy Markdown
Member

I took the liberty of publishing the package on npm (I don't think you would mind since it's a different name than the one before). Happy to give you all access to it.

It's fine that you did that given the namechange, but I'm not fine with you being an owner of the official package. I registered a package with the proper name (aw-client): https://www.npmjs.com/package/aw-client

Comment thread README.md Outdated
```sh
npm install
npm run compile
npm install activity-watch-client
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change to npm install aw-client

Comment thread README.md Outdated

```javascript
const aw_client = require('aw-client');
const { AWClient } = require('activity-watch-client');
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, change to require('aw-client')

Comment thread README.md Outdated
const aw_client = require('aw-client');
const { AWClient } = require('activity-watch-client');

const client = new AWCLient(myClientName)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error, should be new AWClient (notice lowercase L).

Comment thread package.json Outdated
@@ -1,24 +1,25 @@
{
"name": "aw-client-js",
"name": "activity-watch-client",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, name should be aw-client

Comment thread package.json
"test": "./test.sh"
"compile": "(rm -rf out || true) && tsc",
"test": "./test.sh",
"prepare": "npm run compile && npm run test"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

Comment thread src/aw-client.ts Outdated
pulsetime: number;
onSuccess: (heartbeat: Heartbeat) => void;
onError: (err: AxiosError) => void;
pulseTime: number;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't camelCase pulsetime anywhere else, so probably shouldn't here either for consistency.

Comment thread src/aw-client.ts Outdated
constructor(clientname: string, options?: {testing?: boolean, baseURL?: string}) {
if (!options) {
options = {}
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assign a default object to the options parameter instead.

Like this:

constructor(clientname: string, options: {testing?: boolean, baseURL?: string} = {})

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not exactly the same: if options is null, the default parameter will not be set. Only when it's undefined.

The default parameter is compiled down to if (typeof options === 'undefined') { options = {} }

Copy link
Copy Markdown
Member

@ErikBjare ErikBjare Jul 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would options ever be null? Passing null to it shouldn't be valid so not a problem.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you never know, it's going to be used by third party devs. Tbh, we should do a proper argument check: verify that the clientname is indeed a string, that the options is indeed an object, and same for all methods and provide useful error message instead of returning the error from the server.
But that's another PR ;)

Copy link
Copy Markdown
Member

@ErikBjare ErikBjare Jul 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If third party devs pass an invalid argument to a function that's their problem. The types are clearly specified, they should know better than to pass in null (and why would they? Makes no sense).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

95% of JS devs don't use types. Believe me, JS makes you do crazy stuff, I've been bitten by it a few time already: you wrap the API with another function that returns null in some cases and boom, you end up looking for 2h why it works in some cases and no others. Not every js library is being nice about null vs undefined.
It's a simple change that doesn't impact us in any way: the code is as readable either way and it can save some headaches so let's do it?

Copy link
Copy Markdown
Member

@ErikBjare ErikBjare Jul 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really think it's unnecessary. Why would you construct an options object by calling a function? Seems like overengineering around the flaws of JavaScript for an obscure case where a developer does something that would be extremely uncommon and bad practice anyway.

Just use the default parameter syntax, it's really not worth the 3 extra lines in this case (but I do appreciate the larger point you're trying to make).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would you construct an options object by calling a function?

Why wouldn't you? I don't think you get to decide what someone is going to do in its code haha.

bad practice anyway

Yes it's bad practice to mix null and undefined but in the past, a lot of libraries didn't really care about the difference and it's not unlikely that someone is going to use one.

it's really not worth the 3 extra lines in this case

You know that it's going to get compiled to something longer in case of the default parameter, right? haha

I really don't think it's a good idea to optimise for code size over developer experience but whatever, it's a not hill I want to die on

@ErikBjare
Copy link
Copy Markdown
Member

Just wanted to say: Huge thanks for making this PR! A lot of great changes! ❤️

@mathieudutour
Copy link
Copy Markdown
Contributor Author

Before merging this we need to fix compatibility with aw-webui and aw-watcher-vscode.

This should be done after merging and publishing, right? I see that now they are using it as a submodules. It would be better to use it as an npm package I believe.

@ErikBjare
Copy link
Copy Markdown
Member

We shouldn't need to fix the compatibility before merging even if they they are used as submodules.

@ErikBjare
Copy link
Copy Markdown
Member

Ready to merge?

@johan-bjareholt johan-bjareholt merged commit a7236f1 into ActivityWatch:master Jul 19, 2018
devzsolt added a commit to devzsolt/aw-watcher-vscode that referenced this pull request Dec 9, 2018
johan-bjareholt pushed a commit to ActivityWatch/aw-watcher-vscode that referenced this pull request Dec 9, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants