Repository: mlrun/mlrun

Issue:
httpd/db artifacts broken
@tebeka the artifacts get/store etc is broken 

a. you must use the `artifact.to_json()` vs dumps like in filedb, since `to_json()` accounts for model details, also `body` is not stored in the DB

b. artifacts object path should be `/artifact/<project>/<uid/tag>/<key>'  (key not as arg)
, (uid/tag is like a git tree and can also list all keys in a tree)

https://github.com/mlrun/mlrun/blob/0935dda40fb3a5db551a4b4e269adbac4813a792/mlrun/db/httpdb.py#L142

Comments:

Patch:
diff --git a/mlrun/db/httpd.py b/mlrun/db/httpd.py
index e9c53354..1ed01fcd 100644
--- a/mlrun/db/httpd.py
+++ b/mlrun/db/httpd.py
@@ -20,7 +20,6 @@ from http import HTTPStatus
 
 from flask import Flask, jsonify, request
 
-from mlrun.artifacts import Artifact
 from mlrun.db import RunDBError
 from mlrun.db.filedb import FileRunDB
 from mlrun.utils import logger
@@ -218,15 +217,10 @@ def store_artifact(project, uid):
     _file_db.store_artifact(key, data, uid, tag, project)
     return jsonify(ok=True)
 
-# curl http://localhost:8080/artifact/p1&key=k&tag=t
-@app.route('/artifact/<project>/<uid>', methods=['GET'])
+# curl http://localhost:8080/artifact/p1/tag/key
+@app.route('/artifact/<project>/<tag>/<path:key>', methods=['GET'])
 @catch_err
-def read_artifact(project, uid):
-    key = request.args.get('key')
-    if not key:
-        return json_error(HTTPStatus.BAD_REQUEST, reason='missing data')
-
-    tag = request.args.get('tag', '')
+def read_artifact(project, tag, key):
     data = _file_db.read_artifact(key, tag, project)
     return data
 
diff --git a/mlrun/db/httpdb.py b/mlrun/db/httpdb.py
index cf516fff..6080a32c 100644
--- a/mlrun/db/httpdb.py
+++ b/mlrun/db/httpdb.py
@@ -93,13 +93,13 @@ class HTTPRunDB(RunDBInterface):
         path = self._path_of('run', project, uid)
         error = f'store run {project}/{uid}'
         params = {'commit': bool2str(commit)}
-        body = dict_to_json(struct)
+        body = _as_json(struct)
         self._api_call('POST', path, error, params, body=body)
 
     def update_run(self, updates: dict, uid, project=''):
         path = self._path_of('run', project, uid)
         error = f'update run {project}/{uid}'
-        body = dict_to_json(updates)
+        body = _as_json(updates)
         self._api_call('PATCH', path, error, body=body)
 
     def read_run(self, uid, project=''):
@@ -149,17 +149,17 @@ class HTTPRunDB(RunDBInterface):
         }
 
         error = f'store artifact {project}/{uid}'
+
+        body = _as_json(artifact)
         self._api_call(
-            'POST', path, error, params=params, body=dict_to_json(artifact))
+            'POST', path, error, params=params, body=body)
 
     def read_artifact(self, key, tag='', project=''):
-        path = self._path_of('artifact', project, key)  # TODO: uid?
-        params = {
-            'key': key,
-            'tag': tag,
-        }
+        project = project or default_project
+        tag = tag or 'latest'
+        path = self._path_of('artifact', project, tag, key)
         error = f'read artifact {project}/{key}'
-        resp = self._api_call('GET', path, error, params=params)
+        resp = self._api_call('GET', path, error)
         return resp.content
 
     def del_artifact(self, key, tag='', project=''):
@@ -197,3 +197,10 @@ class HTTPRunDB(RunDBInterface):
         }
         error = 'del artifacts'
         self._api_call('DELETE', 'artifacts', error, params=params)
+
+
+def _as_json(obj):
+    fn = getattr(obj, 'to_json', None)
+    if fn:
+        return fn()
+    return dict_to_json(obj)


Test patch:
diff --git a/tests/test_httpdb.py b/tests/test_httpdb.py
index e432064e..88b04ccd 100644
--- a/tests/test_httpdb.py
+++ b/tests/test_httpdb.py
@@ -157,7 +157,7 @@ def test_artifact(create_server):
     db = server.conn
 
     prj, uid, key, body = 'p7', 'u199', 'k800', 'cucumber'
-    artifact = Artifact(key, body).to_dict()
+    artifact = Artifact(key, body)
 
     db.store_artifact(key, artifact, uid, project=prj)
     # TODO: Need a run file
@@ -168,7 +168,7 @@ def test_artifacts(create_server):
     server: Server = create_server()
     db = server.conn
     prj, uid, key, body = 'p9', 'u19', 'k802', 'tomato'
-    artifact = Artifact(key, body).to_dict()
+    artifact = Artifact(key, body)
 
     db.store_artifact(key, artifact, uid, project=prj)
     artifacts = db.list_artifacts(project=prj)