Most "pythonic" syntax to use for an API client library

2019-04-28 Thread Jonathan Leroy - Inikup via Python-list
Hi all,

I'm writing a client library for a REST API. The API endpoints looks like this:
/customers
/customers/1
/customers/1/update
/customers/1/delete

Which of the following syntax do you expect an API client library to
use, and why?

1/
api.customers_list()
api.customers_info(1)
api.customers_update(1, name='Bob')
api.customers_delete(1)

2/
api.customers.list()
api.customers.info(1)
api.customers.update(1, name='Bob')
api.customers.delete(1)

3/
api.customers.list()
api.customers(1).info()
api.customers(1).update(name='Bob')
api.customers(1).delete()

...any other?

#3 seems to be more "pretty" to me, but I did not find any "official"
recommendation online.

Thanks.

--
Jonathan.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Most "pythonic" syntax to use for an API client library

2019-04-28 Thread Chris Angelico
On Mon, Apr 29, 2019 at 11:44 AM Jonathan Leroy - Inikup via
Python-list  wrote:
>
> Hi all,
>
> I'm writing a client library for a REST API. The API endpoints looks like 
> this:
> /customers
> /customers/1
> /customers/1/update
> /customers/1/delete
>
> Which of the following syntax do you expect an API client library to
> use, and why?
>
> 1/
> api.customers_list()
> api.customers_info(1)
> api.customers_update(1, name='Bob')
> api.customers_delete(1)
>
> 2/
> api.customers.list()
> api.customers.info(1)
> api.customers.update(1, name='Bob')
> api.customers.delete(1)
>
> 3/
> api.customers.list()
> api.customers(1).info()
> api.customers(1).update(name='Bob')
> api.customers(1).delete()
>
> ...any other?
>
> #3 seems to be more "pretty" to me, but I did not find any "official"
> recommendation online.
>

Well, it's pretty much up to you; all three of these are reasonable.
I'd base a decision on what "api.customers(1)" would mean. Would that
actually have meaning, or would it be merely a placeholder that
remembers "whatever operation you do, do it to customer 1"? If the
latter, I would be inclined to go with option 2, as it clearly shows
that there will be exactly one API call triggered by that. Also,
option 2 lends itself well to a metaprogramming model, where you can
create a "customers" object, a "documents" object, a "transactions"
object, etc, etc, etc, all from the same class, eg via subclassing
(unless they are SO simple that they can all be completely generic).

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Most "pythonic" syntax to use for an API client library

2019-04-28 Thread DL Neil

On 29/04/19 6:58 AM, Jonathan Leroy - Inikup via Python-list wrote:

1/
api.customers_list()
api.customers_info(1)
api.customers_update(1, name='Bob')
api.customers_delete(1)


Dislike this because it mixes point and underscore - easy to mistake!



2/
api.customers.list()
api.customers.info(1)
api.customers.update(1, name='Bob')
api.customers.delete(1)


Prefer this because it 'fits' with module/class notations.



3/
api.customers.list()
api.customers(1).info()
api.customers(1).update(name='Bob')
api.customers(1).delete()


Hate this because it identifies the subject (customers), then requires 
customerID (I presume), then states the action, finally we add any 
adverb(s). In some respects, preference for grouping the two (most) 
variable-items.




...any other?


Well, seeing you ask: a more HTTP-ish approach *might* be:

api.update.customer( 1, name='Bob' )

ie
api.verb.subject( adjectives and adverbs )

Thus:
api_label/intro/ID.what_we're_going_to_do.who/what_we'll_do_it_to( 
customerID, support_data)


Yet, it doesn't really *look right* does it?
(and someone might complain about mixing the 'different' variable-values...)


Doesn't the framework you are using have its own preference?
--
Regards =dn
--
https://mail.python.org/mailman/listinfo/python-list


Re: Most "pythonic" syntax to use for an API client library

2019-04-28 Thread Chris Angelico
On Mon, Apr 29, 2019 at 1:43 PM DL Neil  wrote:
> Well, seeing you ask: a more HTTP-ish approach *might* be:
>
> api.update.customer( 1, name='Bob' )
>
> ie
> api.verb.subject( adjectives and adverbs )
>
> Thus:
> api_label/intro/ID.what_we're_going_to_do.who/what_we'll_do_it_to(
> customerID, support_data)
>
> Yet, it doesn't really *look right* does it?
> (and someone might complain about mixing the 'different' variable-values...)
>

The point here is not to make an HTTP-like interface, but a
Python-like interface :)

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Most "pythonic" syntax to use for an API client library

2019-04-28 Thread DL Neil

On 29/04/19 3:55 PM, Chris Angelico wrote:

On Mon, Apr 29, 2019 at 1:43 PM DL Neil  wrote:

Well, seeing you ask: a more HTTP-ish approach *might* be:

api.update.customer( 1, name='Bob' )

ie
api.verb.subject( adjectives and adverbs )

Thus:
api_label/intro/ID.what_we're_going_to_do.who/what_we'll_do_it_to(
customerID, support_data)

Yet, it doesn't really *look right* does it?
(and someone might complain about mixing the 'different' variable-values...)



The point here is not to make an HTTP-like interface, but a
Python-like interface :)


OK, I'll bite...

...shouldn't the Python-like interface reflect what it is wrapping?


(says he, wrestling with the Kraken and cv2. G!)
--
Regards =dn
--
https://mail.python.org/mailman/listinfo/python-list


Re: Most "pythonic" syntax to use for an API client library

2019-04-28 Thread Chris Angelico
On Mon, Apr 29, 2019 at 2:43 PM DL Neil  wrote:
>
> On 29/04/19 3:55 PM, Chris Angelico wrote:
> > On Mon, Apr 29, 2019 at 1:43 PM DL Neil  
> > wrote:
> >> Well, seeing you ask: a more HTTP-ish approach *might* be:
> >>
> >> api.update.customer( 1, name='Bob' )
> >>
> >> ie
> >> api.verb.subject( adjectives and adverbs )
> >>
> >> Thus:
> >> api_label/intro/ID.what_we're_going_to_do.who/what_we'll_do_it_to(
> >> customerID, support_data)
> >>
> >> Yet, it doesn't really *look right* does it?
> >> (and someone might complain about mixing the 'different' 
> >> variable-values...)
> >>
> >
> > The point here is not to make an HTTP-like interface, but a
> > Python-like interface :)
>
> OK, I'll bite...
>
> ...shouldn't the Python-like interface reflect what it is wrapping?

It should. But if you just want an HTTP-like interface, you don't
really need much of a wrapper. All you need is a hyperthin wrapper
around the requests library - something like:

api.post("customer", {...})
api.get("customer", 1)
api.patch("customer", 1, {...})

And that's fine if what you want is HTTP. But if you want something a
bit more Pythonic, you want something that more adequately represents
the underlying concepts, not the intermediate transport layer. In this
case, the concepts are customers (and, presumably, other types of
queryable information), and the things you can do with them (get info,
update info, enumerate, create).

There may be some useful inspiration to be gained from looking at database ORMs.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Most "pythonic" syntax to use for an API client library

2019-04-28 Thread DL Neil

On 29/04/19 4:52 PM, Chris Angelico wrote:

On Mon, Apr 29, 2019 at 2:43 PM DL Neil  wrote:


On 29/04/19 3:55 PM, Chris Angelico wrote:

On Mon, Apr 29, 2019 at 1:43 PM DL Neil  wrote:

Well, seeing you ask: a more HTTP-ish approach *might* be:

api.update.customer( 1, name='Bob' )

ie
api.verb.subject( adjectives and adverbs )

Thus:
api_label/intro/ID.what_we're_going_to_do.who/what_we'll_do_it_to(
customerID, support_data)

Yet, it doesn't really *look right* does it?
(and someone might complain about mixing the 'different' variable-values...)



The point here is not to make an HTTP-like interface, but a
Python-like interface :)


OK, I'll bite...

...shouldn't the Python-like interface reflect what it is wrapping?


It should. But if you just want an HTTP-like interface, you don't
really need much of a wrapper. All you need is a hyperthin wrapper
around the requests library - something like:

api.post("customer", {...})
api.get("customer", 1)
api.patch("customer", 1, {...})

And that's fine if what you want is HTTP. But if you want something a
bit more Pythonic, you want something that more adequately represents
the underlying concepts, not the intermediate transport layer. In this
case, the concepts are customers (and, presumably, other types of
queryable information), and the things you can do with them (get info,
update info, enumerate, create).

There may be some useful inspiration to be gained from looking at database ORMs.



Yes. I certainly read "thin" into the OP - see also your own comment 
earlier re: "metaprogramming model", which presumed a likelihood of 'more'.


Once bring ORMs, etc, into the equation, then (and depending upon the 
selected tool), recommend maintaining a consistency* to avoid future 
reader-confusion/cognitive-load.


* "hobgoblins" of the world unite!

(having just unravelled some poor soul's vacillation about whether 'it' 
is "width" before "height" or v-v; who then doubled-down by falling into 
the 'where is this-package's Cartesian origin' confusion, aka in which 
direction does *this* y-axis flow?)

--
Regards =dn
--
https://mail.python.org/mailman/listinfo/python-list


Re: Most "pythonic" syntax to use for an API client library

2019-04-28 Thread Albert-Jan Roskam



On 29 Apr 2019 07:18, DL Neil  wrote:

On 29/04/19 4:52 PM, Chris Angelico wrote:
> On Mon, Apr 29, 2019 at 2:43 PM DL Neil  
> wrote:
>>
>> On 29/04/19 3:55 PM, Chris Angelico wrote:
>>> On Mon, Apr 29, 2019 at 1:43 PM DL Neil  
>>> wrote:
 Well, seeing you ask: a more HTTP-ish approach *might* be:

 api.update.customer( 1, name='Bob' )

 ie
 api.verb.subject( adjectives and adverbs )

 Thus:
 api_label/intro/ID.what_we're_going_to_do.who/what_we'll_do_it_to(
 customerID, support_data)

 Yet, it doesn't really *look right* does it?
 (and someone might complain about mixing the 'different' 
 variable-values...)

>>>
>>> The point here is not to make an HTTP-like interface, but a
>>> Python-like interface :)
>>

I recently used Python properties (getter, setter, deleter) for GET, POST/PUT, 
DELETE, respectively. I didn't need any other http methods.


-- 
https://mail.python.org/mailman/listinfo/python-list