Code Monkey home page Code Monkey logo

stripe-scala's Introduction

stripe-scala, API for Stripe Using Scala

Build Status Maven Central Version Join the chat at https://gitter.im/mdedetrich/stripe-scala

stripe-scala is a wrapper over the Stripe REST api. Unlike stripe-java, stripe-scala binds JSON response to the stripe object models (using Scala case classes) and lets you create requests from typed case classes (rather than just using Java Map<String,Object>)

Libraries Used

  • circe for JSON (circe provides compile time macros for reading/writing JSON from/to scala case classes). It also provides a very powerful API for validating/querying JSON
  • akka-http for making HTTP requests
  • akka-stream-json for streaming JSON
  • ficus for providing config (via typesafe-config)
  • enumeratum for providing typesafe enumerations on stripe enum models as well

stripe-scala was intentionally designed to use bare minimum external dependencies so its easier to integrate with scala codebases

Installation

Currently, stripe-scala is in pre-1.0 stage. It is powering the payment processing of at least one company in production but not all endpoints are completed.

It has been deployed to Maven Central, so to install it add the following to your build definition:

libraryDependencies ++= Seq(
  "org.mdedetrich" %% "stripe-scala" % "0.2.1"
)

To get the latest version please check the Maven repository search.

TODO for 1.0 release

  • Add all operations for all endpoints
  • Add tests
  • Shade jawn/enumeratum if possible. These dependencies don't need to be exposed to users
  • Document Stripe API with ScalaDoc
  • Figure out how to deal with list collections
  • Figure out how to deal with error handling
  • Implement a single instance of all operation types to figure out if there are any potential issues
    • get
    • create
    • update
    • list
    • delete
  • Clean up/refactor code (still a lot of duplication)
  • Webhooks/Events

Examples

There are integration tests that show how the library is intended to be used.

Usage

Stripe Api key and url endpoint are provided implicitly by using the org.mdedetrich.stripe.ApiKey and org.mdedetrich.stripe.Endpoint types. The org.mdedetrich.stripe.Config object provides these keys through environment variables/system settings (see application.conf for more details), although you can manually provide your own implicit ApiKey and Endpoint instances.

All base responses made are in the format of Future[Try[T]] where T is the model for the object being returned (i.e. creating a charge will return a Future[Try[Charges.Charge]]). If there is an error in making the response that involves either invalid JSON or an error in mapping the JSON to the models case class, this will throw an exception which you need to catch as a failed Future (it is by design that the models defined in stripe-scala are correct and that stripe does actually return valid JSON).

If there however is a checked error (such as an invalid API key) this will not throw an exception, instead it will be contained within the Try monad (i.e. you will get a scala.util.Failure)

The second parameter for stripe POST requests (often named as create in stripe-scala) has an optional idempotencyKey which defaults to None. You can specify a IdempotencyKey to make sure that you don't create duplicate POST requests with the same input.

stripe-scala provides handle/handleIdempotent functions which provides the typical way of dealing with stripe-errors. It will attempt to retry the original request (using the IdempotencyKey to prevent duplicate side effects with handleIdempotent) for errors which are deemed to be network related errors, else it will return a failed Future. If it fails due to going over the retry limit, handle/handleIdempotent will also return a failed Future with MaxNumberOfRetries

import org.mdedetrich.stripe.v1.{Customers, handleIdempotent}
import scala.concurrent.Future

val customerInput: Customers.CustomerInput = ??? // Some customer input
val response: Future[Customers.Customer] = handleIdempotent(Customers.create(customerInput))

For the most part you will want to use handleIdempotent/handle however if you want more fine grained control over potential errors then you can use the various .create/.get methods

Building case classes

The Stripe object models in stripe-scala have named parameters set to default values which simplifies creating the Stripe models

import org.mdedetrich.stripe.v1.Customers._

val expMonth = 01
val expYear = 2020
val cardNumber = "4242424242424242"
val cvc = "536"

// Inefficient way
val source = Source.Card(expMonth,
                        expYear,
                        cardNumber,
                        None,
                        None,
                        None,
                        None,
                        None,
                        None,
                        None,
                        Option(cvc),
                        None,
                        None,
                        None
                      )

// Efficient way
val source2 = Source.Card(
  expMonth = expMonth,
  expYear = expYear,
  number = cardNumber,
  cvc = Option(cvc)
)

metadata

Stripe provides a metadata field which is available as an input field to most of the stripe objects. The metadata in stripe-scala has a type of Option[Map[String,String]]. As you can see, the metadata is wrapped in an Option. This is to make working with metadata easier.

Timestamps

