Skip to content

Commit fb93494

Browse files
auth support
1 parent 135ecbd commit fb93494

3 files changed

Lines changed: 51 additions & 11 deletions

File tree

modules/openapi-generator/src/main/resources/scala-sttp4-jsoniter/api.mustache

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,43 @@ import sttp.model.Method
1414
1515
{{#operations}}
1616
object {{classname}}:
17-
def apply(baseUrl: String = "{{{basePath}}}") = new {{classname}}(baseUrl)
17+
def apply(baseUrl: String = "{{{basePath}}}"): {{classname}}[{{invokerPackage}}.Authorization.NoAuthorization.type] = {{classname}}(baseUrl, {{invokerPackage}}.Authorization.NoAuthorization)
18+
def withBasicAuth(baseUrl: String, username: String, password: String): {{classname}}[{{invokerPackage}}.Authorization.BasicAuth] =
19+
{{classname}}(baseUrl, {{invokerPackage}}.Authorization.BasicAuth(username, password))
20+
21+
def withApiKeyAuth(baseUrl: String, apiKey: String): {{classname}}[{{invokerPackage}}.Authorization.ApiKey] =
22+
{{classname}}(baseUrl, {{invokerPackage}}.Authorization.ApiKey(apiKey))
23+
24+
def withBearerTokenAuth(baseUrl: String, token: String): {{classname}}[{{invokerPackage}}.Authorization.BearerToken] =
25+
{{classname}}(baseUrl, {{invokerPackage}}.Authorization.BearerToken(token))
26+
27+
case class {{classname}}[Auth <: {{invokerPackage}}.Authorization] private (baseUrl: String, authConfig: {{invokerPackage}}.Authorization):
28+
def withBasicAuth(username: String, password: String): {{classname}}[{{invokerPackage}}.Authorization.BasicAuth] =
29+
copy(authConfig = {{invokerPackage}}.Authorization.BasicAuth(username, password))
30+
31+
def withApiKeyAuth(apiKey: String): {{classname}}[{{invokerPackage}}.Authorization.ApiKey] =
32+
copy(authConfig = {{invokerPackage}}.Authorization.ApiKey(apiKey))
33+
34+
def withNoAuth: {{classname}}[{{invokerPackage}}.Authorization.NoAuthorization.type] =
35+
copy(authConfig = {{invokerPackage}}.Authorization.NoAuthorization)
36+
37+
def withBearerTokenAuth(token: String): {{classname}}[{{invokerPackage}}.Authorization.BearerToken] =
38+
copy(authConfig = {{invokerPackage}}.Authorization.BearerToken(token))
1839
19-
class {{classname}}(baseUrl: String):
2040
{{#operation}}
2141
{{#javadocRenderer}}
2242
{{>javadoc}}
2343
{{/javadocRenderer}}
2444
def {{operationId}}{{>methodParameters}}: sttp.client4.Request[{{#separateErrorChannel}}Either[ResponseException[String], {{>operationReturnType}}]{{/separateErrorChannel}}{{^separateErrorChannel}}{{>operationReturnType}}{{/separateErrorChannel}}] =
2545
val requestURL =
2646
uri"$baseUrl{{{path}}}"{{#queryParams}}
27-
.addParams(FormSerializable.serialize("{{baseName}}", {{{paramName}}}{{#style}}, FormStyleFormat.{{style.toUpperCase}}{{/style}}{{^style}}, FormStyleFormat.FORM{{/style}}, {{isExplode}}): _*){{/queryParams}}{{#isApiKey}}{{#isKeyInQuery}}
28-
.addParams("{{keyParamName}}" -> apiKey.value){{/isKeyInQuery}}{{/isApiKey}}
47+
.addParams(FormSerializable.serialize("{{baseName}}", {{{paramName}}}{{#style}}, FormStyleFormat.{{style.toUpperCase}}{{/style}}{{^style}}, FormStyleFormat.FORM{{/style}}, {{isExplode}}): _*){{/queryParams}}
2948
3049
basicRequest
3150
.method(Method.{{httpMethod.toUpperCase}}, requestURL)
3251
.contentType({{#consumes.0}}"{{{mediaType}}}"{{/consumes.0}}{{^consumes}}"application/json"{{/consumes}}){{#headerParams}}
33-
.header({{>paramCreation}}){{/headerParams}}{{#authMethods}}{{#isBasic}}{{#isBasicBasic}}
34-
.auth.basic(username, password){{/isBasicBasic}}{{#isBasicBearer}}
35-
.auth.bearer(bearerToken){{/isBasicBearer}}{{/isBasic}}{{#isApiKey}}{{#isKeyInHeader}}
36-
.header("{{keyParamName}}", apiKey){{/isKeyInHeader}}{{#isKeyInCookie}}
37-
.cookie("{{keyParamName}}", apiKey){{/isKeyInCookie}}{{/isApiKey}}{{/authMethods}}{{#formParams.0}}{{^isMultipart}}
52+
.header({{>paramCreation}}){{/headerParams}}{{#authMethods}}
53+
.auth(authConfig{{#isApiKey}}, {{invokerPackage}}.{{#isKeyInQuery}}QUERY{{/isKeyInQuery}}{{#isKeyInHeader}}HEADER{{/isKeyInHeader}}{{#isKeyInCookie}}COOKIE{{/isKeyInCookie}}, "{{keyParamName}}"{{/isApiKey}}){{/authMethods}}{{#formParams.0}}{{^isMultipart}}
3854
.body({{#formParams}}
3955
{{>paramFormCreation}}{{^-last}} ++ {{/-last}}{{/formParams}},
4056
"utf-8"

modules/openapi-generator/src/main/resources/scala-sttp4-jsoniter/helpers.mustache

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@ import scala.deriving.*
55
import scala.compiletime.*
66
import java.io.File
77

8+
enum ApiKeyLocation:
9+
case HEADER
10+
case COOKIE
11+
case QUERY
12+
case NOAPIKEY
13+
14+
enum Authorization:
15+
case NoAuthorization
16+
case BasicAuth(username: String, password: String)
17+
case ApiKey(apiKey: String)
18+
case BearerToken(token: String)
19+
820
enum FormStyleFormat:
921
case FORM
1022
case SPACEDELIMITED
@@ -126,4 +138,16 @@ object Helpers:
126138
def fileBody(file: Option[File] | File): sttp.client4.Request[?] =
127139
file match
128140
case f: File => request.body(f)
129-
case f: Option[File] => f.map(request.body(_)).getOrElse(request)
141+
case f: Option[File] => f.map(request.body(_)).getOrElse(request)
142+
143+
def auth(authConfig: Authorization, location: ApiKeyLocation = ApiKeyLocation.NOAPIKEY, keyParamName: String = ""): sttp.client4.Request[?] =
144+
// multiple calls to auth with the same config are not idempotent only for APIKey with COOKIE and QUERY - that's why we have NOAPIKEY as default
145+
authConfig match
146+
case Authorization.NoAuthorization => request
147+
case Authorization.BasicAuth(username, password) => request.auth.basic(username, password)
148+
case Authorization.BearerToken(token) => request.auth.bearer(token)
149+
case Authorization.ApiKey(apiKey) =>location match
150+
case ApiKeyLocation.HEADER => request.header(keyParamName, apiKey)
151+
case ApiKeyLocation.COOKIE => request.cookie(keyParamName, apiKey)
152+
case ApiKeyLocation.QUERY => request.copy(uri = request.uri.addParam(keyParamName, apiKey))
153+
case ApiKeyLocation.NOAPIKEY => request // since it can be called multiple times in request (when there are for example 2 auth methods) we want to make this call idempotent
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{{#authMethods.0}}({{#authMethods}}{{#isApiKey}}apiKey: String{{/isApiKey}}{{#isBasic}}{{#isBasicBasic}}username: String, password: String{{/isBasicBasic}}{{#isBasicBearer}}bearerToken: String{{/isBasicBearer}}{{/isBasic}}{{^-last}}, {{/-last}}{{/authMethods}}){{/authMethods.0}}{{#allParams.0}}({{#allParams}}{{paramName}}: {{#required}}{{dataType}}{{/required}}{{^required}}{{#isContainer}}{{dataType}}{{/isContainer}}{{^isContainer}}Option[{{dataType}}]{{/isContainer}}{{/required}}{{^defaultValue}}{{^required}}{{^isContainer}} = scala.None{{/isContainer}}{{/required}}{{/defaultValue}}{{^-last}}, {{/-last}}{{/allParams}}){{/allParams.0}}
1+
{{#allParams.0}}({{#allParams}}{{paramName}}: {{#required}}{{dataType}}{{/required}}{{^required}}{{#isContainer}}{{dataType}}{{/isContainer}}{{^isContainer}}Option[{{dataType}}]{{/isContainer}}{{/required}}{{^defaultValue}}{{^required}}{{^isContainer}} = scala.None{{/isContainer}}{{/required}}{{/defaultValue}}{{^-last}}, {{/-last}}{{/allParams}}){{/allParams.0}}{{#authMethods.0}}(using Auth <:< {{#authMethods}}{{#isApiKey}}{{invokerPackage}}.Authorization.ApiKey{{/isApiKey}}{{#isBasic}}{{#isBasicBasic}}{{invokerPackage}}.Authorization.BasicAuth{{/isBasicBasic}}{{#isBasicBearer}}{{invokerPackage}}.Authorization.BearerToken{{/isBasicBearer}}{{/isBasic}}{{^-last}} | {{/-last}}{{/authMethods}}){{/authMethods.0}}

0 commit comments

Comments
 (0)