Skip to content

Commit

Permalink
support routes on apis
Browse files Browse the repository at this point in the history
  • Loading branch information
Zwiterrion committed Jan 16, 2025
1 parent a8e0e9d commit 39a2b7c
Show file tree
Hide file tree
Showing 9 changed files with 482 additions and 96 deletions.
22 changes: 21 additions & 1 deletion otoroshi/app/api/api.scala
Original file line number Diff line number Diff line change
Expand Up @@ -879,7 +879,27 @@ class OtoroshiResources(env: Env) {
stateOne = id => env.proxyState.api(id),
stateUpdate = seq => env.proxyState.updateApis(seq)
)
)
),
// //////
// Resource(
// "Flow",
// "flows",
// "flow",
// "flows.otoroshi.io",
// ResourceVersion("v1", true, false, true),
// GenericResourceAccessApiWithState[Flow](
// Flow.format,
// classOf[Flow],
// env.datastores.flowDataStore.key,
// env.datastores.flowDataStore.extractId,
// json => json.select("id").asString,
// () => "id",
// (_v, _p) => env.datastores.flowDataStore.template(env).json,
// stateAll = () => env.proxyState.allFlows(),
// stateOne = id => env.proxyState.flow(id),
// stateUpdate = seq => env.proxyState.updateFlows(seq)
// )
// )
) ++ env.adminExtensions.resources()
}

