Add more robust error handling to server

Changes:
- Use the proper RESTful HTTP status codes for all endpoints (e.g. 204 rather than 200 when the response body is empty)
- Add consistent and more helpful error messages
- Handle invalid route parameters by checking if jamid returns empty objects (e.g. invalid contact IDs)
- Use res.send() rather than res.json() for consistency
- Handle three new signals

GitLab: #111
Change-Id: I1d48dc4629995ab9a96bb2086a9aa91f81889598
diff --git a/server/src/routers/conversation-router.ts b/server/src/routers/conversation-router.ts
index 164ea3e..224962c 100644
--- a/server/src/routers/conversation-router.ts
+++ b/server/src/routers/conversation-router.ts
@@ -37,6 +37,10 @@
 // TODO: Create interface for return type in common/ when Records and interfaces are refactored
 async function createConversationResponseObject(accountId: string, accountUri: string, conversationId: string) {
   const infos = jamid.getConversationInfos(accountId, conversationId);
+  if (Object.keys(infos).length === 0) {
+    return undefined;
+  }
+
   const members = jamid.getConversationMembers(accountId, conversationId);
 
   const namedMembers = [];
@@ -94,21 +98,29 @@
   })
 );
 
-conversationRouter.post('/', (req: Request<ParamsDictionary, Record<string, string>, ConversationMembers>, res) => {
-  const accountId = res.locals.accountId;
+conversationRouter.post(
+  '/',
+  (req: Request<ParamsDictionary, Record<string, string> | string, ConversationMembers>, res) => {
+    const { members } = req.body;
+    if (members === undefined || members.length !== 1) {
+      res.status(HttpStatusCode.BadRequest).send('Missing members or more than one member in body');
+      return;
+    }
 
-  const { members } = req.body;
-  if (members === undefined || members.length !== 1) {
-    res.sendStatus(HttpStatusCode.BadRequest);
-    return;
+    const accountId = res.locals.accountId;
+
+    const contactId = members[0];
+    jamid.addContact(accountId, contactId);
+
+    const contactDetails = jamid.getContactDetails(accountId, contactId);
+    if (Object.keys(contactDetails).length === 0) {
+      res.status(HttpStatusCode.NotFound).send('No such member found');
+      return;
+    }
+
+    res.send(contactDetails);
   }
-
-  const contactId = members[0];
-  jamid.addContact(accountId, contactId);
-
-  const contactDetails = jamid.getContactDetails(accountId, contactId);
-  res.send(contactDetails);
-});
+);
 
 // TODO: Check if we actually need this endpoint to return messages.
 // Verify by checking what is truly needed in the client when migrating, to clean up the API.
@@ -124,13 +136,12 @@
     // Retrieve the URI of the current account (Account.username actually stores the URI rather than the username)
     const accountUri = jamid.getAccountDetails(accountId)['Account.username'];
 
-    const conversationIds = jamid.getConversationIds(accountId);
-    if (!conversationIds.includes(conversationId)) {
-      res.sendStatus(HttpStatusCode.NotFound);
+    const conversation = await createConversationResponseObject(accountId, accountUri, conversationId);
+    if (conversation === undefined) {
+      res.status(HttpStatusCode.NotFound).send('No such conversation found');
       return;
     }
 
-    const conversation = await createConversationResponseObject(accountId, accountUri, conversationId);
     res.send(conversation);
   })
 );
@@ -141,9 +152,9 @@
     const accountId = res.locals.accountId;
     const conversationId = req.params.conversationId;
 
-    const conversationIds = jamid.getConversationIds(accountId);
-    if (!conversationIds.includes(conversationId)) {
-      res.sendStatus(HttpStatusCode.NotFound);
+    const infos = jamid.getConversationInfos(accountId, conversationId);
+    if (Object.keys(infos).length === 0) {
+      res.status(HttpStatusCode.NotFound).send('No such conversation found');
       return;
     }
 
@@ -157,11 +168,20 @@
   (req: Request<ParamsDictionary, any, ConversationMessage>, res) => {
     const { message } = req.body;
     if (message === undefined) {
-      res.sendStatus(HttpStatusCode.BadRequest);
+      res.status(HttpStatusCode.BadRequest).send('Missing message in body');
       return;
     }
 
-    jamid.sendConversationMessage(res.locals.accountId, req.params.conversationId, message);
-    res.end();
+    const accountId = res.locals.accountId;
+    const conversationId = req.params.conversationId;
+
+    const infos = jamid.getConversationInfos(accountId, conversationId);
+    if (Object.keys(infos).length === 0) {
+      res.status(HttpStatusCode.NotFound).send('No such conversation found');
+      return;
+    }
+
+    jamid.sendConversationMessage(accountId, conversationId, message);
+    res.sendStatus(HttpStatusCode.NoContent);
   }
 );