Skip to content

Commit

Permalink
Add UsageRecords and bump version
Browse files Browse the repository at this point in the history
  • Loading branch information
PJUllrich committed Jun 25, 2024
1 parent d3fe344 commit 1c0cf4c
Show file tree
Hide file tree
Showing 22 changed files with 194 additions and 86 deletions.
4 changes: 2 additions & 2 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
elixir 1.15.7-otp-26
erlang 26.1.2
elixir 1.17.1-otp-27
erlang 27.0
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## v0.2.3 - 2024-06-25

* Add `UsageRecords` endpoints.
* Accept the API-key as a request option in all endpoints.
* Add a Livebook for easier local testing of endpoints.

## v0.2.2

* Add `first_subscription_item` to Subscriptions
Expand Down
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ An Elixir client for the API and Webhooks of LemonSqueezy.
```elixir
def deps do
[
{:lemon_ex, "~> 0.2.2"}
{:lemon_ex, "~> 0.2.3"}
]
end
```
Expand All @@ -21,14 +21,20 @@ To make API calls, you need to create an [API key](https://docs.lemonsqueezy.com
```elixir
import Config

config :lemon_ex,
config :lemon_ex,
api_key: System.get_env("LEMONSQUEEZY_API_KEY"),
webhook_secret: System.get_env("LEMONSQUEEZY_WEBHOOK_SECRET"),
# (Optional) You can provide HTTPoison options which are added to every request.
# See all options here: https://hexdocs.pm/httpoison/HTTPoison.Request.html#content
request_options: [timeout: 10_000]
```

Alternatively, you can also pass the `api_key` as an option when you make a request, like this:

```elixir
LemonEx.UsageRecords.list([], [api_key: "your-api-key"])
```

If you don't provide a valid API key, you will receive `401: Unauthorized` error responses.

## Making Requests
Expand Down Expand Up @@ -139,11 +145,15 @@ You can use [ngrok](https://ngrok.com/) to proxy webhook events to your `localho

1. Install `ngrok` with e.g. `brew install --cask ngrok`
2. Start `ngrok` with `ngrok http 4000`
3. Copy the URL behind `Forwarding` that looks like this: `https://{identifier_here}.eu.ngrok.io`
3. Copy the URL behind `Forwarding` that looks like this: `https://{identifier_here}.eu.ngrok.io`
4. Create a new Webhook in [LemonSqueezy](https://app.lemonsqueezy.com/settings/webhooks) that points to the copied URL plus your endpoint. For example: `https://{identifier}.eu.ngrok.io/webhooks/lemonsqueezy`
5. Start your Phoenix application and enjoy!
6. (Optional): View the event payload in the `Ngrok Inspector` at [http://localhost:4040](http://localhost:4040)

## Testing Endpoints locally

You can use the `testing.livemd` Livebook to test LemonEx endpoints locally. Simply start the Livebook, add your test api key as `LEMON_EX_API_KEY` to the livebook, and start testing.

## Todos

- [x] Add all schema objects
Expand Down
12 changes: 6 additions & 6 deletions lib/lemon_ex/checkouts/checkouts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule LemonEx.Checkouts do
alias LemonEx.Request
alias LemonEx.PaginatedResponse

def create(store_id, variant_id, attributes) do
def create(store_id, variant_id, attributes, opts \\ []) do
data = %{
type: "checkouts",
attributes: attributes,
Expand All @@ -25,19 +25,19 @@ defmodule LemonEx.Checkouts do

payload = %{data: data}

with {:ok, %{"data" => body}} <- Request.post("/checkouts", payload) do
with {:ok, %{"data" => body}} <- Request.post("/checkouts", payload, opts) do
{:ok, Checkout.from_json(body)}
end
end

def get(id) do
with {:ok, %{"data" => body}} <- Request.get("/checkouts/#{id}") do
def get(id, opts \\ []) do
with {:ok, %{"data" => body}} <- Request.get("/checkouts/#{id}", opts) do
{:ok, Checkout.from_json(body)}
end
end

def list(filter \\ []) do
with {:ok, body} <- Request.get("/checkouts", filter) do
def list(filter \\ [], opts \\ []) do
with {:ok, body} <- Request.get("/checkouts", filter, opts) do
{:ok, PaginatedResponse.from_json(body, Checkout)}
end
end
Expand Down
8 changes: 4 additions & 4 deletions lib/lemon_ex/customers/customers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ defmodule LemonEx.Customers do
alias LemonEx.Request
alias LemonEx.PaginatedResponse

def get(id) do
with {:ok, %{"data" => body}} <- Request.get("/customers/#{id}") do
def get(id, opts \\ []) do
with {:ok, %{"data" => body}} <- Request.get("/customers/#{id}", opts) do
{:ok, Customer.from_json(body)}
end
end

def list(filter \\ []) do
with {:ok, body} <- Request.get("/customers", filter) do
def list(filter \\ [], opts \\ []) do
with {:ok, body} <- Request.get("/customers", filter, opts) do
{:ok, PaginatedResponse.from_json(body, Customer)}
end
end
Expand Down
8 changes: 4 additions & 4 deletions lib/lemon_ex/discount_redemptions/discount_redemptions.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ defmodule LemonEx.DiscountRedemptions do
alias LemonEx.Request
alias LemonEx.PaginatedResponse

def get(id) do
with {:ok, %{"data" => body}} <- Request.get("/discount-redemptions/#{id}") do
def get(id, opts \\ []) do
with {:ok, %{"data" => body}} <- Request.get("/discount-redemptions/#{id}", opts) do
{:ok, DiscountRedemption.from_json(body)}
end
end

def list(filter \\ []) do
with {:ok, body} <- Request.get("/discount-redemptions", filter) do
def list(filter \\ [], opts \\ []) do
with {:ok, body} <- Request.get("/discount-redemptions", filter, opts) do
{:ok, PaginatedResponse.from_json(body, DiscountRedemption)}
end
end
Expand Down
20 changes: 10 additions & 10 deletions lib/lemon_ex/discounts/discounts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule LemonEx.Discounts do
alias LemonEx.Request
alias LemonEx.PaginatedResponse

def create(store_id, attributes) do
def create(store_id, attributes, opts \\ []) do
data = %{
type: "discounts",
attributes: attributes,
Expand All @@ -19,34 +19,34 @@ defmodule LemonEx.Discounts do

payload = %{data: data}

with {:ok, %{"data" => body}} <- Request.post("/discounts", payload) do
with {:ok, %{"data" => body}} <- Request.post("/discounts", payload, opts) do
{:ok, Discount.from_json(body)}
end
end

def get(id) do
with {:ok, %{"data" => body}} <- Request.get("/discounts/#{id}") do
def get(id, opts \\ []) do
with {:ok, %{"data" => body}} <- Request.get("/discounts/#{id}", opts) do
{:ok, Discount.from_json(body)}
end
end

def list(filter \\ []) do
with {:ok, body} <- Request.get("/discounts", filter) do
def list(filter \\ [], opts \\ []) do
with {:ok, body} <- Request.get("/discounts", filter, opts) do
{:ok, PaginatedResponse.from_json(body, Discount)}
end
end

def update(id, data) do
def update(id, data, opts \\ []) do
data = Map.merge(%{type: "discounts", id: to_string(id)}, data)
payload = %{data: data}

with {:ok, %{"data" => body}} <- Request.patch("/discounts/#{id}", payload) do
with {:ok, %{"data" => body}} <- Request.patch("/discounts/#{id}", payload, opts) do
{:ok, Discount.from_json(body)}
end
end

@spec delete(any()) :: :ok | {:error, integer(), any()} | {:error, any()}
def delete(id) do
Request.delete("/discounts/#{id}")
def delete(id, opts \\ []) do
Request.delete("/discounts/#{id}", opts)
end
end
8 changes: 4 additions & 4 deletions lib/lemon_ex/files/files.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ defmodule LemonEx.Files do
alias LemonEx.Request
alias LemonEx.PaginatedResponse

def get(id) do
with {:ok, %{"data" => body}} <- Request.get("/files/#{id}") do
def get(id, opts \\ []) do
with {:ok, %{"data" => body}} <- Request.get("/files/#{id}", opts) do
{:ok, File.from_json(body)}
end
end

def list(filter \\ []) do
with {:ok, body} <- Request.get("/files", filter) do
def list(filter \\ [], opts \\ []) do
with {:ok, body} <- Request.get("/files", filter, opts) do
{:ok, PaginatedResponse.from_json(body, File)}
end
end
Expand Down
8 changes: 4 additions & 4 deletions lib/lemon_ex/license_keys/license_keys.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ defmodule LemonEx.LicenseKeys do
alias LemonEx.Request
alias LemonEx.PaginatedResponse

def get(id) do
with {:ok, %{"data" => body}} <- Request.get("/license-keys/#{id}") do
def get(id, opts \\ []) do
with {:ok, %{"data" => body}} <- Request.get("/license-keys/#{id}", opts) do
{:ok, LicenseKey.from_json(body)}
end
end

def list(filter \\ []) do
with {:ok, body} <- Request.get("/license-keys", filter) do
def list(filter \\ [], opts \\ []) do
with {:ok, body} <- Request.get("/license-keys", filter, opts) do
{:ok, PaginatedResponse.from_json(body, LicenseKey)}
end
end
Expand Down
8 changes: 4 additions & 4 deletions lib/lemon_ex/order_items/order_items.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ defmodule LemonEx.OrderItems do
alias LemonEx.Request
alias LemonEx.PaginatedResponse

def get(id) do
with {:ok, %{"data" => body}} <- Request.get("/order-items/#{id}") do
def get(id, opts \\ []) do
with {:ok, %{"data" => body}} <- Request.get("/order-items/#{id}", opts) do
{:ok, OrderItem.from_json(body)}
end
end

def list(filter \\ []) do
with {:ok, body} <- Request.get("/order-items", filter) do
def list(filter \\ [], opts \\ []) do
with {:ok, body} <- Request.get("/order-items", filter, opts) do
{:ok, PaginatedResponse.from_json(body, OrderItem)}
end
end
Expand Down
8 changes: 4 additions & 4 deletions lib/lemon_ex/orders/orders.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ defmodule LemonEx.Orders do
alias LemonEx.Request
alias LemonEx.PaginatedResponse

def get(id) do
with {:ok, %{"data" => body}} <- Request.get("/orders/#{id}") do
def get(id, opts \\ []) do
with {:ok, %{"data" => body}} <- Request.get("/orders/#{id}", opts) do
{:ok, Order.from_json(body)}
end
end

def list(filter \\ []) do
with {:ok, body} <- Request.get("/orders", filter) do
def list(filter \\ [], opts \\ []) do
with {:ok, body} <- Request.get("/orders", filter, opts) do
{:ok, PaginatedResponse.from_json(body, Order)}
end
end
Expand Down
8 changes: 4 additions & 4 deletions lib/lemon_ex/products/products.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ defmodule LemonEx.Products do
alias LemonEx.Request
alias LemonEx.PaginatedResponse

def get(id) do
with {:ok, %{"data" => body}} <- Request.get("/products/#{id}") do
def get(id, opts \\ []) do
with {:ok, %{"data" => body}} <- Request.get("/products/#{id}", opts) do
{:ok, Product.from_json(body)}
end
end

def list(filter \\ []) do
with {:ok, body} <- Request.get("/products", filter) do
def list(filter \\ [], opts \\ []) do
with {:ok, body} <- Request.get("/products", filter, opts) do
{:ok, PaginatedResponse.from_json(body, Product)}
end
end
Expand Down
34 changes: 20 additions & 14 deletions lib/lemon_ex/request.ex
Original file line number Diff line number Diff line change
@@ -1,39 +1,43 @@
defmodule LemonEx.Request do
@api_base_url "https://api.lemonsqueezy.com/v1"

@spec post(binary(), any()) :: {:ok, map()} | {:error, any()} | {:error, integer(), any()}
def post(url, payload) do
headers = get_headers()
@spec post(binary(), any(), keyword()) ::
{:ok, map()} | {:error, any()} | {:error, integer(), any()}
def post(url, payload, opts \\ []) do
headers = get_headers(opts)
url = "#{@api_base_url}#{url}"
payload = prepare_payload(payload)
opts = request_options()
response = HTTPoison.post(url, payload, headers, opts)
handle_response(response)
end

@spec get(binary(), keyword()) :: {:ok, map()} | {:error, any()} | {:error, integer(), any()}
def get(url, params \\ []) do
headers = get_headers()
@spec get(binary(), keyword(), keyword()) ::
{:ok, map()} | {:error, any()} | {:error, integer(), any()}
def get(url, params \\ [], opts \\ []) do
headers = get_headers(opts)
url = "#{@api_base_url}#{url}"
params = prepare_params(params)
opts = [params: params] ++ request_options()
response = HTTPoison.get(url, headers, opts)
handle_response(response)
end

@spec patch(binary(), any()) :: {:ok, map()} | {:error, any()} | {:error, integer(), any()}
def patch(url, payload) do
headers = get_headers()
@spec patch(binary(), any(), keyword()) ::
{:ok, map()} | {:error, any()} | {:error, integer(), any()}
def patch(url, payload, opts \\ []) do
headers = get_headers(opts)
url = "#{@api_base_url}#{url}"
payload = prepare_payload(payload)
opts = request_options()
response = HTTPoison.patch(url, payload, headers, opts)
handle_response(response)
end

@spec delete(binary()) :: :ok | {:ok, map()} | {:error, any()} | {:error, integer(), any()}
def delete(url) do
headers = get_headers()
@spec delete(binary(), keyword()) ::
:ok | {:ok, map()} | {:error, any()} | {:error, integer(), any()}
def delete(url, opts \\ []) do
headers = get_headers(opts)
url = "#{@api_base_url}#{url}"
opts = request_options()
response = HTTPoison.delete(url, headers, opts)
Expand All @@ -48,9 +52,11 @@ defmodule LemonEx.Request do
Application.get_env(:lemon_ex, :request_options, [])
end

defp get_headers do
defp get_headers(opts) do
bearer_token = Keyword.get(opts, :api_key, api_key())

[
{"Authorization", "Bearer #{api_key()}"},
{"Authorization", "Bearer #{bearer_token}"},
{"Accept", "application/vnd.api+json"},
{"Content-Type", "application/vnd.api+json"}
]
Expand Down
8 changes: 4 additions & 4 deletions lib/lemon_ex/stores/stores.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ defmodule LemonEx.Stores do
alias LemonEx.Request
alias LemonEx.PaginatedResponse

def get(id) do
with {:ok, %{"data" => body}} <- Request.get("/stores/#{id}") do
def get(id, opts \\ []) do
with {:ok, %{"data" => body}} <- Request.get("/stores/#{id}", opts) do
{:ok, Store.from_json(body)}
end
end

def list(filter \\ []) do
with {:ok, body} <- Request.get("/stores", filter) do
def list(filter \\ [], opts \\ []) do
with {:ok, body} <- Request.get("/stores", filter, opts) do
{:ok, PaginatedResponse.from_json(body, Store)}
end
end
Expand Down
8 changes: 4 additions & 4 deletions lib/lemon_ex/subscription_invoices/subscription_invoices.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ defmodule LemonEx.SubscriptionInvoices do
alias LemonEx.Request
alias LemonEx.PaginatedResponse

def get(id) do
with {:ok, %{"data" => body}} <- Request.get("/subscription-invoices/#{id}") do
def get(id, opts \\ []) do
with {:ok, %{"data" => body}} <- Request.get("/subscription-invoices/#{id}", opts) do
{:ok, SubscriptionInvoice.from_json(body)}
end
end

def list(filter \\ []) do
with {:ok, body} <- Request.get("/subscription-invoices", filter) do
def list(filter \\ [], opts \\ []) do
with {:ok, body} <- Request.get("/subscription-invoices", filter, opts) do
{:ok, PaginatedResponse.from_json(body, SubscriptionInvoice)}
end
end
Expand Down
Loading

0 comments on commit 1c0cf4c

Please sign in to comment.