Repository: jupyterhub/jupyterhub
Pull request: consolidate server APIHandlers
no need for separate handlers for named and default servers

avoid claiming that empty responses are JSON.

Fixes 202 error handling by setting content-type: text/plain when sending empty responses.

Errors were raised in jQuery because response was empty but content-type header claimed it was application/json.

closes #1256


Problem statement:
'Stop server' raises an alert if it gets back a 202 Accepted
If stopping a server is slow, the JupyterHub API responds with a '202 Accepted'. The UI should do something with this - right now it just throws up an error box.

Hints from issue discussion:

Commit message: include non-empty body with 202 responses

reply claims to be application/json, so make sure it has some content

Patch to review:
diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py
index 24e2499317..5744e9c59b 100644
--- a/jupyterhub/apihandlers/users.py
+++ b/jupyterhub/apihandlers/users.py
@@ -156,9 +156,9 @@ def delete(self, name):
         yield gen.maybe_future(self.authenticator.delete_user(user))
         # remove from registry
         del self.users[user]
-        
+
         self.set_status(204)
-    
+
     @admin_only
     def patch(self, name):
         user = self.find_user(name)
@@ -194,6 +194,8 @@ def post(self, name):
         options = self.get_json_body()
         yield self.spawn_single_user(user, options=options)
         status = 202 if user.spawner._spawn_pending else 201
+        if status == 202:
+            self.write(json.dumps({"message": "Server is slow to start"}))
         self.set_status(status)
 
     @gen.coroutine
@@ -211,6 +213,8 @@ def delete(self, name):
             raise web.HTTPError(400, "%s's server is not running" % name)
         yield self.stop_single_user(user)
         status = 202 if user.spawner._stop_pending else 204
+        if status == 202:
+            self.write(json.dumps({"message": "Server is slow to stop"}))
         self.set_status(status)
 
 
@@ -232,6 +236,8 @@ def post(self, name, server_name):
         yield self.spawn_single_user(user, server_name, options=options)
         spawner = user.spawners[server_name]
         status = 202 if spawner._spawn_pending else 201
+        if status == 202:
+            self.write(json.dumps({"message": "Server is slow to start"}))
         self.set_status(status)
 
     @gen.coroutine
@@ -256,6 +262,8 @@ def delete(self, name, server_name):
             raise web.HTTPError(400, "%s's server %s is not running" % (name, server_name))
         yield self.stop_single_user(user, server_name)
         status = 202 if spawner._stop_pending else 204
+        if status == 202:
+            self.write(json.dumps({"message": "Server is slow to stop"}))
         self.set_status(status)
 
 


Code review comments:
diff_hunk: @@ -183,79 +183,49 @@ class UserServerAPIHandler(APIHandler):
     """
     @gen.coroutine
     @admin_or_self
-    def post(self, name):
+    def post(self, name, server_name=''):
path: jupyterhub/apihandlers/users.py
text: @user1:
Class docstring needs to be updated since allow_named_servers can be True.