This repository has been archived by the owner on Jul 31, 2023. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 6c7a92e
Showing
443 changed files
with
16,193 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
.classpath | ||
.project | ||
.settings/ | ||
.idea/ | ||
target/ | ||
*.iml | ||
.metals/ | ||
.bsp/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
version = "3.0.5" | ||
|
||
maxColumn = 120 | ||
assumeStandardLibraryStripMargin = false | ||
align.preset = more | ||
align.stripMargin = true | ||
docstrings.oneline = fold | ||
docstrings.wrap = "no" # "yes" would be nicer, but it doesn't support embedded html | ||
indent.main = 2 | ||
indent.defnSite = 2 | ||
indent.extendSite = 2 | ||
rewrite.rules = [ Imports, RedundantBraces, RedundantParens, PreferCurlyFors, SortModifiers ] | ||
rewrite.imports.sort = ascii | ||
rewrite.redundantBraces.generalExpressions = false | ||
rewrite.redundantBraces.stringInterpolation = true | ||
runner.dialect = "scala212" | ||
project.git = true | ||
project.excludeFilters = [".*\\.sbt"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
Copyright 2021 ngrok, Inc. | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,259 @@ | ||
# ngrok API client library for Scala | ||
|
||
This library wraps the [ngrok HTTP API](https://ngrok.com/docs/api) to | ||
make it easier to consume in Scala. | ||
|
||
## Usage | ||
|
||
This library is published on [Maven | ||
Central](https://search.maven.org/artifact/com.ngrok/ngrok-api-scala). | ||
|
||
If using sbt, add the following dependency: | ||
|
||
```scala | ||
"com.ngrok" %% "ngrok-api-scala % "[use latest version]" | ||
``` | ||
If using Maven, in your `pom.xml` file, add: | ||
```xml | ||
<dependencies> | ||
<dependency> | ||
<groupId>com.ngrok</groupId> | ||
<artifactId>ngrok-api-scala</artifactId> | ||
<version>${ngrok-api-scala.version}</version> | ||
</dependency> | ||
</dependencies> | ||
``` | ||
See the above URL for the latest version of the API client. | ||
Versions of this library are published for Scala 2.12 and Scala 2.13 | ||
(the 2.13 version can be used with Scala 3). | ||
## Documentation | ||
All objects, methods and properties are documented with Scaladoc for | ||
integration with an IDE like IntelliJ IDEA or Eclipse. You can also | ||
[view the documentation online](https://scala-api.docs.ngrok.com/). | ||
Beyond that, this readme is the best source of documentation for the | ||
library. | ||
### Versioning | ||
This class library is published to Maven Central using semantic | ||
versioning. Breaking changes to the API will only be released with a bump | ||
of the major version number. Each released commit is tagged in this | ||
repository. | ||
No compatibility promises are made for versions < 1.0.0. | ||
### Quickstart | ||
First, use the ngrok dashboard to generate an API key. Store that in a | ||
safe place. Inject it into your application using the environment | ||
variable `NGROK_API_KEY`. The `Ngrok()` method will pull from that | ||
environment variable. If you prefer, you can also pass the API key | ||
explicitly. | ||
#### Create an IP Policy that allows traffic from some subnets | ||
```scala | ||
import cats.implicits._ | ||
import com.ngrok._ | ||
import scala.concurrent.Await | ||
import scala.concurrent.ExecutionContext.Implicits.global | ||
import scala.concurrent.duration._ | ||
class Example extends App { | ||
val ngrok = Ngrok() | ||
Await.result( | ||
ngrok.ipPolicies.create("allow").flatMap(policy => | ||
List("24.0.0.0/8", "12.0.0.0/8").traverse( | ||
cidr => ngrok.ipPolicyRules.create(cidr, policy.id) | ||
) | ||
), | ||
1.second | ||
) | ||
} | ||
``` | ||
#### List all online tunnels | ||
```scala | ||
import cats.implicits._ | ||
import com.ngrok._ | ||
import com.ngrok.definitions._ | ||
import scala.concurrent.ExecutionContext.Implicits.global | ||
import scala.concurrent.Future | ||
import scala.concurrent.duration._ | ||
class Example extends App { | ||
val ngrok = Ngrok() | ||
println("Tunnels:") | ||
ngrok.tunnels.list().map(printRecursively(ngrok, _)) | ||
private def printRecursively(ngrok: Ngrok, currentPage: Page[TunnelList]): Future[Unit] = { | ||
currentPage.page.tunnels.foreach(println) | ||
currentPage.next() | ||
.map(_ | ||
.map(printRecursively(ngrok, _)) | ||
.getOrElse(Future.successful(())) | ||
) | ||
} | ||
} | ||
``` | ||
### Conventions | ||
Conventional usage of this package is to construct a root `Ngrok` object | ||
using its `apply()` method. You can then access API resources using that | ||
object. Do not construct the individual API resource client classes in | ||
your application code. | ||
You can also customize low-level behavior by instantiating the | ||
`DefaultNgrokApiClient` yourself, and then using it to construct the | ||
`Ngrok` instance. If you'd like to use a different HTTP library | ||
entirely, you can even implement the `NgrokApiClient` interface | ||
yourself. | ||
```scala | ||
import com.ngrok._ | ||
import java.net.URI | ||
import scala.concurrent.Await | ||
import scala.concurrent.ExecutionContext.Implicits.global | ||
import scala.concurrent.duration._ | ||
class Example extends App { | ||
// Create the root api client using an API key from the environment variable NGROK_API_KEY | ||
val defaultNgrok = Ngrok() | ||
// ... or create the root api client using an API key provided directly | ||
val defaultNgrokWithApiKey = Ngrok("my secret api key") | ||
|
||
// ... or create the root api client by customizing the low-level networking details | ||
val customApiClient = DefaultNgrokApiClient( | ||
apiKey = System.getenv("NGROK_API_KEY") | ||
baseUri = Some(URI.create("https://some-other-server.com")) | ||
) | ||
val ngrokWithCustomApiClient = Ngrok(customApiClient); | ||
|
||
// Clients for all api resources (like ip policies) are acccessible via methods on the root client | ||
val policy = Await.result(defaultNgrok.ipPolicies.get(policyId), 1.second) | ||
|
||
// Some api resources are 'namespaced' through another method | ||
val circuitBreaker = Await.result(defaultNgrok.pointcfgModule.circuitBreaker.get(endpointConfigId), 1.second) | ||
} | ||
``` | ||
|
||
### Paging | ||
|
||
All list responses from the ngrok API are paged. All list response | ||
objects implement the `Pageable` trait, and are wrapped in a `Page` | ||
class, which has a `next()` method. Calling `next()` will asyncronously | ||
request the next page. If no next page is available, an empty `Option` | ||
will be returned inside the `Future`. | ||
|
||
```scala | ||
import com.ngrok._ | ||
import com.ngrok.definitions._ | ||
|
||
import scala.concurrent.Await | ||
import scala.concurrent.ExecutionContext.Implicits.global | ||
import scala.concurrent.Future | ||
import scala.concurrent.duration._ | ||
|
||
class Example extends App { | ||
val ngrok = Ngrok() | ||
|
||
val credentials = Await.result( | ||
ngrok.credentials.list().flatMap(gatherRecursively(ngrok, List.empty, _)), | ||
1.second | ||
) | ||
println("Credentials:") | ||
credentials.foreach(println) | ||
|
||
private def gatherRecursively(ngrok: Ngrok, credentials: List[Credential], currentPage: Page[CredentialList]): Future[List[Credential]] { | ||
val updatedCredentials = credentials ++ currentPage.page.credentials | ||
currentPage.next().flatMap(_ | ||
.map(gatherRecursively(ngrok, updatedCredentials, _)) | ||
.getOrElse(Future.successful(updatedCredentials)) | ||
) | ||
} | ||
} | ||
``` | ||
|
||
### Error Handling | ||
|
||
All errors returned by the ngrok API are serialized as structured | ||
payloads for easy error handling. If a structured error is returned by | ||
the ngrok API, this library will return a failed `Future` | ||
containing a `NgrokApiError`. | ||
|
||
This object will allow you to check the unique ngrok error code and the | ||
http status code of a failed response. Use the `errorCode` property | ||
to check for unique ngrok error codes returned by the API. All error | ||
codes are documented at | ||
[https://ngrok.com/docs/errors](https://ngrok.com/docs/errors). There is | ||
also an `isErrorCode()` method on the exception object to check against | ||
multiple error codes. The `httpStatusCode` property can be used to | ||
check not found errors. | ||
|
||
Other non-structured errors encountered while making an API call from | ||
e.g. networking or serialization failures are not wrapped in any way and | ||
will bubble up as normal. | ||
|
||
```scala | ||
import com.ngrok._ | ||
import com.ngrok.definitions._ | ||
|
||
import scala.concurrent.Await | ||
import scala.concurrent.ExecutionContext.Implicits.global | ||
import scala.concurrent.duration._ | ||
import scala.util.{Failure, Success} | ||
|
||
class Example extends App { | ||
val ngrok = Ngrok() | ||
|
||
Await.ready( | ||
ngrok.reservedDomains.create( | ||
name = System.getenv("NGROK_DOMAIN"), | ||
description = Some("example domain") | ||
).onComplete({ | ||
case Success(_) => | ||
println("Successfully reserved domain.") | ||
|
||
case Failure(error: NgrokApiError) if error.isErrorCode("NGROK_ERR_402", "NGROK_ERR_403") => | ||
println("Ignoring invalid wildcard domain.") | ||
|
||
case Failure(error: NgrokApiError) => | ||
val errorCode = error.errorCode.getOrElse("unknown") | ||
println(s"API Error ($errorCode): ${error.message}") | ||
|
||
case Failure(error) => | ||
println(s"Other error: ${error.message}) | ||
}), | ||
1.second | ||
) | ||
} | ||
``` | ||
|
||
### Datatype Overrides | ||
|
||
All datatype objects in the ngrok API library are case classes, which | ||
properly override `equals()` and `hashCode()` so that the objects can be | ||
compared. Similarly, they override `toString()` for more helpful pretty | ||
printing of ngrok domain objects. | ||
|
||
### Sync / Async Interfaces | ||
|
||
Each API client operation returns a `Future[T]` and is asynchonous. If | ||
you require a synchonous call, you can wrap the return value in | ||
`Await.result()`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import java.nio.charset.StandardCharsets | ||
import java.nio.file.Files | ||
import java.util.stream.Collectors | ||
import scala.collection.JavaConverters._ | ||
|
||
import Dependencies._ | ||
|
||
ThisBuild / organization := "com.ngrok" | ||
ThisBuild / organizationName := "ngrok" | ||
ThisBuild / version := IO.readLines(file("project/version")).head.trim | ||
ThisBuild / description := "Ngrok API client for Scala applications" | ||
ThisBuild / licenses := List("MIT" -> url("https://mit-license.org/")) | ||
ThisBuild / homepage := Some(url("https://ngrok.com")) | ||
ThisBuild / crossScalaVersions := Seq("2.13.6", "2.12.14") | ||
ThisBuild / scalaVersion := (ThisBuild / crossScalaVersions).value.head | ||
|
||
ThisBuild / scmInfo := Some( | ||
ScmInfo( | ||
url("https://github.com/ngrok/ngrok-api-scala"), | ||
"scm:git@github.com:ngrok/ngrok-api-scala.git" | ||
) | ||
) | ||
|
||
ThisBuild / developers := List( | ||
Developer( | ||
id = "ngrok", | ||
name = "ngrok", | ||
email = "", | ||
url = url("https://ngrok.com") | ||
) | ||
) | ||
|
||
ThisBuild / publishTo := sonatypePublishToBundle.value | ||
ThisBuild / sonatypeCredentialHost := "s01.oss.sonatype.org" | ||
ThisBuild / sonatypeProfileName := "com.ngrok" | ||
ThisBuild / sonatypeProjectHosting := Some(xerial.sbt.Sonatype.GitHubHosting("ngrok", "ngrok-api-scala", "")) | ||
|
||
ThisBuild / autoAPIMappings := true | ||
ThisBuild / apiURL := Some(url("https://scala-api.docs.ngrok.com/")) | ||
|
||
lazy val generateSources = taskKey[Seq[File]]("Generates sources from templates") | ||
generateSources := { | ||
val templatesRoot = ((Compile / sourceDirectory).value / "scala-templates").getAbsoluteFile | ||
val generatedSourcesRoot = (Compile / sourceManaged).value.getAbsoluteFile | ||
|
||
Files | ||
.walk(templatesRoot.toPath) | ||
.collect(Collectors.toList[java.nio.file.Path]) | ||
.asScala | ||
.filter(_.toString.endsWith(".scala")) | ||
.map({ path => | ||
val contents = IO.read(path.toFile, StandardCharsets.UTF_8) | ||
val newContents = contents | ||
.replace("${project.version}", (ThisBuild / version).value) | ||
val outputPath = file(path.toAbsolutePath.toString.replace(templatesRoot.toString, generatedSourcesRoot.toString)) | ||
IO.write(outputPath, newContents) | ||
outputPath | ||
}) | ||
} | ||
|
||
lazy val root = (project in file(".")) | ||
.settings( | ||
name := "ngrok-api-scala", | ||
scalacOptions ++= Seq( | ||
"-deprecation", | ||
"-encoding", "utf-8", | ||
"-feature", | ||
"-unchecked", | ||
"-Xlint:adapted-args", | ||
"-Xlint:constant", | ||
"-Xlint:deprecation", | ||
"-Xlint:infer-any", | ||
"-Xlint:missing-interpolator", | ||
"-Xlint:nullary-unit", | ||
"-Xlint:private-shadow", | ||
"-Xlint:type-parameter-shadow", | ||
), | ||
Compile / doc / scalacOptions ++= Seq( | ||
"-doc-title", "Ngrok API Documentation", | ||
"-doc-version", s"(${version.value})", | ||
"-implicits", | ||
"-groups", | ||
), | ||
libraryDependencies := Seq( | ||
scalaJava8, | ||
armeriaBom, | ||
armeria, | ||
circeCore, | ||
circeParser, | ||
scalaTest, | ||
wiremock, | ||
slf4jSimple, | ||
), | ||
Compile / sourceGenerators += generateSources.taskValue, | ||
publishMavenStyle := true, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
scala-api.docs.ngrok.com |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
<!DOCTYPE html ><html><head><meta http-equiv="X-UA-Compatible" content="IE=edge"/><meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/><title>ngrok API Documentation (0.1.0-SNAPSHOT) - com</title><meta content="ngrok API Documentation 0.1.0 - SNAPSHOT - com" name="description"/><meta content="ngrok API Documentation 0.1.0 SNAPSHOT com" name="keywords"/><meta http-equiv="content-type" content="text/html; charset=UTF-8"/><link href="../lib/index.css" media="screen" type="text/css" rel="stylesheet"/><link href="../lib/template.css" media="screen" type="text/css" rel="stylesheet"/><link href="../lib/print.css" media="print" type="text/css" rel="stylesheet"/><link href="../lib/diagrams.css" media="screen" type="text/css" rel="stylesheet" id="diagrams-css"/><script type="text/javascript" src="../lib/jquery.min.js"></script><script type="text/javascript" src="../lib/index.js"></script><script type="text/javascript" src="../index.js"></script><script type="text/javascript" src="../lib/scheduler.js"></script><script type="text/javascript" src="../lib/template.js"></script><script type="text/javascript">/* this variable can be used by the JS to determine the path to the root document */ | ||
var toRoot = '../';</script></head><body><div id="search"><span id="doc-title">ngrok API Documentation<span id="doc-version">(0.1.0-SNAPSHOT)</span></span> <span class="close-results"><span class="left"><</span> Back</span><div id="textfilter"><span class="input"><input autocapitalize="none" placeholder="Search" id="index-input" type="text" accesskey="/"/><i class="clear material-icons"></i><i id="search-icon" class="material-icons"></i></span></div></div><div id="search-results"><div id="search-progress"><div id="progress-fill"></div></div><div id="results-content"><div id="entity-results"></div><div id="member-results"></div></div></div><div id="content-scroll-container" style="-webkit-overflow-scrolling: touch;"><div id="content-container" style="-webkit-overflow-scrolling: touch;"><div id="subpackage-spacer"><div id="packages"><h1>Packages</h1><ul><li class="indented0 " name="_root_.root" group="Ungrouped" fullComment="yes" data-isabs="false" visbl="pub"><a id="_root_" class="anchorToMember"></a><a id="root:_root_" class="anchorToMember"></a> <span class="permalink"><a href="../index.html" title="Permalink"><i class="material-icons"></i></a></span> <span class="modifier_kind"><span class="modifier"></span> <span class="kind">package</span></span> <span class="symbol"><a href="../index.html" title=""><span class="name">root</span></a></span><div class="fullcomment"><dl class="attributes block"><dt>Definition Classes</dt><dd><a href="../index.html" name="_root_" id="_root_" class="extype">root</a></dd></dl></div></li><li class="indented1 current" name="_root_.com" group="Ungrouped" fullComment="yes" data-isabs="false" visbl="pub"><a id="com" class="anchorToMember"></a><a id="com:com" class="anchorToMember"></a> <span class="permalink"><a href="../com/index.html" title="Permalink"><i class="material-icons"></i></a></span> <span class="modifier_kind"><span class="modifier"></span> <span class="kind">package</span></span> <span class="symbol"><span class="name">com</span></span><div class="fullcomment"><dl class="attributes block"><dt>Definition Classes</dt><dd><a href="../index.html" name="_root_" id="_root_" class="extype">root</a></dd></dl></div></li><li class="indented2 " name="com.ngrok" group="Ungrouped" fullComment="no" data-isabs="false" visbl="pub"><a id="ngrok" class="anchorToMember"></a><a id="ngrok:ngrok" class="anchorToMember"></a> <span class="permalink"><a href="../com/ngrok/index.html" title="Permalink"><i class="material-icons"></i></a></span> <span class="modifier_kind"><span class="modifier"></span> <span class="kind">package</span></span> <span class="symbol"><a href="ngrok/index.html" title=""><span class="name">ngrok</span></a></span></li></ul></div></div><div id="content"><body class="package value"><div id="definition"><div class="big-circle package">p</div><h1>com<span class="permalink"><a href="../com/index.html" title="Permalink"><i class="material-icons"></i></a></span></h1></div><h4 id="signature" class="signature"><span class="modifier_kind"><span class="modifier"></span> <span class="kind">package</span></span> <span class="symbol"><span class="name">com</span></span></h4><div id="comment" class="fullcommenttop"></div><div id="template"><div id="allMembers"><div id="packages" class="package members"><h3>Package Members</h3><ol><li class="indented0 " name="com.ngrok" group="Ungrouped" fullComment="no" data-isabs="false" visbl="pub"><a id="ngrok" class="anchorToMember"></a><a id="ngrok:ngrok" class="anchorToMember"></a> <span class="permalink"><a href="../com/ngrok/index.html" title="Permalink"><i class="material-icons"></i></a></span> <span class="modifier_kind"><span class="modifier"></span> <span class="kind">package</span></span> <span class="symbol"><a href="ngrok/index.html" title=""><span class="name">ngrok</span></a></span></li></ol></div></div><div id="inheritedMembers"></div><div id="groupedMembers"><div name="Ungrouped" class="group"><h3>Ungrouped</h3></div></div></div><div id="tooltip"></div><div id="footer"></div></body></div></div></div></body></html> |
Oops, something went wrong.