mirror of
https://github.com/edufeed-org/amb-api.git
synced 2025-12-10 00:34:33 +00:00
Endpoint working and validating against amb schema
This commit is contained in:
parent
0b6513bae2
commit
e5ff9265b4
5 changed files with 260 additions and 13 deletions
18
.clj-kondo/imports/io.pedestal/pedestal.log/config.edn
Normal file
18
.clj-kondo/imports/io.pedestal/pedestal.log/config.edn
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
; Copyright 2024 Nubank NA
|
||||||
|
|
||||||
|
; The use and distribution terms for this software are covered by the
|
||||||
|
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0)
|
||||||
|
; which can be found in the file epl-v10.html at the root of this distribution.
|
||||||
|
;
|
||||||
|
; By using this software in any fashion, you are agreeing to be bound by
|
||||||
|
; the terms of this license.
|
||||||
|
;
|
||||||
|
; You must not remove this notice, or any other, from this software.
|
||||||
|
|
||||||
|
{:hooks
|
||||||
|
{:analyze-call
|
||||||
|
{io.pedestal.log/trace hooks.io.pedestal.log/log-expr
|
||||||
|
io.pedestal.log/debug hooks.io.pedestal.log/log-expr
|
||||||
|
io.pedestal.log/info hooks.io.pedestal.log/log-expr
|
||||||
|
io.pedestal.log/warn hooks.io.pedestal.log/log-expr
|
||||||
|
io.pedestal.log/error hooks.io.pedestal.log/log-expr}}}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
; Copyright 2024 Nubank NA
|
||||||
|
|
||||||
|
; The use and distribution terms for this software are covered by the
|
||||||
|
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0)
|
||||||
|
; which can be found in the file epl-v10.html at the root of this distribution.
|
||||||
|
;
|
||||||
|
; By using this software in any fashion, you are agreeing to be bound by
|
||||||
|
; the terms of this license.
|
||||||
|
;
|
||||||
|
; You must not remove this notice, or any other, from this software.
|
||||||
|
|
||||||
|
(ns hooks.io.pedestal.log
|
||||||
|
(:require [clj-kondo.hooks-api :as api]))
|
||||||
|
|
||||||
|
(defn log-expr
|
||||||
|
"Expands (log-expr :a :A :b :B ... )
|
||||||
|
to (hash-map :a :A :b :B ... ) per clj-kondo examples."
|
||||||
|
[{:keys [:node]}]
|
||||||
|
(let [[k v & _kvs] (rest (:children node))]
|
||||||
|
(when-not (and k v)
|
||||||
|
(throw (ex-info "No kv pair provided" {})))
|
||||||
|
(let [new-node (api/list-node
|
||||||
|
(list*
|
||||||
|
(api/token-node 'hash-map)
|
||||||
|
(rest (:children node))))]
|
||||||
|
{:node (vary-meta new-node assoc :clj-kondo/ignore [:unused-value])})))
|
||||||
6
deps.edn
6
deps.edn
|
|
@ -1,8 +1,10 @@
|
||||||
{:deps {org.clojure/clojure {:mvn/version "1.12.0"}
|
{:paths ["src" "resources"]
|
||||||
|
:deps {org.clojure/clojure {:mvn/version "1.12.0"}
|
||||||
com.stuartsierra/component {:mvn/version "1.1.0"}
|
com.stuartsierra/component {:mvn/version "1.1.0"}
|
||||||
io.pedestal/pedestal.service {:mvn/version "0.7.2"}
|
cheshire/cheshire {:mvn/version "5.13.0"}
|
||||||
io.pedestal/pedestal.jetty {:mvn/version "0.7.1"}
|
io.pedestal/pedestal.jetty {:mvn/version "0.7.1"}
|
||||||
org.slf4j/slf4j-simple {:mvn/version "2.0.10"}
|
org.slf4j/slf4j-simple {:mvn/version "2.0.10"}
|
||||||
|
luposlip/json-schema {:mvn/version "0.4.6"}
|
||||||
net.clojars.laoc/nostr {:local/root "/home/laoc/coding/nostr-clj"}}
|
net.clojars.laoc/nostr {:local/root "/home/laoc/coding/nostr-clj"}}
|
||||||
|
|
||||||
:aliases
|
:aliases
|
||||||
|
|
|
||||||
121
resources/schema.json
Normal file
121
resources/schema.json
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"$id": "https://w3id.org/kim/amb/20231019/schemas/schema.json",
|
||||||
|
"title": "OER",
|
||||||
|
"description": "This is a generic JSON schema for describing an Open Educational Resource with schema.org",
|
||||||
|
"type": "object",
|
||||||
|
"default": {
|
||||||
|
"@context": [
|
||||||
|
"https://w3id.org/kim/amb/context.jsonld",
|
||||||
|
{
|
||||||
|
"@language": "de"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": ["LearningResource"]
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"@context": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/context-schema.json"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/id.json"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/type.json"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/name.json"
|
||||||
|
},
|
||||||
|
"creator": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/creator.json"
|
||||||
|
},
|
||||||
|
"contributor": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/contributor.json"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/description.json"
|
||||||
|
},
|
||||||
|
"about": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/about.json"
|
||||||
|
},
|
||||||
|
"license": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/license.json"
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/image.json"
|
||||||
|
},
|
||||||
|
"trailer": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/trailer.json"
|
||||||
|
},
|
||||||
|
"dateCreated": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/dateCreated.json"
|
||||||
|
},
|
||||||
|
"datePublished": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/datePublished.json"
|
||||||
|
},
|
||||||
|
"dateModified": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/dateModified.json"
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/duration.json"
|
||||||
|
},
|
||||||
|
"inLanguage": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/inLanguage.json"
|
||||||
|
},
|
||||||
|
"publisher": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/publisher.json"
|
||||||
|
},
|
||||||
|
"learningResourceType": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/learningResourceType.json"
|
||||||
|
},
|
||||||
|
"audience": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/audience.json"
|
||||||
|
},
|
||||||
|
"isBasedOn": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/isBasedOn.json"
|
||||||
|
},
|
||||||
|
"isPartOf": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/isPartOf.json"
|
||||||
|
},
|
||||||
|
"hasPart": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/hasPart.json"
|
||||||
|
},
|
||||||
|
"mainEntityOfPage": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/mainEntityOfPage.json"
|
||||||
|
},
|
||||||
|
"keywords": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/keywords.json"
|
||||||
|
},
|
||||||
|
"encoding": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/encoding.json"
|
||||||
|
},
|
||||||
|
"caption": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/caption.json"
|
||||||
|
},
|
||||||
|
"conditionsOfAccess": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/conditionsOfAccess.json"
|
||||||
|
},
|
||||||
|
"funder": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/funder.json"
|
||||||
|
},
|
||||||
|
"assesses": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/assesses.json"
|
||||||
|
},
|
||||||
|
"competencyRequired": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/competencyRequired.json"
|
||||||
|
},
|
||||||
|
"teaches": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/teaches.json"
|
||||||
|
},
|
||||||
|
"educationalLevel": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/educationalLevel.json"
|
||||||
|
},
|
||||||
|
"isAccessibleForFree": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/isAccessibleForFree.json"
|
||||||
|
},
|
||||||
|
"interactivityType": {
|
||||||
|
"$ref": "https://w3id.org/kim/amb/20231019/schemas/interactivityType.json"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["@context", "id", "name", "type"]
|
||||||
|
}
|
||||||
|
|
@ -1,28 +1,88 @@
|
||||||
(ns app.components.webserver
|
(ns app.components.webserver
|
||||||
(:require [io.pedestal.http :as http]
|
(:require [io.pedestal.http :as http]
|
||||||
[com.stuartsierra.component :as component]
|
[com.stuartsierra.component :as component]
|
||||||
[io.pedestal.http.route :as route]))
|
[io.pedestal.http.route :as route]
|
||||||
|
[nostr.core :as nostr]
|
||||||
|
[nostr.edufeed :as edufeed]
|
||||||
|
[cheshire.core :as json]
|
||||||
|
[json-schema.core :as json-schema]
|
||||||
|
[clojure.core.async :refer [go chan >! <!]]))
|
||||||
|
|
||||||
(defn respond-hello [request]
|
(defn validate [resources]
|
||||||
{:status 200 :body "Hello, world!"})
|
(let [schema (json-schema/prepare-schema
|
||||||
|
(-> "resources/schema.json"
|
||||||
|
slurp
|
||||||
|
(cheshire.core/parse-string true)))]
|
||||||
|
(try
|
||||||
|
(let [validation-results
|
||||||
|
(map (fn [resource]
|
||||||
|
(try
|
||||||
|
(when (json-schema/validate schema resource)
|
||||||
|
{:valid true :resource resource})
|
||||||
|
(catch Exception e
|
||||||
|
{:valid false :error e :resource resource})))
|
||||||
|
resources)]
|
||||||
|
(do
|
||||||
|
;; Log invalid resources
|
||||||
|
(doseq [{:keys [error resource]} (filter #(not (:valid %)) validation-results)]
|
||||||
|
(println "Invalid resource:" resource "Error:" error))
|
||||||
|
;; Return only valid resources
|
||||||
|
(->> validation-results
|
||||||
|
(filter :valid)
|
||||||
|
(map :resource))))
|
||||||
|
(catch Exception e
|
||||||
|
(println "Unexpected error during validation" e)
|
||||||
|
[]))))
|
||||||
|
|
||||||
(defn resources-by-user [request]
|
|
||||||
{:status 200 :body "hello user"})
|
(defn ok [body]
|
||||||
|
{:status 200 :body body})
|
||||||
|
|
||||||
|
;; Async pedestal
|
||||||
|
(defn get-resources [request]
|
||||||
|
(let [result-chan (chan)]
|
||||||
|
(go
|
||||||
|
(let [npub (get-in request [:query-params :npub])
|
||||||
|
pk (get-in request [:query-params :pk])
|
||||||
|
filter (if pk
|
||||||
|
{:kinds [30142] :authors [pk]}
|
||||||
|
{:kinds [30142]})
|
||||||
|
resources (nostr/fetch-events "ws://localhost:7778" filter)
|
||||||
|
transformed (map #(edufeed/convert-30142-to-nostr-amb % true true) resources)
|
||||||
|
validate (validate transformed)
|
||||||
|
resp (if validate
|
||||||
|
transformed
|
||||||
|
{:response "Some error occured during validation against AMB Scheme. Better give you nothing than wrong data"})]
|
||||||
|
(>! result-chan (json/generate-string resp))))
|
||||||
|
result-chan))
|
||||||
|
|
||||||
|
(def resources-by-user
|
||||||
|
{:name ::resources-by-user
|
||||||
|
:enter (fn [context]
|
||||||
|
(go
|
||||||
|
(let [result (<! (get-resources (:request context)))
|
||||||
|
;; TODO check against amb schema
|
||||||
|
]
|
||||||
|
(assoc context :response (ok result)))))})
|
||||||
|
|
||||||
(def routes
|
(def routes
|
||||||
(route/expand-routes
|
(route/expand-routes
|
||||||
#{["/greet" :get respond-hello :route-name :greet]
|
#{["/resources" :get resources-by-user :route-name :resources]}))
|
||||||
["/user" :get resources-by-user :route-name :user]}))
|
|
||||||
|
(def service-map
|
||||||
|
{::http/routes routes
|
||||||
|
::http/type :jetty
|
||||||
|
::http/port 8890})
|
||||||
|
|
||||||
(defn create-service []
|
(defn create-service []
|
||||||
(http/create-server
|
(http/create-server service-map))
|
||||||
{::http/routes routes
|
|
||||||
::http/type :jetty
|
|
||||||
::http/port 8890}))
|
|
||||||
|
|
||||||
(defn start []
|
(defn start []
|
||||||
(http/start (create-service)))
|
(http/start (create-service)))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(http/stop (create-service)))
|
||||||
|
|
||||||
(defrecord WebServer []
|
(defrecord WebServer []
|
||||||
component/Lifecycle
|
component/Lifecycle
|
||||||
(start [this]
|
(start [this]
|
||||||
|
|
@ -37,3 +97,23 @@
|
||||||
|
|
||||||
(defn new-web-server []
|
(defn new-web-server []
|
||||||
(map->WebServer {}))
|
(map->WebServer {}))
|
||||||
|
|
||||||
|
;; For interactive development
|
||||||
|
(defonce server (atom nil))
|
||||||
|
|
||||||
|
(defn start-dev []
|
||||||
|
(reset! server
|
||||||
|
(http/start (http/create-server
|
||||||
|
(assoc service-map
|
||||||
|
::http/join? false)))))
|
||||||
|
|
||||||
|
(defn stop-dev []
|
||||||
|
(http/stop @server))
|
||||||
|
|
||||||
|
(defn restart []
|
||||||
|
(stop-dev)
|
||||||
|
(start-dev))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(start-dev)
|
||||||
|
(restart))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue