mirror of
https://github.com/edufeed-org/amb-api.git
synced 2025-12-07 23: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"}
|
||||
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"}
|
||||
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"}}
|
||||
|
||||
: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
|
||||
(:require [io.pedestal.http :as http]
|
||||
[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]
|
||||
{:status 200 :body "Hello, world!"})
|
||||
(defn validate [resources]
|
||||
(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
|
||||
(route/expand-routes
|
||||
#{["/greet" :get respond-hello :route-name :greet]
|
||||
["/user" :get resources-by-user :route-name :user]}))
|
||||
#{["/resources" :get resources-by-user :route-name :resources]}))
|
||||
|
||||
(def service-map
|
||||
{::http/routes routes
|
||||
::http/type :jetty
|
||||
::http/port 8890})
|
||||
|
||||
(defn create-service []
|
||||
(http/create-server
|
||||
{::http/routes routes
|
||||
::http/type :jetty
|
||||
::http/port 8890}))
|
||||
(http/create-server service-map))
|
||||
|
||||
(defn start []
|
||||
(http/start (create-service)))
|
||||
|
||||
(comment
|
||||
(http/stop (create-service)))
|
||||
|
||||
(defrecord WebServer []
|
||||
component/Lifecycle
|
||||
(start [this]
|
||||
|
|
@ -37,3 +97,23 @@
|
|||
|
||||
(defn new-web-server []
|
||||
(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