Ohhhhh, I LOVE this question because I got a really hot take on it…
I don’t use "SDK"s anymore… especially if they wrap a simple JSON over HTTP API. Not in Elixir, nor any other language.
JSON over HTTP is simple…
defmodule Github.Api do
use Kestrel, finch: Finch, url: "https://api.github.com"
@impl true
def process_request_headers(headers) do
token = System.get_env("GITHUB_TOKEN")
[{"Authorization", "Bearer #{token}"} | headers]
end
end
iex> Github.Api.get("/repository/MyThing")
There. That’s it. It never goes out of date; it doesn’t matter if GitHub expands or changes their API. It will always work; I never have to wait for a library update or anything.
In a statically typed language, there is some benefit to using a 3rd party SDK so you get compile time guarantees… and arguably there is a benefit to doing the same with Elixir so typespecs + Dialyzer give you some feedback.
But for simple HTTP+JSON in a dynamically typed language… this has served me very well.
And that’s even more true for GraphQL APIs, since SDKs can often be out of date or incomplete (or in Github’s case many SDKs use the old JSON API which doesn’t have as much capability r flexibility as the GraphQL one). Here’s a function to illustrate (taken from a script we use to generate a changelog from all recently closed issues):
def fetch_issues(opts \\ []) do
org = Keyword.get(opts, :org, "my-org")
closed_after = Keyword.get(opts, :closed_after) || Date.add(Date.utc_today, -Keyword.get(opts, :closed_in_last_days, 30))
with token when is_binary(token) and token !="" <- Keyword.get(opts, :github_token) || System.get_env("GITHUB_TOKEN"),
{:ok, %{body: body}} <- Neuron.query("""
query {
search(first: 100, type: ISSUE, query: "org:#{org} state:closed closed:>#{closed_after}") {
issueCount
pageInfo {
hasNextPage
endCursor
}
edges {
node {
... on Issue {
number
# createdAt
# closedAt
title
url
# bodyText
# repository {
# name
# }
labels(first: 100) {
edges {
node {
name
color
}
}
}
assignees(first: 5) {
edges {
node {
login
}
}
}
}
}
}
}
}
""",
nil,
url: "https://api.github.com/graphql",
headers: [authorization: "Bearer #{token}"]) do
body["data"]["search"]["edges"]
|> Enum.map(&Map.get(&1, "node", &1))
else e ->
Logger.error(e)
[]
end
end
If you use Stripe Checkout then your app doesn’t need to handle sensitive payment info. It redirects the user to stripe for checkout and then handles the results of checkout from Stripe webhooks.
I just published a tutorial with the basics of setting it up.