Packages
oaspec
0.67.0
0.68.0
0.67.0
0.66.0
0.65.0
0.64.0
0.63.0
0.62.0
0.61.0
0.60.0
0.59.0
0.58.1
0.58.0
0.57.0
0.56.0
0.55.0
0.54.0
0.53.0
0.52.0
0.51.0
0.50.0
0.49.0
0.48.0
0.47.0
0.46.0
0.45.0
0.44.0
0.43.0
0.42.0
0.41.0
0.40.0
0.39.0
0.38.0
0.37.0
0.36.0
0.35.0
0.34.0
0.33.0
0.32.0
0.31.0
0.30.0
0.29.0
0.28.0
0.27.0
0.26.0
0.25.0
0.24.0
0.23.0
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.0
0.12.0
0.11.0
0.10.0
0.9.0
0.8.0
0.7.0
0.6.3
0.6.1
0.6.0
0.5.0
0.4.0
0.3.0
0.1.3
Generate Gleam code from OpenAPI 3.x specifications
Current section
Files
Jump to
Current section
Files
src/oaspec/internal/codegen/client_security.gleam
import gleam/bool
import gleam/dict
import gleam/list
import gleam/option.{Some}
import gleam/string
import oaspec/internal/codegen/context.{type Context}
import oaspec/internal/openapi/spec.{type Resolved}
/// Capitalize the first letter of a string. Used to render HTTP scheme
/// prefixes like `Bearer` / `Basic` / `Digest` in the emitted security
/// metadata.
pub fn capitalize_first(value: String) -> String {
case string.pop_grapheme(value) {
Ok(#(first, rest)) -> string.uppercase(first) <> rest
// nolint: thrown_away_error -- empty string has no first grapheme; fall back to the original value
Error(_) -> value
}
}
/// Render the OpenAPI security requirements for an operation as a Gleam
/// list-of-`SecurityAlternative` literal that can be inlined into a
/// generated `transport.Request`. Returns `"[]"` when the operation has
/// no security or when none of the listed schemes resolve.
pub fn render_security_metadata(
ctx: Context,
alternatives: List(spec.SecurityRequirement),
) -> String {
case alternatives {
[] -> "[]"
_ -> {
let rendered =
alternatives
|> list.filter_map(fn(alt) {
case render_alternative(ctx, alt) {
"" -> Error(Nil)
s -> Ok(s)
}
})
case rendered {
[] -> "[]"
_ -> "[" <> string.join(rendered, ", ") <> "]"
}
}
}
}
fn render_alternative(ctx: Context, alt: spec.SecurityRequirement) -> String {
let reqs =
alt.schemes
|> list.filter_map(fn(scheme_ref) { render_requirement(ctx, scheme_ref) })
case reqs {
[] -> ""
_ -> "transport.SecurityAlternative([" <> string.join(reqs, ", ") <> "])"
}
}
fn render_requirement(
ctx: Context,
scheme_ref: spec.SecuritySchemeRef,
) -> Result(String, Nil) {
case context.spec(ctx).components {
Some(components) ->
case dict.get(components.security_schemes, scheme_ref.scheme_name) {
Ok(spec.Value(scheme)) ->
case scheme {
spec.ApiKeyScheme(name: header_name, in_: spec.SchemeInHeader) ->
Ok(api_key(scheme_ref.scheme_name, "ApiKeyHeader", header_name))
spec.ApiKeyScheme(name: query_name, in_: spec.SchemeInQuery) ->
Ok(api_key(scheme_ref.scheme_name, "ApiKeyQuery", query_name))
spec.ApiKeyScheme(name: cookie_name, in_: spec.SchemeInCookie) ->
Ok(api_key(scheme_ref.scheme_name, "ApiKeyCookie", cookie_name))
spec.HttpScheme(scheme: prefix, ..) ->
Ok(http_authorization(
scheme_ref.scheme_name,
capitalize_first(prefix),
))
spec.OAuth2Scheme(..) | spec.OpenIdConnectScheme(..) ->
Ok(http_authorization(scheme_ref.scheme_name, "Bearer"))
_ -> Error(Nil)
}
_ -> Error(Nil)
}
_ -> Error(Nil)
}
}
fn api_key(scheme_name: String, variant: String, name: String) -> String {
"transport."
<> variant
<> "(scheme_name: \""
<> scheme_name
<> "\", "
<> field_label(variant)
<> ": \""
<> name
<> "\")"
}
fn http_authorization(scheme_name: String, prefix: String) -> String {
"transport.HttpAuthorization(scheme_name: \""
<> scheme_name
<> "\", prefix: \""
<> prefix
<> "\")"
}
fn field_label(variant: String) -> String {
case variant {
"ApiKeyHeader" -> "header_name"
"ApiKeyQuery" -> "query_name"
"ApiKeyCookie" -> "cookie_name"
_ -> "name"
}
}
/// Wrap a value expression with `uri.percent_encode` unless the parameter
/// declares `allowReserved: true`.
pub fn maybe_percent_encode(
value_expr: String,
param: spec.Parameter(Resolved),
) -> String {
use <- bool.guard(param.allow_reserved, value_expr)
"uri.percent_encode(" <> value_expr <> ")"
}