An Elixir client for Picnic's unofficial supermarket API.
The API is undocumented and changes without notice; this library is built around that fact. It may break at any time and using it may violate Picnic's terms of service — be a good citizen and don't hammer the endpoints.
Usage
client = Picnic.Client.new(country: :nl)
{:ok, client} = Picnic.login(client, "user@example.com", "password")
{:ok, results} = Picnic.search(client, "melk")
{:ok, cart} = Picnic.add_to_cart(client, "s1019822", count: 2)
{:ok, deliveries} = Picnic.deliveries(client)The client is a plain struct — no process, no global state. Login returns a
new client carrying the token; persist client.auth_token and rebuild with
Picnic.Client.new(auth_token: token) to skip login next time. For managed
auth with automatic re-login, see the optional Picnic.Session.
The escape hatch: request/4
Because the API drifts ahead of any library, the generic passthrough is a first-class part of the public surface, not a debug affordance:
Picnic.request(client, :get, "/user")
Picnic.request(client, :post, "/cart/add_product", json: %{product_id: id, count: 2})It reaches any endpoint — including ones this library hasn't modelled or ones Picnic adds tomorrow. The named functions below are conveniences layered on top of it; they are never the only way in.
Results, drift, and :raw
Every function returns {:ok, result} | {:error, %Picnic.Error{}}; the
bang variants raise the Picnic.Error instead. Results are plain maps by
default. Pass as: :struct for loose typed structs — and note that every
struct keeps the complete, untouched payload under :raw, which is your
lifeline when Picnic ships a field the structs don't know about yet. See
Picnic.Decode for the full drift-handling rules.
Summary
Functions
Adds a product to the cart. See Picnic.Resources.Cart.add/3.
Same as add_to_cart/3 but raises on error.
Empties the cart. See Picnic.Resources.Cart.clear/2.
Same as clear_cart/2 but raises on error.
Lists deliveries. See Picnic.Resources.Deliveries.list/2.
Same as deliveries/2 but raises on error.
Fetches one delivery. See Picnic.Resources.Deliveries.get/3.
Same as delivery/3 but raises on error.
Fetches a delivery's live position. See Picnic.Resources.Deliveries.position/3.
Same as delivery_position/3 but raises on error.
Fetches the shopping cart. See Picnic.Resources.Cart.get/2.
Same as get_cart/2 but raises on error.
Fetches the account profile. See Picnic.Resources.User.get/2.
Same as get_user/2 but raises on error.
Logs in and returns a client carrying the auth token.
Same as login/4 but raises on error.
Fetches one recipe. See Picnic.Resources.Recipes.get/3.
Same as recipe/3 but raises on error.
Lists recipes. See Picnic.Resources.Recipes.list/2.
Same as recipes/2 but raises on error.
Removes a product from the cart. See Picnic.Resources.Cart.remove/3.
Same as remove_from_cart/3 but raises on error.
Generic passthrough to any API endpoint — see the module documentation.
Same as request/4 but raises on error.
Searches the product catalogue. See Picnic.Resources.Search.search/3.
Same as search/3 but raises on error.
Types
@type result() :: {:ok, term()} | {:error, Picnic.Error.t()}
Functions
@spec add_to_cart(Picnic.Client.t(), String.t(), keyword()) :: result()
Adds a product to the cart. See Picnic.Resources.Cart.add/3.
@spec add_to_cart!(Picnic.Client.t(), String.t(), keyword()) :: term()
Same as add_to_cart/3 but raises on error.
@spec clear_cart( Picnic.Client.t(), keyword() ) :: result()
Empties the cart. See Picnic.Resources.Cart.clear/2.
@spec clear_cart!( Picnic.Client.t(), keyword() ) :: term()
Same as clear_cart/2 but raises on error.
@spec deliveries( Picnic.Client.t(), keyword() ) :: result()
Lists deliveries. See Picnic.Resources.Deliveries.list/2.
@spec deliveries!( Picnic.Client.t(), keyword() ) :: term()
Same as deliveries/2 but raises on error.
@spec delivery(Picnic.Client.t(), String.t(), keyword()) :: result()
Fetches one delivery. See Picnic.Resources.Deliveries.get/3.
@spec delivery!(Picnic.Client.t(), String.t(), keyword()) :: term()
Same as delivery/3 but raises on error.
@spec delivery_position(Picnic.Client.t(), String.t(), keyword()) :: result()
Fetches a delivery's live position. See Picnic.Resources.Deliveries.position/3.
@spec delivery_position!(Picnic.Client.t(), String.t(), keyword()) :: term()
Same as delivery_position/3 but raises on error.
@spec get_cart( Picnic.Client.t(), keyword() ) :: result()
Fetches the shopping cart. See Picnic.Resources.Cart.get/2.
@spec get_cart!( Picnic.Client.t(), keyword() ) :: term()
Same as get_cart/2 but raises on error.
@spec get_user( Picnic.Client.t(), keyword() ) :: result()
Fetches the account profile. See Picnic.Resources.User.get/2.
@spec get_user!( Picnic.Client.t(), keyword() ) :: term()
Same as get_user/2 but raises on error.
@spec login(Picnic.Client.t(), String.t(), String.t(), keyword()) :: {:ok, Picnic.Client.t()} | {:error, Picnic.Error.t()}
Logs in and returns a client carrying the auth token.
Accounts with two-factor authentication get
{:error, %Picnic.Error{reason: :two_factor_required}}; pass send_2fa: true
to request the code as part of logging in. See Picnic.Auth for the
handshake.
@spec login!(Picnic.Client.t(), String.t(), String.t(), keyword()) :: Picnic.Client.t()
Same as login/4 but raises on error.
@spec recipe(Picnic.Client.t(), String.t(), keyword()) :: result()
Fetches one recipe. See Picnic.Resources.Recipes.get/3.
@spec recipe!(Picnic.Client.t(), String.t(), keyword()) :: term()
Same as recipe/3 but raises on error.
@spec recipes( Picnic.Client.t(), keyword() ) :: result()
Lists recipes. See Picnic.Resources.Recipes.list/2.
@spec recipes!( Picnic.Client.t(), keyword() ) :: term()
Same as recipes/2 but raises on error.
@spec remove_from_cart(Picnic.Client.t(), String.t(), keyword()) :: result()
Removes a product from the cart. See Picnic.Resources.Cart.remove/3.
@spec remove_from_cart!(Picnic.Client.t(), String.t(), keyword()) :: term()
Same as remove_from_cart/3 but raises on error.
@spec request(Picnic.Client.t(), Picnic.HTTP.method(), String.t(), keyword()) :: result()
Generic passthrough to any API endpoint — see the module documentation.
opts takes anything Req.request/1 accepts, most usefully :json and
:params.
@spec request!(Picnic.Client.t(), Picnic.HTTP.method(), String.t(), keyword()) :: term()
Same as request/4 but raises on error.
@spec search(Picnic.Client.t(), String.t(), keyword()) :: result()
Searches the product catalogue. See Picnic.Resources.Search.search/3.
@spec search!(Picnic.Client.t(), String.t(), keyword()) :: term()
Same as search/3 but raises on error.