A function oriented, happy way to call APIs from Clojure/Script.
TODO: The ClojureScript part
Calling an API is often a study in incidental complexity
Oh, what a tangled web we weave.
-- Sir Walter Scott
Making a request is easy - clj-http
.
But there is a lot more to it:
Despite this, web APIs are often described as easy. Companies like to pretend it's easy and users like to imagine that it's easy. Nobody talks about the hard parts. This situation often ends with frustration and failure.
Part of the difference between Amazonica and Cognitect is trying to make you think it's a function call, but it's not! Stop pretending. A client with stateful stuff. Call request with a data object.
Getting stuff out. Return or something else?
TODO: insert diagrams
App -secret-> Google
Google -access-> User
User -access-> App
...
App -secret-> Google
...
Google -access-> User
...
User -access-> App
...
Poor API usage:
API usage is often a last resort.
Companies don't want you to use their API! Their priority is to prevent overuse (quotas) and misuse (auth).
API libraries are often out of date, and rarely address user problems. Never concerned with paging or throttling.
A library!
Generate code from the webservice description document (A big JSON file).
TODO: I like the big JSON file, do other companies have these (AWS?)
TODO: Can it be made compatible with things like Swagger?
TODO: Compare, contrast, and learn from https://github.com/cognitect-labs/aws-api
Makes consuming the API a pleasure! I can use my IDE features like "help" and "autocomplete" to quickly make requests with confidence that I got them right.
But there is value in having EVERYTHING be data (we can have both).
Automatically release schema changes?
Oauth2
Credential lookup (looks for secret.json etc... is there a way to encourage encrypting credentials?)
Dynamic var?
There's already a good throttling library (but does it allow rate maximization)? Make it easy to use.
Dynamic var?
There's a retry library, is it enough?
Exceptions vs Errors (Having to deal with both sucks, but they are different, kind of? not really)
This is maybe just error handling and rate maximization? Or a task system? Or something else?
Originally I chose to follow the api organization as closely as possible, but upon reflection I think it would be better to collect resources:
happygapi.youtube.videos/list$
vs happygapi.youtube/videos-list
vs happygapi.youtube/videos$list
list
, get
etc.This could be a non-breaking change by generating BOTH, but I think that would be confusing. Given there probably aren't many users, I plan to just break this.
Pass auth
to every call, or use a global?
I originally chose to pass it to every call, the proper functional choice. But upon reflection I'd rather it be a dynamically bound function.
This could be a non-breaking change by generating BOTH, but I think that would be confusing. Given there probably aren't many users, I plan to just break this.
Should really be a separate library.
This could be a non-breaking change by generating BOTH, but I think that would be confusing. Given there probably aren't many users, I plan to just break this.
Originally some default scopes were included for convenience. But they are arbitrary and bad. I plan to break this.
These seem like they would be helpful
Probably not? Maybe worth discussion.
Maybe API functions should create request maps???
API calls aren't functions
Actually clj-http solves many of these things, we just need some good defaults and a way to customize, except comprehension
Control flow: use nil instead of exceptions (as much as is possible, but what about when it isn't?)
keep happygapi and happy in separate projects to avoid spam diffs
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close