Expand Down
5 changes: 5 additions & 0 deletions otoroshi/app/next/controllers/frontends.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class NgFrontendsController(val ApiAction: ApiAction, val cc: ControllerComponen

lazy val logger = Logger("otoroshi-frontends-api")

// TODO - ???
def form() = ApiAction {
env.openApiSchema.asForms.get("otoroshi.next.models.NgFrontend") match {
case Some(value) =>
Expand All @@ -42,4 +43,8 @@ class NgFrontendsController(val ApiAction: ApiAction, val cc: ControllerComponen
case _ => NotFound(Json.obj("error" -> "Schema and flow not found"))
}
}

def template() = ApiAction {
Ok(NgFrontend.empty.json)
}
}
59 changes: 37 additions & 22 deletions otoroshi/app/next/models/Api.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import otoroshi.next.plugins.NgApikeyCallsConfig
import otoroshi.security.IdGenerator
import otoroshi.storage.{BasicStore, RedisLike, RedisLikeStore}
import otoroshi.utils.syntax.implicits.{BetterJsReadable, BetterJsValue}
import play.api.libs.json.{Format, JsArray, JsError, JsResult, JsString, JsSuccess, JsValue, Json}
import play.api.libs.json.{Format, JsArray, JsBoolean, JsError, JsNull, JsNumber, JsObject, JsResult, JsString, JsSuccess, JsValue, Json}

import scala.util.{Failure, Success, Try}

Expand Down Expand Up @@ -65,16 +65,18 @@ case object ApiRemoved extends ApiState {
// }
//}

case class ApiRoute(frontend: NgFrontend, flows: String, backend: String)
case class ApiRoute(id: String, name: Option[String], frontend: NgFrontend, flowRef: String, backend: ApiBackend)

object ApiRoute {
val _fmt = new Format[ApiRoute] {

override def reads(json: JsValue): JsResult[ApiRoute] = Try {
ApiRoute(
frontend = NgFrontend.readFrom((json \ "frontend")),
flows = (json \ "flows").as[String],
backend = (json \ "backend").as[String]
id = json.select("id").as[String],
name = json.select("name").asOpt[String],
frontend = NgFrontend.readFrom(json \ "frontend"),
flowRef = (json \ "flow_ref").as[String],
backend = (json \ "backend").as[ApiBackend](ApiBackend._fmt)
)
} match {
case Failure(ex) =>
Expand All @@ -84,7 +86,11 @@ object ApiRoute {
}

override def writes(o: ApiRoute): JsValue = Json.obj(

"id" -> o.id,
"name" -> o.name,
"frontend" -> o.frontend.json,
"backend" -> ApiBackend._fmt.writes(o.backend),
"flow_ref" -> o.flowRef
)
}
}
Expand Down Expand Up @@ -260,9 +266,7 @@ object ApiDocumentation {
.getOrElse(Seq.empty)
)
} match {
case Failure(ex) =>
ex.printStackTrace()
JsError(ex.getMessage)
case Failure(ex) => JsError(ex.getMessage)
case Success(value) => JsSuccess(value)
}

Expand Down Expand Up @@ -474,29 +478,39 @@ object ApiConsumerStatus {
}
}

case class ApiBackend(id: String, name: String, backend: NgBackend)
sealed trait ApiBackend

object ApiBackend {
val _fmt: Format[ApiBackend] = new Format[ApiBackend] {
case class ApiBackendRef(ref: String) extends ApiBackend
case class ApiBackendInline(id: String, name: String, backend: NgBackend) extends ApiBackend

val _fmt: Format[ApiBackend] = new Format[ApiBackend] {
override def reads(json: JsValue): JsResult[ApiBackend] = Try {
ApiBackend(
id = json.select("id").as[String],
name = json.select("name").as[String],
backend = json.select("backend").as(NgBackend.fmt)
)
json.select("ref").asOpt[String] match {
case Some(ref) => ApiBackendRef(ref)
case None => ApiBackendInline(
id = json.select("id").as[String],
name = json.select("name").as[String],
backend = json.select("backend").as(NgBackend.fmt)
)
}
} match {
case Failure(ex) =>
ex.printStackTrace()
JsError(ex.getMessage)
case Success(value) => JsSuccess(value)
}

override def writes(o: ApiBackend): JsValue = Json.obj(
"id" -> o.id,
"name" -> o.name,
"backend" -> NgBackend.fmt.writes(o.backend)
)
override def writes(o: ApiBackend): JsValue = {
o match {
case ApiBackendRef(ref) => Json.obj("ref" -> ref)
case ApiBackendInline(id, name, backend) => Json.obj(
"id" -> id,
"name" -> name,
"backend" -> NgBackend.fmt.writes(backend)
)
}
}
}
}

Expand Down Expand Up @@ -628,7 +642,8 @@ object Api {
.asOpt[Seq[JsValue]]
.map(_.flatMap(v => ApiBackendClient._fmt.reads(v).asOpt))
.getOrElse(Seq.empty),
documentation = ApiDocumentation._fmt.reads((json \ "documentation").as[JsValue]).asOpt,
documentation = (json \ "documentation")
.asOpt[ApiDocumentation](ApiDocumentation._fmt.reads),
consumers = (json \ "consumers")
.asOpt[Seq[JsValue]]
.map(_.flatMap(v => ApiConsumer._fmt.reads(v).asOpt))
Expand Down
2 changes: 2 additions & 0 deletions otoroshi/conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,9 @@ GET /api/backends otoroshi.next.controllers.adminap
POST /api/backends otoroshi.next.controllers.adminapi.NgBackendsController.createAction()

## Frontends
## TODO - remove this endpoint
GET /api/frontends/_form otoroshi.next.controllers.adminapi.NgFrontendsController.form()
GET /api/frontends/_template otoroshi.next.controllers.adminapi.NgFrontendsController.template()

## Plugins
GET /api/plugins/categories otoroshi.next.controllers.NgPluginsController.categories()
Expand Down
7 changes: 6 additions & 1 deletion otoroshi/javascript/src/components/Drafts/DraftEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ import { PillButton } from '../PillButton';
import JsonViewCompare from './Compare';
import { Button } from '../Button';

const queryClient = new QueryClient();
const queryClient = new QueryClient({
queries: {
retry: false,
refetchOnWindowFocus: false
},
});

function findDraftByEntityId(id) {
return nextClient.forEntityNext(nextClient.ENTITIES.DRAFTS).findById(id);
Expand Down
47 changes: 23 additions & 24 deletions otoroshi/javascript/src/components/nginputs/inputs.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,8 @@ export class NgDotsRenderer extends Component {

return (
<button
className={`btn btn-radius-25 btn-sm ${
backgroundColorFromOption ? '' : selected ? 'btn-primary' : 'btn-dark'
} me-1 px-3 mb-1`}
className={`btn btn-radius-25 btn-sm ${backgroundColorFromOption ? '' : selected ? 'btn-primary' : 'btn-dark'
} me-1 px-3 mb-1`}
type="button"
key={rawOption}
style={style}
Expand Down Expand Up @@ -605,10 +604,10 @@ export class NgBoxBooleanRenderer extends Component {
const Container = this.props.rawDisplay
? ({ children }) => children
: ({ children }) => (
<div className={`row mb-${margin} ${className || ''}`}>
<div className="col-sm-10 ms-auto">{children}</div>
</div>
);
<div className={`row mb-${margin} ${className || ''}`}>
<div className="col-sm-10 ms-auto">{children}</div>
</div>
);

return (
<Container>
Expand Down Expand Up @@ -688,8 +687,8 @@ export class NgArrayRenderer extends Component {
form: () => ({
...this.generateDefaultValue(current.schema),
}),
object: () => {},
json: () => {},
object: () => { },
json: () => { },
});

generateDefaultValue = (obj) => {
Expand Down Expand Up @@ -883,21 +882,21 @@ export class NgObjectRenderer extends Component {
itemRenderer={
ItemRenderer
? (key, value, idx) => (
<ItemRenderer
embedded
flow={this.props.flow}
schema={this.props.schema}
value={value}
key={key}
idx={idx}
onChange={(e) => {
const newObject = this.props.value ? { ...this.props.value } : {};
newObject[key] = e;
this.props.onChange(newObject);
}}
{...props}
/>
)
<ItemRenderer
embedded
flow={this.props.flow}
schema={this.props.schema}
value={value}
key={key}
idx={idx}
onChange={(e) => {
const newObject = this.props.value ? { ...this.props.value } : {};
newObject[key] = e;
this.props.onChange(newObject);
}}
{...props}
/>
)
: null
}
/>
Expand Down
2 changes: 1 addition & 1 deletion otoroshi/javascript/src/forms/ng_plugins/NgBackend.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default {
field: 'backend',
schema: {
root: {
label: 'root',
label: 'Root',
type: 'string',
help: 'The root URL of the target service',
},
Expand Down
2 changes: 1 addition & 1 deletion otoroshi/javascript/src/forms/ng_plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ import NgApiFrontend from './NgApiFrontend';
import NgApiBackend from './NgApiBackend';

export const Backend = NgBackend;
export const Frontend = NgApiFrontend;
export const Frontend = NgFrontend;
export const ApiFrontend = NgApiFrontend;
export const ApiBackend = NgApiBackend;

Expand Down
Loading

0 comments on commit 39a2b7c

Please sign in to comment.