The document discusses building a simple payment page using Elixir and Stripe. It describes setting up a Stripe client in Elixir to communicate with the Stripe API, building a UI to accept payments, and storing payment tokens and responses in a database for verification. The presentation provides code examples for making API calls, handling payment tokens, and processing responses from Stripe.
The Data Dichotomy- Rethinking the Way We Treat Data and Servicesconfluent
Presenter: Ben Stopford, Engineer, Confluent
Services come with a problem: they’re not well suited to sharing data. This talk will examine the underlying dichotomy we all face as we piece such systems together. One that is not well served today. The solution lies in blending the old with the new and Apache Kafka plays a central role.
The Data Dichotomy- Rethinking the Way We Treat Data and Servicesconfluent
Presenter: Ben Stopford, Engineer, Confluent
Services come with a problem: they’re not well suited to sharing data. This talk will examine the underlying dichotomy we all face as we piece such systems together. One that is not well served today. The solution lies in blending the old with the new and Apache Kafka plays a central role.
Startups are a hype. Many founders copy-paste actions and processes without understanding why they're doing them in the first place. What's worse, many support networks like accelerators and events make founders do things that are irrelevant, or even outright detrimental, to a first-time entrepreneur.
In this slide deck, I compare the startup world to the cargo cults of Western technology found among aboriginal tribes in the Melanesian islands in the 20th century. Demo days, lean approaches, MVP obsessions are all overrated and abused as cults for the lack of real milestones and goals for startups.
Let's focus on what really makes startups successful instead of idolizing buzz words and work-like procrastination processes.
Cloud computing means storing and accessing data and programs over the Internet instead of your computer's hard drive.In computer networking, cloud computing is a phrase used to describe a variety of computing concepts that involve a large number of computers connected through a real-time communication network such as the Internet.
Cloud Computing is the internet-based computing wherby shared resources, software, and information are provided to computers and other devices on demand, like the electrcity grid
IA 7: IA? IxD? UX! is an uncooked
collection of definitions, categorizations, outlines, and visualizations concerning
⁄ Information architecture IA,
⁄ Interaction design IxD, and
⁄ User experience UX design.
This deck is an updated version of IA 3: IA Concepts. It’s main purpose is to sear the partially dry substances into my own memory.
Download is disabled due to the copyrighted material within the presentation.
Credits: Alan Dix, Ben Shneiderman, Christina Wodtke, Dan Brown, Don Norman, Erin Malone, George Olsen, Jan Borchers, Jesse James Garrett, Jess McMullin, Olga Howard, Peter Morville, Theo Mandel, Todd Warfel
Image credits: flickr.com/library_of_virginia, /liewcf, /nypl
A summary of the major events that brought about cloud computing, starting in the 1950s. You can find this information and much more in Oneserve's 'Ultimate Guide to the Cloud'.
Startups are a hype. Many founders copy-paste actions and processes without understanding why they're doing them in the first place. What's worse, many support networks like accelerators and events make founders do things that are irrelevant, or even outright detrimental, to a first-time entrepreneur.
In this slide deck, I compare the startup world to the cargo cults of Western technology found among aboriginal tribes in the Melanesian islands in the 20th century. Demo days, lean approaches, MVP obsessions are all overrated and abused as cults for the lack of real milestones and goals for startups.
Let's focus on what really makes startups successful instead of idolizing buzz words and work-like procrastination processes.
Cloud computing means storing and accessing data and programs over the Internet instead of your computer's hard drive.In computer networking, cloud computing is a phrase used to describe a variety of computing concepts that involve a large number of computers connected through a real-time communication network such as the Internet.
Cloud Computing is the internet-based computing wherby shared resources, software, and information are provided to computers and other devices on demand, like the electrcity grid
IA 7: IA? IxD? UX! is an uncooked
collection of definitions, categorizations, outlines, and visualizations concerning
⁄ Information architecture IA,
⁄ Interaction design IxD, and
⁄ User experience UX design.
This deck is an updated version of IA 3: IA Concepts. It’s main purpose is to sear the partially dry substances into my own memory.
Download is disabled due to the copyrighted material within the presentation.
Credits: Alan Dix, Ben Shneiderman, Christina Wodtke, Dan Brown, Don Norman, Erin Malone, George Olsen, Jan Borchers, Jesse James Garrett, Jess McMullin, Olga Howard, Peter Morville, Theo Mandel, Todd Warfel
Image credits: flickr.com/library_of_virginia, /liewcf, /nypl
A summary of the major events that brought about cloud computing, starting in the 1950s. You can find this information and much more in Oneserve's 'Ultimate Guide to the Cloud'.
Context-aware application development with FIWARE #CPBR8Fermin Galan
Context-aware application development with FIWARE, used in the #CPBR8 workshop. It includes basic and advanced Orion topics, along with usage examples.
FIWARE Developers Week_ Introduction to Managing Context Information at Large...FIWARE
Introduction to Managing Context Information at Large Scale by Fermín Galán and Leandro Gullén (@leandrogullen @fermingalan) for Developers Week
www.fiware.org
Web APIs have revolutionized all kinds of products and services, and still continue to do so. Nowadays the most relevant architecture is REST along with the JSON media type. Furthermore, lots of specifications to serialize those media types are appearing. JSON API has released its first version last May.
0 to 60 with AWS AppSync: Rapid Development Techniques for Mobile APIs (MOB32...Amazon Web Services
Building a working prototype can help you quickly gather feedback from users, but mock data can be limiting, and backend services might not exist in the state you need. In this chalk talk, we explore how you can use AWS AppSync to build a mobile API with little to no coding and manage existing APIs to empower small development teams or bring your prototypes to life.
How to Leverage APIs for SEO #TTTLive2019Paul Shapiro
Learn the basic of APIs and how they can be leveraged for SEO and marketing. Chalk full of Python code examples.
The URL to the GitHub gist link on slide 54 has changed to the following:
https://gist.github.com/pshapiro/a86dc340f57c38fc22d0545ddec1fc9e
Serverless Microservices Communication with Amazon EventBridgeSheenBrisals
The combination of cloud, serverless and microservices has taken the service implementation to a different level. Though this has accelerated the monolith to microservices transformation, it has also introduced new complexities around service-to-service communication. With every new service added to the system, the order of communications complexity also increases.
Though AWS services such as SNS, SQS and others helped to some extend, they however failed to offer a flexible way to enable filtered routing of messages between microservices. This is where Amazon’s EventBridge makes its mark in alleviating many of these concerns.
AWS EventBridge promotes a hub-and-spoke communication model between microservices. With its flexible and powerful message filtering capability, services can have a renewed way of performing event-driven communication between them. This talk will start by explaining EventBridge and then, with the help of real use-case scenarios, explain how to enable message routing and filtering while working with the event bus.
Similar to Accepting payments using Stripe and Elixir (20)
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...James Anderson
Effective Application Security in Software Delivery lifecycle using Deployment Firewall and DBOM
The modern software delivery process (or the CI/CD process) includes many tools, distributed teams, open-source code, and cloud platforms. Constant focus on speed to release software to market, along with the traditional slow and manual security checks has caused gaps in continuous security as an important piece in the software supply chain. Today organizations feel more susceptible to external and internal cyber threats due to the vast attack surface in their applications supply chain and the lack of end-to-end governance and risk management.
The software team must secure its software delivery process to avoid vulnerability and security breaches. This needs to be achieved with existing tool chains and without extensive rework of the delivery processes. This talk will present strategies and techniques for providing visibility into the true risk of the existing vulnerabilities, preventing the introduction of security issues in the software, resolving vulnerabilities in production environments quickly, and capturing the deployment bill of materials (DBOM).
Speakers:
Bob Boule
Robert Boule is a technology enthusiast with PASSION for technology and making things work along with a knack for helping others understand how things work. He comes with around 20 years of solution engineering experience in application security, software continuous delivery, and SaaS platforms. He is known for his dynamic presentations in CI/CD and application security integrated in software delivery lifecycle.
Gopinath Rebala
Gopinath Rebala is the CTO of OpsMx, where he has overall responsibility for the machine learning and data processing architectures for Secure Software Delivery. Gopi also has a strong connection with our customers, leading design and architecture for strategic implementations. Gopi is a frequent speaker and well-known leader in continuous delivery and integrating security into software delivery.
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024Neo4j
Neha Bajwa, Vice President of Product Marketing, Neo4j
Join us as we explore breakthrough innovations enabled by interconnected data and AI. Discover firsthand how organizations use relationships in data to uncover contextual insights and solve our most pressing challenges – from optimizing supply chains, detecting fraud, and improving customer experiences to accelerating drug discoveries.
UiPath Test Automation using UiPath Test Suite series, part 4DianaGray10
Welcome to UiPath Test Automation using UiPath Test Suite series part 4. In this session, we will cover Test Manager overview along with SAP heatmap.
The UiPath Test Manager overview with SAP heatmap webinar offers a concise yet comprehensive exploration of the role of a Test Manager within SAP environments, coupled with the utilization of heatmaps for effective testing strategies.
Participants will gain insights into the responsibilities, challenges, and best practices associated with test management in SAP projects. Additionally, the webinar delves into the significance of heatmaps as a visual aid for identifying testing priorities, areas of risk, and resource allocation within SAP landscapes. Through this session, attendees can expect to enhance their understanding of test management principles while learning practical approaches to optimize testing processes in SAP environments using heatmap visualization techniques
What will you get from this session?
1. Insights into SAP testing best practices
2. Heatmap utilization for testing
3. Optimization of testing processes
4. Demo
Topics covered:
Execution from the test manager
Orchestrator execution result
Defect reporting
SAP heatmap example with demo
Speaker:
Deepak Rai, Automation Practice Lead, Boundaryless Group and UiPath MVP
Pushing the limits of ePRTC: 100ns holdover for 100 daysAdtran
At WSTS 2024, Alon Stern explored the topic of parametric holdover and explained how recent research findings can be implemented in real-world PNT networks to achieve 100 nanoseconds of accuracy for up to 100 days.
Generative AI Deep Dive: Advancing from Proof of Concept to ProductionAggregage
Join Maher Hanafi, VP of Engineering at Betterworks, in this new session where he'll share a practical framework to transform Gen AI prototypes into impactful products! He'll delve into the complexities of data collection and management, model selection and optimization, and ensuring security, scalability, and responsible use.
Securing your Kubernetes cluster_ a step-by-step guide to success !KatiaHIMEUR1
Today, after several years of existence, an extremely active community and an ultra-dynamic ecosystem, Kubernetes has established itself as the de facto standard in container orchestration. Thanks to a wide range of managed services, it has never been so easy to set up a ready-to-use Kubernetes cluster.
However, this ease of use means that the subject of security in Kubernetes is often left for later, or even neglected. This exposes companies to significant risks.
In this talk, I'll show you step-by-step how to secure your Kubernetes cluster for greater peace of mind and reliability.
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...SOFTTECHHUB
The choice of an operating system plays a pivotal role in shaping our computing experience. For decades, Microsoft's Windows has dominated the market, offering a familiar and widely adopted platform for personal and professional use. However, as technological advancements continue to push the boundaries of innovation, alternative operating systems have emerged, challenging the status quo and offering users a fresh perspective on computing.
One such alternative that has garnered significant attention and acclaim is Nitrux Linux 3.5.0, a sleek, powerful, and user-friendly Linux distribution that promises to redefine the way we interact with our devices. With its focus on performance, security, and customization, Nitrux Linux presents a compelling case for those seeking to break free from the constraints of proprietary software and embrace the freedom and flexibility of open-source computing.
Elevating Tactical DDD Patterns Through Object CalisthenicsDorra BARTAGUIZ
After immersing yourself in the blue book and its red counterpart, attending DDD-focused conferences, and applying tactical patterns, you're left with a crucial question: How do I ensure my design is effective? Tactical patterns within Domain-Driven Design (DDD) serve as guiding principles for creating clear and manageable domain models. However, achieving success with these patterns requires additional guidance. Interestingly, we've observed that a set of constraints initially designed for training purposes remarkably aligns with effective pattern implementation, offering a more ‘mechanical’ approach. Let's explore together how Object Calisthenics can elevate the design of your tactical DDD patterns, offering concrete help for those venturing into DDD for the first time!
Transcript: Selling digital books in 2024: Insights from industry leaders - T...BookNet Canada
The publishing industry has been selling digital audiobooks and ebooks for over a decade and has found its groove. What’s changed? What has stayed the same? Where do we go from here? Join a group of leading sales peers from across the industry for a conversation about the lessons learned since the popularization of digital books, best practices, digital book supply chain management, and more.
Link to video recording: https://bnctechforum.ca/sessions/selling-digital-books-in-2024-insights-from-industry-leaders/
Presented by BookNet Canada on May 28, 2024, with support from the Department of Canadian Heritage.
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Albert Hoitingh
In this session I delve into the encryption technology used in Microsoft 365 and Microsoft Purview. Including the concepts of Customer Key and Double Key Encryption.
Threats to mobile devices are more prevalent and increasing in scope and complexity. Users of mobile devices desire to take full advantage of the features
available on those devices, but many of the features provide convenience and capability but sacrifice security. This best practices guide outlines steps the users can take to better protect personal devices and information.
DevOps and Testing slides at DASA ConnectKari Kakkonen
My and Rik Marselis slides at 30.5.2024 DASA Connect conference. We discuss about what is testing, then what is agile testing and finally what is Testing in DevOps. Finally we had lovely workshop with the participants trying to find out different ways to think about quality and testing in different parts of the DevOps infinity loop.
UiPath Test Automation using UiPath Test Suite series, part 5DianaGray10
Welcome to UiPath Test Automation using UiPath Test Suite series part 5. In this session, we will cover CI/CD with devops.
Topics covered:
CI/CD with in UiPath
End-to-end overview of CI/CD pipeline with Azure devops
Speaker:
Lyndsey Byblow, Test Suite Sales Engineer @ UiPath, Inc.
3. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
Visited Leipzig back in 2005
for a conference
Took the high speed train
to Paris
Hello Hamburg!
4. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
B.A.Sc in software engineering
M.Sc. and PhD in computer science
Worked with Deloitte, IBM, Canadian Federal Government
PHP, C#, Java, Ruby, Clojure
Elixir part-time only,
but since the beginning
(3 tiny PRs in the elixir core)
Part-time professor at the University of Ottawa
Two kids, August (4) and Hayden (6)
Married 13 years to Ayana
Currently working at CrossFit
(remotely, HQ located in California, USA)
Andrew Forward
aforward@gmail.com
@a4word
a4word.com
github.com/aforward
13. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
Enter user information
Share directly with Stripe
Returns unguessable token
Send payment
token to your server
Apply charge
to Stripe
account
14. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
https://stripe.com/docs/security
Keep CC information off your computer*
22. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
Returns unguessable token
{
"id": "tok_1A3QMREz7Te5wka71D40vfk1",
"card": {
"id": "card_1A3QMREz7Te5wka7XSzH1osR",
"name": "aforward@gmail.com",
"brand": "Visa",
"last4": "1111",
"object": "card",
"country": "US",
"funding": "unknown",
"exp_year": "2019",
"cvc_check": "pass",
"exp_month": "12",
"address_zip": "",
"address_city": "",
"address_line1": "",
"address_line2": "",
"address_state": "",
"dynamic_last4": "",
"address_country": "",
"address_zip_check": "",
"address_line1_check": "",
"tokenization_method": ""
},
"type": "card",
"used": "false",
"email": "aforward@gmail.com",
"object": "token",
"created": "1490969059",
"livemode": "false",
"client_ip": "69.159.206.244"
}
No sensitive CC information
The unguessable token
Amount is not provided, as
we have only requested authority
to make the charge
23. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
Send payment
token to your server
token: function(stripeToken) {
$.ajax({
type: "POST",
url: "api/tokens",
data: {token: {"stripe": stripeToken,
"invoice": entity.invoiceData}},
});
}
Forward on the
token to your server
for processing
That unguessable token
For this example, we are also passing
along an invoice full of details about
the payment
24. {
"stripe": {
"id": "tok_1A3QMREz7Te5wka71D40vfk1",
},
"invoice": {
"name": “Payment Gateway
"currency": "cad",
"description": "3 woggles"
}
}
SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
Append invoice information as well
to more easily apply the payment
Send payment
token to your server
Pass along the stripe token (other
fields omitted here for brevity)
Anything client side is manipulable
from, well, the client. So beware!
25. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
Apply charge to
Stripe account
iex(1)> StripePost.post(
...(1)> "https://api.stripe.com/v1/charges",
...(1)> "amount=10000¤cy=cad&description=3+wozzle&source=pk_abc_123",
...(1)> [{"Authorization", "Bearer abc123"},
...(1)> {"Content-Type", "application/x-www-form-urlencoded"}])
Another REST call to Stripe APIs, but
now done in Elixir on the server
Endpoint for making charges
URL encoded data
Your stripe “sensitive” key
(only for server side transactions)
29. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
https://github.com/aforward/stripe-post
30. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
@doc"""
Post a message to the Stripe API by providing all the necessary
information. The answer will be
If successful
{status_code, body}
Under error
{:error, reason}
"""
def post(url, body, headers) do
case HTTPoison.post(url, body, headers) do
{:ok, %HTTPoison.Response{status_code: status_code, body: body}} ->
{status_code, Poison.decode!(body)}
{:error, %HTTPoison.Error{reason: reason}} ->
{:error, reason}
end
end
Stripe endpoint
URL encoded data
Authentication + other headers
Delegate to HTTPoison (I prefer its API to
alternatives like HTTPotion)
Similar to {:ok, object} tuple response, except here it’s the
HTTP status code response (e.g. 200 for OK)
31. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
iex(1)> StripePost.post(
...(1)> "https://api.stripe.com/v1/charges",
...(1)> "amount=10000¤cy=cad&description=3+wozzle&source=pk_abc_123",
...(1)> [{"Authorization", "Bearer abc123"},
...(1)> {"Content-Type", "application/x-www-form-urlencoded"}])
16:41:29.215 [error] SSL: :certify: tls_connection.erl:704:Fatal error: handshake
failure - malformed_handshake_data
{:error, {:tls_alert, 'handshake failure'}}
Underlying error with HTTPosion
(mix deps.update --all)
Not a legit authentication token
Not a legit payment token
And too much “raw” code
here…
{401,
%{"error" => %{"message" => "Invalid API Key provided: **c123",
"type" => "invalid_request_error"}}}
Contrived example, but showing
that indeed we are hitting the API
32. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
@doc"""
Charge an account with the following body configurations
body = %{amount: 10000, currency: "cad", description: "3 wozzle", source: "pk_abc_123"}
configs = %{secret_key: "sk_test_abc123"}
"""
def charge(body, configs) do
post(Api.url <> "/charges", encode_body(body), headers(configs))
end
Constant (which
could/should be configurable)
Helper to convert maps to
URL encoded bodies
Helper to convert maps
to valid HTTPosion headers
33. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
iex(1)> StripePost.charge(
...(1)> %{amount: 10000,
...(1)> currency: "cad",
...(1)> description: "3 wozzle",
...(1)> source: "pk_abc_123"},
...(1)> %{secret_key: "sk_test_abc123"})
{401,
%{"error" => %{"message" => "Invalid API Key provided: **c123",
"type" => "invalid_request_error"}}}
Still contrived
But at least now more elixir like
Passing in the secret key directly
is OK, but not practical
As you will have one for testing
and one for production, so
it’s really more a config
34. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
use Mix.Config
config :stripe_post,
secret_key: "sk_test_abc123",
public_key: "pk_test_def456"
iex(1)> StripePost.charge(
...(1)> %{amount: 10000,
...(1)> currency: "cad",
...(1)> description: "3 wozzle",
...(1)> source: "pk_abc_123"})
So, let’s leverage Elixir’s config instead
No we can charge without
providing the configs
directly
Note, that is the payment token
not the sensitive secret key from above
so it’s still part of the API
35. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
Not real keys
Sensitive keys
are for the server
(“s” for secret)
Public keys are
for the client
(i.e. JavaScript)
Production keys
separate from
testing
37. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
https://github.com/aforward/stripe-callbacks
38. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
iex(1)> StripeCallbacks.process(%{
...(1)> "stripe" => %{"id" => "pk_abc_123"},
...(1)> "invoice" => %{
...(1)> "amount" => 2000,
...(1)> "currency" => "cad",
...(1)> "description" => "3 wozzle"}})
Still contrived
But we log to a database
Split between expected
response from stripe
and the “charge” invoice info
10:22:01.870 [debug] QUERY OK db=3.1ms
UPDATE "tokens" SET "token_status" = $1, "updated_at" = $2 WHERE "id" = $3 ["invalid", {{2017, 4, 25}, {14, 22, 1, 867165}}, 1]
{:ok,
%StripeCallbacks.Token{__meta__: #Ecto.Schema.Metadata<:loaded, "tokens">,
data: %{"invoice" => %{"amount" => 2000, "currency" => "cad",
"description" => "3 wozzle"}, "stripe" => %{"id" => "pk_abc_123"}}, id: 1,
inserted_at: ~N[2017-04-25 14:22:01.075526], token_status: "invalid",
updated_at: ~N[2017-04-25 14:22:01.867165]}}
39. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
Store tokens from the client in the database
Also store the response from Stripe trying to make the charge
Contrived example,
so we are still in “error”
but not for long
stripe_callbacks_dev=# select data, token_status from tokens;
data | token_status
-----------------------------------------------------------------------------+--------------
{ "stripe": {"id": "pk_abc_123"}, | invalid
"invoice": {"amount": 2000, "currency": "cad", "description": "3 wozzle"}} |
stripe_callbacks_dev=# select data, response_status, status_code, token_id from responses;
data | response_status | status_code | token_id
-----------------------------------------------------------------+-----------------+-------------+----------
{“error”. : {"type": "invalid_request_error", | failure | 400 | 1
"message": "Invalid token id: pk_abc_123"}} | | |
43. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
mix new <my-project> --sup --module MyProject --app my_project
11:32 /tmp $ mix new stripe-callbacks --sup --module StripeCallbacks --app stripe_callbacks
* creating README.md
* creating .gitignore
* creating mix.exs
* creating config
* creating config/config.exs
* creating lib
* creating lib/stripe_callbacks.ex
* creating lib/stripe_callbacks/application.ex
* creating test
* creating test/test_helper.exs
* creating test/stripe_callbacks_test.exs
Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:
cd stripe-callbacks
mix test
Run "mix help" for more commands.
45. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
@doc"""
Encode the provided hash map for the URL.
## Examples
iex> StripePost.Api.encode_body(%{a: "one", b: "two"})
"a=one&b=two"
iex> StripePost.Api.encode_body(%{a: "o ne"})
"a=o+ne"
"""
def encode_body(map), do: URI.encode_query(map)
Simply delegates to available
core Elixir function
But documentation is a
first class property of Elixir
And testing too!
46. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
https://hexdocs.pm/stripe_post/StripePost.Api.html
47. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
@doc"""
Build the headers for your API
## Examples
iex> StripePost.Api.headers(%{content_type: "application/json", secret_key: "abc123"})
[{"Authorization", "Bearer abc123"}, {"Content-Type", "application/json"}]
iex> StripePost.Api.headers(%{secret_key: "abc123"})
[{"Authorization", "Bearer abc123"}, {"Content-Type", "application/x-www-form-urlencoded"}]
iex> StripePost.Api.headers(%{})
[{"Authorization", "Bearer sk_test_abc123"}, {"Content-Type", "application/x-www-form-urlencoded"}]
iex> StripePost.Api.headers()
[{"Authorization", "Bearer sk_test_abc123"}, {"Content-Type", "application/x-www-form-urlencoded"}]
"""
def headers(), do: headers(%{})
def headers(nil), do: headers(%{})
def headers(data) do
h = %{content_type: "application/x-www-form-urlencoded"}
|> Map.merge(app_headers())
|> Map.merge(reject_nil(data))
[{"Authorization", "Bearer #{h[:secret_key]}"},
{"Content-Type", h[:content_type]}]
end
Pattern matching to avoid “if”ing out
bad, missing, defaulted data
Generating headers in a structure
like HTTPosion wants
Examples, examples, examples
49. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
use Mix.Config
config :stripe_post,
secret_key: "sk_test_abc123",
public_key: "pk_test_def456"
iex(1)> StripePost.charge(
...(1)> %{amount: 10000,
...(1)> currency: "cad",
...(1)> description: "3 wozzle",
...(1)> source: "pk_abc_123"})
So, let’s leverage Elixir’s config instead
No we can charge without
providing the configs
directly
Note, that is the payment token
not the sensitive secret key from above
so it’s still part of the API
50. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
use Mix.Config
# You will need to configure your public and private keys in Stripe.
# optionally you can also set the default content type
# https://dashboard.stripe.com/account/apikeys
# config :stripe_post,
# secret_key: "sk_test_abc123"
# public_key: "pk_test_abc123"
# content_type: "application/x-www-form-urlencoded"
#
# Within the application we will reference these using
# Application.get_env(:stripe_post, :secret_key)
# Application.get_env(:stripe_post, :public_key)
# Application.get_env(:stripe_post, :content_type)
#
import_config "#{Mix.env}.exs"
Elixir convention for
loading MIX_ENV specific
configs
And then each env, typically
dev, test and prod can be
separately configured
51. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
DO NOT commit sensitive
information to your repo
If some prod configs are not sensitive
then split them between prod.exs and
prod.secret.exs
Make sure you .gitignore the file
But, DO add a .example file, to help others (and your future self)
remember what production configs need to be set
53. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
mix test.watch
https://hex.pm/packages/mix_test_watch
54. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
autotesting rocks!
11:23 ~/sin/projects/current/stripe-callbacks (master)$ mix test.watch
===> Fetching pc ({pkg,<<"pc">>,<<"1.4.0">>})
===> Downloaded package, caching at /Users/aforward/.cache/rebar3/hex/default/packages/pc-1.4.0.tar
===> Compiling pc
===> Fetching rebar3_hex ({pkg,<<"rebar3_hex">>,<<"3.0.0">>})
===> Downloaded package, caching at /Users/aforward/.cache/rebar3/hex/default/packages/
rebar3_hex-3.0.0.tar
===> Compiling rebar3_hex
===> Compiling fs
===> Compiling /Users/aforward/sin/projects/current/stripe-callbacks/deps/fs/c_src/mac/cli.c
===> Compiling /Users/aforward/sin/projects/current/stripe-callbacks/deps/fs/c_src/mac/compat.c
===> Compiling /Users/aforward/sin/projects/current/stripe-callbacks/deps/fs/c_src/mac/main.c
===> Linking /Users/aforward/sin/projects/current/stripe-callbacks/deps/fs/priv/mac_listener
==> mix_test_watch
Compiling 12 files (.ex)
Generated mix_test_watch app
Running tests...
Compiling 2 files (.ex)
Generated stripe_callbacks app
..
Finished in 0.03 seconds
2 tests, 0 failures
Randomized with seed 587946
Each time you save a file in your project
the tests are re-run.
Unlike some other languages, your tests will be so fast
mix_test_watch does not need to be smart about
which tests to run
55. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
https://medium.com/@a4word/continuous-testing-with-elixir-ddc1107c5cc0
Learn more about continuous testing
56. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
Learn more A LOT MORE
about continuous testing
58. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
Grab ecto as well as the appropriate
underlying DB manager (e.g. postgrex
for PostgreSQL)
Create your Repo (thank you
macros… just 3 LOC
Make sure your application
supervises your database
Tell you application which
ecto_repos you care about
59. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
Support different DBs
for different environments
Uncomment this line in your config.exs
Sample configuration
for your dev database
60. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
So add this if you want your
`mix ecto.migrate` to work
I really like small commits, so I usually setup
and commit an empty schema
61. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
/stripe-callbacks (master)$ mix ecto.gen.migration add_tokens
* creating priv/repo/migrations
* creating priv/repo/migrations/20170325160151_add_tokens.exs
Your database is nothing more
than a bunch of schema migrations
Ecto provides a create
language to easily create
tables, indexes, etc.
62. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
Ecto is NOT an ORM
Describe your DB
schema
Configure your entity
as a JSON response
for RESTful APIs
Changesets are confusing,
until they aren’t
64. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
This allows for asynchronous
testing
Ecto is chatty, so this will
disable much of the logging
But now each test needs it’s own
DB connection
All set, go forth and test
65. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
1) test create (default status) (StripeCallbacks.TokenTest)
test/token_test.exs:22
** (MatchError) no match of right hand side value: {:error, i
%DBConnection.ConnectionError{message:
"connection not available because of disconnection"}}
stacktrace:
test/token_test.exs:8: StripeCallbacks.TokenTest.__ex_unit_setup_0/1
test/token_test.exs:1: StripeCallbacks.TokenTest.__ex_unit__/2
Oopses, no database
Override test* to ensure your database is properly up and running
66. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
$ mix test.watch
Running tests...
Compiling 6 files (.ex)
Generated stripe_callbacks app
** (Mix) The database for StripeCallbacks.Repo couldn't be dropped:
ERROR 55006 (object_in_use): database "stripe_callbacks_test"
is being accessed by other users
There are 10 other sessions using the database.
But now we broke `mix test.watch`
Safe way to support a “one off” testing versus test.watch
but you need to call `MIX_ENV=test mix test.once`
67. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
https://github.com/lpil/mix-test.watch/pull/70
https://github.com/lpil/mix-test.watch/pull/71
Support for just running something “once”
Circumventing (unnecessary?) internal
call that break testing that includes
database setup
But, we can do better
68. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
Fix feature-bug for creating / dropping
databases as part of your testing
To avoid re-creating the database
on each test run (renamed from
just “test”)
Enable creating your
database just once when
start `mix test.run`
(instead of each run)
But, you have to live on the edge
70. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
Schema to describe
your data
Key/Value inputs from
a user (very raw)
Data transformations
(cleaned, defaulted,
derived, validated)
+
Insert into database
Or, present
errors for correction
to the user
This IS a changeset
(just a data structure)
71. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
iex(1)> schema = %{first_name: :string, last_name: :string, email: :string}
%{email: :string, first_name: :string, last_name: :string}
iex(2)> params = %{"first_name" => "James", "last_name" => "Url"}
%{"first_name" => "James", "last_name" => "Url"}
iex(3)> changeset = Ecto.Changeset.cast({%{}, schema}, params, Map.keys(schema))
iex(4)> changeset.changes
%{first_name: "James", last_name: "Url"}
iex(5)> changeset.valid?
true
A changeset is just a tuple
with starting data, and the schema
#Ecto.Changeset<action: nil, changes: %{first_name: "James", last_name: "Url"},
errors: [], data: %{}, valid?: true>
The params are the user input
so usually strings as keys
What are the
valid fields
And it’s really just data structure coming back
That you can access like any struct
72. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
defmodule StripeCallbacks.Token do
use Ecto.Schema
import Ecto.Changeset
schema "tokens" do
field :data, :map
field :token_status, :string
timestamps()
end
def changeset(model, params %{}) do
model
|> cast(params, [:data, :token_status])
end
end
The ecto struct (e.g. %Token{})
Based on the schema
Params and valid fields still apply
%Token{}
|> Token.changeset(
%{"data" => %{"apples" => "red"},
"token_status" => “processed"})
|> Repo.insert
Using changes
to insert data
73. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
@doc """
Creates a changeset based on the `model` and `params`.
If no params are provided, an invalid changeset is returned
with no validation performed.
"""
def changeset(model, params %{}) do
model
|> cast(params, [:pubid, :name, :slug, :owner, :status])
|> ChangesetMerger.defaulted(:name, "LiveCode")
|> ChangesetMerger.defaulted(:owner, "Teacher")
|> ChangesetMerger.Slug.derive_if_missing
|> ChangesetMerger.Token.defaulted(:pubid, 4)
|> ChangesetMerger.defaulted(:status, "created")
end
A much more involved changes
that includes default values,
slug (aka URL safe) generation
and tokens
74. SIMPLE PAYMENT PAGE USING ELIXIR AND STRIPE
https://hex.pm/packages/changeset_merger