Stripe represents all of its timestamps as unix timestamp numbers (https://support.stripe.com/questions/what-timezone-does-the-dashboard-and-api-use) however stripe-scala models store these timestamps as an OffsetDateTime. stripe-scala handles converting the unix timestamp to OffsetDateTime and vice versa by using custom circe encoders/decoders for JSON (defaults.stripeDateTimeDecoder/defaults.stripeDateTimeEncoder) and stripeDateTimeParamWrites for form parameters.

These functions are exposed publicly via the package object.

Dealing with Card Errors

Since error messages from stripe are properly checked, dealing with errors like invalid CVC when adding a card are very easy to do. Here is an example (we assume that you are using Play, but this can work with any web framework. Only OK,BadRequest and Json.obj are Play related methods)

import org.mdedetrich.stripe.v1.Cards
import org.mdedetrich.stripe.v1.Errors._
import org.mdedetrich.stripe.v1.{handleIdempotent,transformParam}

import play.api.mvc // Play related import

val expMonth = 01
val expYear = 2020
val cardNumber = "4000000000000127"
val cvc = "536"

val stripeCustomerId: String = ??? // Some stripe customer Id

val cardData = Cards.CardData.Source.Object(
  expMonth = expMonth,
  expYear = expYear,
  number = cardNumber,
  cvc = Option(cvc)
)

val cardInput = Cards.CardInput(cardData)

val futureResponse = handleIdempotent(Cards.create(stripeCustomerId, cardInput)).recover {
  case Errors.Error.RequestFailed(CardError, _, Some(message), Some(param)) =>
    // We have a parameter, this usually means one of our fields is incorrect such as an invalid CVC
    BadRequest(Json.obj("message" -> List((transformParam(param), List(message)))))
  case Errors.Error.RequestFailed(CardError, _, Some(message), None) =>
    // No parameter, usually means a more general error, such as a declined card
    BadRequest(Json.obj("message" -> message))
}.map { cardData =>
  Ok(Json.toJson(cardData))
}

We attempt to create a card, and if it fails due to a CardError we use the .recover method on a Future with pattern matching to map it to a BadRequest. If the request passes, we simply wrap the card data around an Ok. If we don't catch something of type CardError we let it propagate as a failed Future.

One thing to note is the transformParam function. Since scala-stripe uses camel case instead of stripe's snake case, returned params for error messages from stripe will use snake case (i.e. "exp_month"). transformParam will convert that to a "expMonth".

If you try and run the above code (remembering to implement stripeCustomerId) with that credit card number in a test environment it should return an incorrect CVC, see stripe testing for more info.

List collection

stripe can return items in the form a of a list which has the following format

{
  "object": "list",
  "url": "/v1/customers/35/sources",
  "has_more": false,
  "data": [
    {...},
    {...}
  ]
}

In stripe-scala, there is a base List collection at org.mdedetrich.stripe.v1.Collections.List with represents the model for the list. Other stripe objects extend org.mdedetrich.stripe.v1.Collections.List to provide an implementation of the object as a list collection, i.e. BankAccountList for BankAccount

Formatting/Style Guide

The project uses scalafmt to enforce consistent Scala formatting. Please run scalafmt before commiting your code to github (i.e. do scalafmt inside of sbt)

Testing

The project has unit and integration tests. These can be run with:

sbt test
sbt it:test

stripe-scala's People

Contributors

christobill avatar leonardehrenfried avatar mdedetrich avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stripe-scala's Issues

sbt-release being weird?

I am not sure if I am doing something stupid, but sbt-release seems to be not working correctly, have a look at the latest release process

> release
[info] Starting release process off commit: 0b1a6568a53dffe1c44ab1285bf85968120d2213
[info] Checking remote [origin] ...
[error] From https://github.com/mdedetrich/stripe-scala
[error]  * [new branch]      update-dependencies -> origin/update-dependencies
Release version [0.2.2] : 
Next version [0.2.3-SNAPSHOT] : 
[success] Total time: 0 s, completed 04/06/2017 5:18:33 PM
[info] Updating {file:/Users/matthewdedetrich/github/stripe-scala/}stripe-scala...
[info] Resolving jline#jline;2.14.3 ...
[info] Done updating.
[warn] There may be incompatibilities among your library dependencies.
[warn] Here are some of the libraries that were evicted:
[warn]  * io.circe:circe-core_2.12:0.7.0 -> 0.8.0
[warn] Run 'evicted' to see detailed eviction warnings
[info] Compiling 39 Scala sources to /Users/matthewdedetrich/github/stripe-scala/target/scala-2.12/classes...
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Accounts.scala:9: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/BankAccounts.scala:8: Unused import
[warn] import defaults._
[warn]                 ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Charges.scala:7: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Customers.scala:8: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Disputes.scala:8: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Errors.scala:6: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Errors.scala:7: Unused import
[warn] import defaults._
[warn]                 ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/FileUploads.scala:15: Unused import
[warn] import org.mdedetrich.stripe.{ApiKey, FileUploadEndpoint, InvalidJsonModelException}
[warn]                                                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/ListFilterInput.scala:5: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/PaymentSource.scala:9: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/StripeObject.scala:4: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Subscriptions.scala:7: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Transfers.scala:8: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] 13 warnings found
[info] Compiling 12 Scala sources to /Users/matthewdedetrich/github/stripe-scala/target/scala-2.12/test-classes...
[warn] /Users/matthewdedetrich/github/stripe-scala/src/test/scala/org/mdedetrich/stripe/v1/AccountsSpec.scala:3: Unused import
[warn] import java.io.{BufferedReader, InputStreamReader}
[warn]                 ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/test/scala/org/mdedetrich/stripe/v1/AccountsSpec.scala:3: Unused import
[warn] import java.io.{BufferedReader, InputStreamReader}
[warn]                                 ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/test/scala/org/mdedetrich/stripe/v1/AccountsSpec.scala:5: Unused import
[warn] import java.util.stream.Collectors
[warn]                         ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/test/scala/org/mdedetrich/stripe/v1/AccountsSpec.scala:7: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/test/scala/org/mdedetrich/stripe/v1/ApplicationFeeRefundsSpec.scala:3: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/test/scala/org/mdedetrich/stripe/v1/BaseSpec.scala:3: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/test/scala/org/mdedetrich/stripe/v1/ChargesSpec.scala:3: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/test/scala/org/mdedetrich/stripe/v1/CustomersSpec.scala:3: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/test/scala/org/mdedetrich/stripe/v1/FileUploadSpec.scala:3: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/test/scala/org/mdedetrich/stripe/v1/RefundsSpec.scala:3: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/test/scala/org/mdedetrich/stripe/v1/TokensSpec.scala:3: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/test/scala/org/mdedetrich/stripe/v1/TransfersSpec.scala:3: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] 12 warnings found
[info] AccountsSpec:
[info] Accounts
[info] - should parse JSON correctly
[info] Account create POST params
[info] - should convert tos acceptance
[info] - should convert address
[info] - should convert transfer schedule
[info] Account update POST params
[info] - should convert default currency
[info] - should convert address
[info] - should convert dob
[info] - should convert name
[info] - should convert tos acceptance
[info] - should convert external account data
[info] - should convert external account token
[info] Day of week
[info] - should parse correctly
[info] ChargesSpec:
[info] Charges
[info] - should parse JSON correctly
[info] Charge create POST params
[info] - should put customer charge params
[info] PostParamsSpec:
[info] Post params
[info] - should convert map to Stripe post params
[info] ApplicationFeeRefundsSpec:
[info] ApplicationFeeRefunds
[info] - should parse JSON correctly
[info] FileUploadSpec:
[info] File Upload
[info] - should parse JSON correctly
[info] RefundsSpec:
[info] Refunds
[info] - should parse JSON correctly
[info] CustomersSpec:
[info] Customers
[info] - should parse JSON correctly
[info] - should convert to JSON
[info] Customer update POST params
[info] - should convert payment source
[info] - should convert default source
[info] PaymentSourceSpec:
[info] Payment sources
[info] - should convert to JSON
[info] TransfersSpec:
[info] Transfers
[info] - should parse JSON correctly
[info] TokensSpec:
[info] Tokens
[info] - should parse bank account token JSON correctly
[info] - should parse credit card token JSON correctly
[info] EventsSpec:
[info] Events
[info] - should parse customer.create JSON correctly
[info] - should parse accounts.update from account.updated-0.json
[info] - should parse accounts.update from account.updated-1.json
[info] - should parse previous attributes correctly
[info] - should parse payment.created JSON correctly
[info] - should parse event list
[info] - should parse balance.available
[info] Run completed in 802 milliseconds.
[info] Total number of tests run: 33
[info] Suites: completed 11, aborted 0
[info] Tests: succeeded 33, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[success] Total time: 26 s, completed 04/06/2017 5:19:00 PM
[info] Setting version to '0.2.2'.
[info] Reapplying settings...
[info] Set current project to stripe-scala (in build file:/Users/matthewdedetrich/github/stripe-scala/)
[info] [master 7a47a35] Setting version to 0.2.2
[info]  1 file changed, 1 insertion(+), 1 deletion(-)
[info] Reapplying settings...
[info] Set current project to stripe-scala (in build file:/Users/matthewdedetrich/github/stripe-scala/)
[info] Reapplying settings...
[info] Set current project to stripe-scala (in build file:/Users/matthewdedetrich/github/stripe-scala/)
[info] Setting version to '0.2.3-SNAPSHOT'.
[info] Reapplying settings...
[info] Set current project to stripe-scala (in build file:/Users/matthewdedetrich/github/stripe-scala/)
[info] [master ef01127] Setting version to 0.2.3-SNAPSHOT
[info]  1 file changed, 1 insertion(+), 1 deletion(-)
[info] Nexus repository URL: https://oss.sonatype.org/service/local
[info] sonatypeProfileName = org.mdedetrich
[info] Reading staging repository profiles...
[warn] No staging repository is found. Do publishSigned first.
Push changes to the remote repository (y/n)? [y] y
[info] To https://github.com/mdedetrich/stripe-scala.git
[info]    0b1a656..ef01127  master -> master
[info] To https://github.com/mdedetrich/stripe-scala.git
[info]  * [new tag]         v0.2.2 -> v0.2.2
[info] Setting version to 2.12.2
[info] Reapplying settings...
[info] Set current project to stripe-scala (in build file:/Users/matthewdedetrich/github/stripe-scala/)
[info] Packaging /Users/matthewdedetrich/github/stripe-scala/target/scala-2.12/stripe-scala_2.12-0.2.3-SNAPSHOT-sources.jar ...
[info] Done packaging.
[info] Wrote /Users/matthewdedetrich/github/stripe-scala/target/scala-2.12/stripe-scala_2.12-0.2.3-SNAPSHOT.pom
[info] Updating {file:/Users/matthewdedetrich/github/stripe-scala/}stripe-scala...
[info] Resolving jline#jline;2.14.3 ...
[info] Done updating.
[warn] There may be incompatibilities among your library dependencies.
[warn] Here are some of the libraries that were evicted:
[warn]  * io.circe:circe-core_2.12:0.7.0 -> 0.8.0
[warn] Run 'evicted' to see detailed eviction warnings
[info] :: delivering :: org.mdedetrich#stripe-scala_2.12;0.2.3-SNAPSHOT :: 0.2.3-SNAPSHOT :: integration :: Sun Jun 04 17:19:16 CEST 2017
[info]  delivering ivy file to /Users/matthewdedetrich/github/stripe-scala/target/scala-2.12/ivy-0.2.3-SNAPSHOT.xml
[info] Main Scala API documentation to /Users/matthewdedetrich/github/stripe-scala/target/scala-2.12/api...
[info] Packaging /Users/matthewdedetrich/github/stripe-scala/target/scala-2.12/stripe-scala_2.12-0.2.3-SNAPSHOT.jar ...
[info] Done packaging.
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Accounts.scala:9: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/BankAccounts.scala:8: Unused import
[warn] import defaults._
[warn]                 ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Charges.scala:7: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Customers.scala:8: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Disputes.scala:8: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Errors.scala:6: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Errors.scala:7: Unused import
[warn] import defaults._
[warn]                 ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/FileUploads.scala:15: Unused import
[warn] import org.mdedetrich.stripe.{ApiKey, FileUploadEndpoint, InvalidJsonModelException}
[warn]                                                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/ListFilterInput.scala:5: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/PaymentSource.scala:9: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/StripeObject.scala:4: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Subscriptions.scala:7: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Transfers.scala:8: Unused import
[warn] import cats.syntax.either._
[warn]                           ^
model contains 616 documentable templates
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Subscriptions.scala:314: Variable 10 undefined in comment for class SubscriptionInput in object Subscriptions
[warn]     *                              For example, if your plan is $10/user/month,
[warn]                                                                  ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Subscriptions.scala:317: Variable 50 undefined in comment for class SubscriptionInput in object Subscriptions
[warn]     *                              charged $50 (5 x $10) monthly. If you
[warn]                                             ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Subscriptions.scala:317: Variable 10 undefined in comment for class SubscriptionInput in object Subscriptions
[warn]     *                              charged $50 (5 x $10) monthly. If you
[warn]                                                      ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Subscriptions.scala:339: Variable 10 undefined in comment for class SubscriptionInput in object Subscriptions
[warn]     *                              $10/month with a [[taxPercent]] of 20.0
[warn]                                     ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Subscriptions.scala:340: Variable 12 undefined in comment for class SubscriptionInput in object Subscriptions
[warn]     *                              will charge $12 per invoice.
[warn]                                                 ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Coupons.scala:58: Variable 100 undefined in comment for class Coupon in object Coupons
[warn]     *                         [[percentOff]] of 50 will make a $100 invoice $50 instead.
[warn]                                                                 ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Coupons.scala:58: Variable 50 undefined in comment for class Coupon in object Coupons
[warn]     *                         [[percentOff]] of 50 will make a $100 invoice $50 instead.
[warn]                                                                              ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Charges.scala:602: Variable 1 undefined in comment for class ChargeInput in object Charges
[warn]     * @param amount              A positive integer in the smallest currency unit (e.g 100 cents to charge $1.00,
[warn]                                                                                                             ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Charges.scala:604: Variable 0 undefined in comment for class ChargeInput in object Charges
[warn]     *                            The minimum amount is $0.50 (or equivalent in charge currency).
[warn]                                                         ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Plans.scala:53: Could not find any member to link for "None".
[warn]   /**
[warn]   ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/PaymentSource.scala:1086: Could not find any member to link for "Currency.`United".
[warn]   /**
[warn]   ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/PaymentSource.scala:141: Could not find any member to link for "Brand.`American".
[warn]   /**
[warn]   ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/PaymentSource.scala:512: Could not find any member to link for "Currency.`United".
[warn]       /**
[warn]       ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Coupons.scala:35: Could not find any member to link for "None".
[warn]   /**
[warn]   ^
[warn] 27 warnings found
[info] Main Scala API documentation successful.
[info] Packaging /Users/matthewdedetrich/github/stripe-scala/target/scala-2.12/stripe-scala_2.12-0.2.3-SNAPSHOT-javadoc.jar ...
[info] Done packaging.
Please enter PGP passphrase (or ENTER to abort): ********************************
[info]  published stripe-scala_2.12 to https://oss.sonatype.org/content/repositories/snapshots/org/mdedetrich/stripe-scala_2.12/0.2.3-SNAPSHOT/stripe-scala_2.12-0.2.3-SNAPSHOT.pom
[info]  published stripe-scala_2.12 to https://oss.sonatype.org/content/repositories/snapshots/org/mdedetrich/stripe-scala_2.12/0.2.3-SNAPSHOT/stripe-scala_2.12-0.2.3-SNAPSHOT-javadoc.jar.asc
[info]  published stripe-scala_2.12 to https://oss.sonatype.org/content/repositories/snapshots/org/mdedetrich/stripe-scala_2.12/0.2.3-SNAPSHOT/stripe-scala_2.12-0.2.3-SNAPSHOT-sources.jar.asc
[info]  published stripe-scala_2.12 to https://oss.sonatype.org/content/repositories/snapshots/org/mdedetrich/stripe-scala_2.12/0.2.3-SNAPSHOT/stripe-scala_2.12-0.2.3-SNAPSHOT.jar.asc
[info]  published stripe-scala_2.12 to https://oss.sonatype.org/content/repositories/snapshots/org/mdedetrich/stripe-scala_2.12/0.2.3-SNAPSHOT/stripe-scala_2.12-0.2.3-SNAPSHOT.pom.asc
[info]  published stripe-scala_2.12 to https://oss.sonatype.org/content/repositories/snapshots/org/mdedetrich/stripe-scala_2.12/0.2.3-SNAPSHOT/stripe-scala_2.12-0.2.3-SNAPSHOT.jar
[info]  published stripe-scala_2.12 to https://oss.sonatype.org/content/repositories/snapshots/org/mdedetrich/stripe-scala_2.12/0.2.3-SNAPSHOT/stripe-scala_2.12-0.2.3-SNAPSHOT-sources.jar
[info]  published stripe-scala_2.12 to https://oss.sonatype.org/content/repositories/snapshots/org/mdedetrich/stripe-scala_2.12/0.2.3-SNAPSHOT/stripe-scala_2.12-0.2.3-SNAPSHOT-javadoc.jar
[success] Total time: 53 s, completed 04/06/2017 5:20:08 PM
[info] Setting version to 2.11.11
[info] Reapplying settings...
[info] Set current project to stripe-scala (in build file:/Users/matthewdedetrich/github/stripe-scala/)
[info] Updating {file:/Users/matthewdedetrich/github/stripe-scala/}stripe-scala...
[info] Packaging /Users/matthewdedetrich/github/stripe-scala/target/scala-2.11/stripe-scala_2.11-0.2.3-SNAPSHOT-sources.jar ...
[info] Wrote /Users/matthewdedetrich/github/stripe-scala/target/scala-2.11/stripe-scala_2.11-0.2.3-SNAPSHOT.pom
[info] Resolving org.scala-lang#scala-library;2.11.11 ...
[info] Done packaging.
[info] Resolving jline#jline;2.14.3 ...
[info] downloading https://repo1.maven.org/maven2/io/circe/circe-core_2.11/0.8.0/circe-core_2.11-0.8.0.jar ...
[info]  [SUCCESSFUL ] io.circe#circe-core_2.11;0.8.0!circe-core_2.11.jar (468ms)
[info] downloading https://repo1.maven.org/maven2/io/circe/circe-generic_2.11/0.8.0/circe-generic_2.11-0.8.0.jar ...
[info]  [SUCCESSFUL ] io.circe#circe-generic_2.11;0.8.0!circe-generic_2.11.jar (179ms)
[info] downloading https://repo1.maven.org/maven2/io/circe/circe-parser_2.11/0.8.0/circe-parser_2.11-0.8.0.jar ...
[info]  [SUCCESSFUL ] io.circe#circe-parser_2.11;0.8.0!circe-parser_2.11.jar (215ms)
[info] downloading https://repo1.maven.org/maven2/com/beachape/enumeratum-circe_2.11/1.5.14/enumeratum-circe_2.11-1.5.14.jar ...
[info]  [SUCCESSFUL ] com.beachape#enumeratum-circe_2.11;1.5.14!enumeratum-circe_2.11.jar (343ms)
[info] downloading https://repo1.maven.org/maven2/io/circe/circe-numbers_2.11/0.8.0/circe-numbers_2.11-0.8.0.jar ...
[info]  [SUCCESSFUL ] io.circe#circe-numbers_2.11;0.8.0!circe-numbers_2.11.jar (173ms)
[info] downloading https://repo1.maven.org/maven2/io/circe/circe-jawn_2.11/0.8.0/circe-jawn_2.11-0.8.0.jar ...
[info]  [SUCCESSFUL ] io.circe#circe-jawn_2.11;0.8.0!circe-jawn_2.11.jar (157ms)
[info] downloading https://repo1.maven.org/maven2/org/scalatest/scalatest_2.11/3.0.3/scalatest_2.11-3.0.3.jar ...
[info]  [SUCCESSFUL ] org.scalatest#scalatest_2.11;3.0.3!scalatest_2.11.jar(bundle) (2236ms)
[info] downloading https://repo1.maven.org/maven2/org/scalactic/scalactic_2.11/3.0.3/scalactic_2.11-3.0.3.jar ...
[info]  [SUCCESSFUL ] org.scalactic#scalactic_2.11;3.0.3!scalactic_2.11.jar(bundle) (302ms)
[info] Done updating.
[warn] There may be incompatibilities among your library dependencies.
[warn] Here are some of the libraries that were evicted:
[warn]  * io.circe:circe-core_2.11:0.7.0 -> 0.8.0
[warn] Run 'evicted' to see detailed eviction warnings
[info] :: delivering :: org.mdedetrich#stripe-scala_2.11;0.2.3-SNAPSHOT :: 0.2.3-SNAPSHOT :: integration :: Sun Jun 04 17:20:16 CEST 2017
[info]  delivering ivy file to /Users/matthewdedetrich/github/stripe-scala/target/scala-2.11/ivy-0.2.3-SNAPSHOT.xml
[info] Compiling 39 Scala sources to /Users/matthewdedetrich/github/stripe-scala/target/scala-2.11/classes...
[info] Main Scala API documentation to /Users/matthewdedetrich/github/stripe-scala/target/scala-2.11/api...
model contains 616 documentable templates
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Subscriptions.scala:314: Variable 10 undefined in comment for class SubscriptionInput in object Subscriptions
[warn]     *                              For example, if your plan is $10/user/month,
[warn]                                                                  ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Subscriptions.scala:317: Variable 50 undefined in comment for class SubscriptionInput in object Subscriptions
[warn]     *                              charged $50 (5 x $10) monthly. If you
[warn]                                             ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Subscriptions.scala:317: Variable 10 undefined in comment for class SubscriptionInput in object Subscriptions
[warn]     *                              charged $50 (5 x $10) monthly. If you
[warn]                                                      ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Subscriptions.scala:339: Variable 10 undefined in comment for class SubscriptionInput in object Subscriptions
[warn]     *                              $10/month with a [[taxPercent]] of 20.0
[warn]                                     ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Subscriptions.scala:340: Variable 12 undefined in comment for class SubscriptionInput in object Subscriptions
[warn]     *                              will charge $12 per invoice.
[warn]                                                 ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Coupons.scala:58: Variable 100 undefined in comment for class Coupon in object Coupons
[warn]     *                         [[percentOff]] of 50 will make a $100 invoice $50 instead.
[warn]                                                                 ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Coupons.scala:58: Variable 50 undefined in comment for class Coupon in object Coupons
[warn]     *                         [[percentOff]] of 50 will make a $100 invoice $50 instead.
[warn]                                                                              ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Charges.scala:602: Variable 1 undefined in comment for class ChargeInput in object Charges
[warn]     * @param amount              A positive integer in the smallest currency unit (e.g 100 cents to charge $1.00,
[warn]                                                                                                             ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Charges.scala:604: Variable 0 undefined in comment for class ChargeInput in object Charges
[warn]     *                            The minimum amount is $0.50 (or equivalent in charge currency).
[warn]                                                         ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Plans.scala:53: Could not find any member to link for "None".
[warn]   /**
[warn]   ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/PaymentSource.scala:1086: Could not find any member to link for "Currency.`United".
[warn]   /**
[warn]   ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/PaymentSource.scala:141: Could not find any member to link for "Brand.`American".
[warn]   /**
[warn]   ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/PaymentSource.scala:512: Could not find any member to link for "Currency.`United".
[warn]       /**
[warn]       ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Errors.scala:63: Could not find any member to link for "None".
[warn]   /**
[warn]   ^
[warn] /Users/matthewdedetrich/github/stripe-scala/src/main/scala/org/mdedetrich/stripe/v1/Coupons.scala:35: Could not find any member to link for "None".
[warn]   /**
[warn]   ^
[warn] 15 warnings found
[info] Main Scala API documentation successful.
[info] Packaging /Users/matthewdedetrich/github/stripe-scala/target/scala-2.11/stripe-scala_2.11-0.2.3-SNAPSHOT-javadoc.jar ...
[info] Done packaging.
[info] Packaging /Users/matthewdedetrich/github/stripe-scala/target/scala-2.11/stripe-scala_2.11-0.2.3-SNAPSHOT.jar ...
[info] Done packaging.
[info]  published stripe-scala_2.11 to https://oss.sonatype.org/content/repositories/snapshots/org/mdedetrich/stripe-scala_2.11/0.2.3-SNAPSHOT/stripe-scala_2.11-0.2.3-SNAPSHOT.pom
[info]  published stripe-scala_2.11 to https://oss.sonatype.org/content/repositories/snapshots/org/mdedetrich/stripe-scala_2.11/0.2.3-SNAPSHOT/stripe-scala_2.11-0.2.3-SNAPSHOT-javadoc.jar.asc
[info]  published stripe-scala_2.11 to https://oss.sonatype.org/content/repositories/snapshots/org/mdedetrich/stripe-scala_2.11/0.2.3-SNAPSHOT/stripe-scala_2.11-0.2.3-SNAPSHOT-sources.jar.asc
[info]  published stripe-scala_2.11 to https://oss.sonatype.org/content/repositories/snapshots/org/mdedetrich/stripe-scala_2.11/0.2.3-SNAPSHOT/stripe-scala_2.11-0.2.3-SNAPSHOT.jar.asc
[info]  published stripe-scala_2.11 to https://oss.sonatype.org/content/repositories/snapshots/org/mdedetrich/stripe-scala_2.11/0.2.3-SNAPSHOT/stripe-scala_2.11-0.2.3-SNAPSHOT.pom.asc
[info]  published stripe-scala_2.11 to https://oss.sonatype.org/content/repositories/snapshots/org/mdedetrich/stripe-scala_2.11/0.2.3-SNAPSHOT/stripe-scala_2.11-0.2.3-SNAPSHOT.jar
[info]  published stripe-scala_2.11 to https://oss.sonatype.org/content/repositories/snapshots/org/mdedetrich/stripe-scala_2.11/0.2.3-SNAPSHOT/stripe-scala_2.11-0.2.3-SNAPSHOT-sources.jar
[info]  published stripe-scala_2.11 to https://oss.sonatype.org/content/repositories/snapshots/org/mdedetrich/stripe-scala_2.11/0.2.3-SNAPSHOT/stripe-scala_2.11-0.2.3-SNAPSHOT-javadoc.jar
[success] Total time: 56 s, completed 04/06/2017 5:21:05 PM
[info] Setting version to 2.12.2
[info] Reapplying settings...
[info] Set current project to stripe-scala (in build file:/Users/matthewdedetrich/github/stripe-scala/)
> release
[info] Starting release process off commit: ef01127f663ab4370125cea8b4e5fa07b2cf45a8
[info] Checking remote [origin] ...
Release version [0.2.3] : โŽ

As you can see, the release version gets correctly set to 0.2.2 however the version that gets published is 0.2.3-SNAPSHOT, any ideas what is wrong here?

Plans.create has incorrect parameters

I've noticed a few issues with the createPlan implementation:
A recent Major change in the Stripe API breaks the current Plans implementation:

(1) We're missing the product parameter. From https://stripe.com/docs/api/java#create_plan-product:

The product whose pricing the created plan will represent. This can either be the ID of an existing product, or a dictionary containing fields used to create a service product.

In this implementation, product is missing from both the Plan and PlanInput case classes.

(2) The name field is incorrectly encoded. I'm assuming the name parameter was supposed to be used as the plan's optional nickname as opposed to the product's required name. If that's so, the spelling of this field is another bug. In the other case, it's still a bug since it's not a required field nested under the (missing) product object.

(3) trial_period_days is not a parameter for creating plans, though it is present in the returned json. Rather, it's a paremeter when creating subscriptions to existing plans.

ApiKey Configuration

I've added this library to play framework project. When i am running it i am getting this error:

Configuration error: Configuration error[application.conf @ jar:file:/Users/macos/.ivy2/cache/org.mdedetrich/stripe-scala_2.11/jars/stripe-scala_2.11-1.0.0-SNAPSHOT.jar!/application.conf: 5: Could not resolve substitution to a value: ${STRIPE_APIKEY}]
    at play.api.Configuration$.configError(Configuration.scala:178)
    at play.api.Configuration$.load(Configuration.scala:103)
    at play.core.server.DevServerStart$$anonfun$mainDev$1.apply(DevServerStart.scala:203)
    at play.core.server.DevServerStart$$anonfun$mainDev$1.apply(DevServerStart.scala:61)
    at play.utils.Threads$.withContextClassLoader(Threads.scala:21)
    at play.core.server.DevServerStart$.mainDev(DevServerStart.scala:60)
    at play.core.server.DevServerStart$.mainDevHttpMode(DevServerStart.scala:50)
    at play.core.server.DevServerStart.mainDevHttpMode(DevServerStart.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at play.runsupport.Reloader$.startDevMode(Reloader.scala:223)
    at play.sbt.run.PlayRun$$anonfun$playRunTask$1$$anonfun$apply$2$$anonfun$apply$3.devModeServer$lzycompute$1(PlayRun.scala:74)
    at play.sbt.run.PlayRun$$anonfun$playRunTask$1$$anonfun$apply$2$$anonfun$apply$3.play$sbt$run$PlayRun$$anonfun$$anonfun$$anonfun$$devModeServer$1(PlayRun.scala:74)
    at play.sbt.run.PlayRun$$anonfun$playRunTask$1$$anonfun$apply$2$$anonfun$apply$3.apply(PlayRun.scala:100)
    at play.sbt.run.PlayRun$$anonfun$playRunTask$1$$anonfun$apply$2$$anonfun$apply$3.apply(PlayRun.scala:53)
    at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)

How configure library to pick this key from play application config file?

cats-core version conflicts - upgrading circe-core to 0.9.2

We get a dependency conflict during json decoding probably because stripe-scala transitively links in an older version of cats-core:0.9.1 via circe-core:0.8.0. An update to circe-core:0.9.2 would eventually solve the issue because it links cats-core:1.0.1, the version we do require.

This happens if we call Customers.get

java.lang.NoClassDefFoundError: cats/functor/Invariant
	at io.circe.Decoder$.<init>(Decoder.scala:776)
	at io.circe.Decoder$.<clinit>(Decoder.scala)
	at org.mdedetrich.stripe.v1.Customers$.<init>(Customers.scala:42)
	at org.mdedetrich.stripe.v1.Customers$.<clinit>(Customers.scala)
	at org.acme.id.app.http.api.services.stripepayment.domain.PaymentController.getSubscriptions(PaymentController.scala:67)

Upgrading to circe-core:0.9.2 could solve the issue, not sure about any side effects, though.

Delete Subscription

Hello,

This lib is very nice since Stripe does not provide official Scala lib.
I know there is not all endpoints implemented but how can i delete subscription for a customer ?
Is there a way to do this using this lib or do i need to implement my own http call ?

Thanks

Change from play-json to a better JSON client

Currently I have a preference for using Circe rather than play-json, here are my current pros/cons

Pros

  • Has macros to support a lot of use cases, including automatic Encoder/Decoder transformations for a generic case class T that translates to lower case
  • Uses a HistoryOP to provide very granular error messages
  • Cross compiled for Scalajs (might make sense to move the basic models of stripe to a cross compiled scala.js project at some point in the future for client side support of stripe.js with Scala.js?)
  • Not bounded to any framework apart from Cats and quite independent which means it updates according to Scala versions much better (i.e. it had Scala 2.12 support much sooner than play-json did). Also receives updates a lot more frequently than play-json does

Cons

  • Depends on Cats, which is a pretty big dependency. Not sure if shading the Cats dependency is realistic, but I am wary of introducing big dependencies to ease friction for end users (in any case, I was planning to shade play-json as well)

@leonardehrenfried Thoughts?

Deploy to Maven Central

At my current project we are running this project in production for a few weeks with virtually no issues.

Even though not all endpoints are covered completely I think the code is good enough to be deployed to Maven Central.

What do you think? What are your requirements before putting it up?

Use default named parameters

The current api provides (`.default) methods on various case classes to make the construction of the models easier. This is pointless since Scala also has named default parameters, i.e. instead of

  case class LegalEntity(
      address: Address,
      `type`: Option[LegalEntityType],
      businessName: Option[String],
      firstName: Option[String],
      lastName: Option[String],
      dob: Option[LocalDate],
      tosAgreement: Option[TosAcceptance]
  )

  object LegalEntity {
    def default = LegalEntity(Address.default, None, None, None, None, None, None)
  }

You can just do

  case class LegalEntity(
      address: Address,
      `type`: Option[LegalEntityType] = None,
      businessName: Option[String] = None,
      firstName: Option[String] = None,
      lastName: Option[String] = None,
      dob: Option[LocalDate] = None,
      tosAgreement: Option[TosAcceptance]
  )

And you can just construct with LegalEntity("some address"). The only downside to this is it will break the ordering of the fields of the models in various places, since you need to move all of the optional fields to the bottom of the case class for ideal use

Fatal Warnings

There are not many warnings (13), it would be easy to add -Xfatal-warnings compilation flag ๐Ÿ˜„

Set Stripe-Version header

At the moment, the API version is set in the settings of Stripe account which would break if someone uses a newer version.

Support brand in charge source

Hi!
I was wondering if you had looked at also adding in the card brand (Visa, Mastercard, etc) from the charge's source.
Quick glance at the code, it would be around the maskedCardSourceEncoder and MaskedCard case class.
If not, I am happy to do the change, test and send you a pull request.
Cheers,
Marco

Investigate DI (use case classes instead of objects?)

For basic top level models (i.e. org.mdedetrich.stripe.v1.Accounts), these are currently represented as objects. While very convenient, it makes DI harder because we have to mention the dependencies in every internal method of the Object, i.e.

def get(id: String)(implicit apiKey: ApiKey, endpoint: Endpoint): Future[Try[Account]] = {
    val finalUrl = endpoint.url + s"/v1/accounts/$id"

    createRequestGET[Account](finalUrl, logger)
  }

We could kinda get away with this (for now) because

  • We used a global dispatch singleton Http client instance (the current version of stripe-scala doesn't actually let you specify a httpClient object if you don't want to use the global one)
  • There aren't that many DI dependencies for it to become painful

However with the move to akka-http (and possibly some other changes that will happen in the future), it may make some sense to use a saner mechanism. What I have immediately in mind (without having to resort to other external dependencies) is instead of using objects we use implicit final case classes, i.e. instead of

object Accounts extends LazyLogging

we have

final case class Accounts(implicit httpClient: HttpExt, executionContext: ExecutionContext....) extends LazyLogging

This however means that instead of doing Accounts.update(....) we would have to do Accounts().update(....). We also create an instance of Accounts() whenever its called, I think the JVM is good at handling this stuff but not entirely sure

@leonardehrenfried Do you have any ideas. We could just do what we do currently and just add all of the dependencies onto the internal object functions

There are also other options, i.e. using stuff like MacWire or Subcut for DI.

Migrate to akka-http client

This is a general issue ticket for migrating to akka-http-client, doing so brings a number of advantages

  • Better support (the maintenance and support for dispatch in the future is dubious)
  • Streaming support (akka-http-client supports streaming throughout the whole library, including JSON via extensions)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.