Add support for FQN entity names with leading forward slash (#83)

* Remove "experimental" API Gateway support.

Fixes #52

* 3.7.0

* 3.8.0

* Adding supporting for `responsetype` for route creation.

* 3.9.0

* Add support for FQN without leading forward slash.
Fixes #75
diff --git a/lib/names.js b/lib/names.js
index 7aaba8f..391d54a 100644
--- a/lib/names.js
+++ b/lib/names.js
@@ -12,21 +12,32 @@
 // - package/resource_name
 // - /namespace/resource_name
 // - /namespace/package/resource_name
+// - namespace/package/resource_name
 const parse_id_and_ns = resource => {
-  if (!resource.startsWith('/')) {
+  const parts = (resource.match(/\//g) || []).length
+  const names = resource.split('/')
+
+  // checking for `resource_name` and `package/resource_name`
+  if (parts === 0 ||
+     (parts === 1 && !resource.startsWith('/'))) {
     return { namespace: default_namespace(), id: resource }
   }
 
-  const paths = resource.split('/')
-
-  if (paths.length !== 3 && paths.length !== 4) {
-    throw new Error(messages.INVALID_RESOURCE_ERROR)
+  // checking for `/namespace/resource_name` and `namespace/package/resource_name`
+  if (parts === 2) {
+    if (resource.startsWith('/')) {
+      return { namespace: names[1], id: names[2] }
+    } else {
+      return { namespace: names[0], id: `${names[1]}/${names[2]}` }
+    }
   }
 
-  const id = paths.slice(2).join('/')
-  const namespace = paths[1]
+  // checking for `/namespace/package/resource_name`
+  if (parts === 3 && resource.startsWith('/')) {
+    return { namespace: names[1], id: `${names[2]}/${names[3]}` }
+  }
 
-  return { id, namespace }
+  throw new Error(messages.INVALID_RESOURCE_ERROR)
 }
 
 const parse_namespace = id => parse_id_and_ns(id).namespace
diff --git a/test/unit/names.test.js b/test/unit/names.test.js
index f9aaeae..b1a788b 100644
--- a/test/unit/names.test.js
+++ b/test/unit/names.test.js
@@ -20,38 +20,64 @@
   t.is(names.parse_namespace('hello'), '_')
 })
 
+test('should parse namespace from package resource without explicit ns', t => {
+  t.is(names.parse_namespace('pkg/hello'), '_')
+})
+
 test('should parse namespace from resource with explicit ns', t => {
   t.is(names.parse_namespace('/ns/hello'), 'ns')
 })
 
-test('should parse namespace from resource with explicit ns and package', t => {
+test('should parse namespace from package resource with explicit ns', t => {
   t.is(names.parse_namespace('/ns/pkg/hello'), 'ns')
 })
 
+test('should parse namespace from resource with explicit ns and package but missing leading slash', t => {
+  t.is(names.parse_namespace('ns/pkg/hello'), 'ns')
+})
+
 test('should throw error for resource with only namespace', t => {
   t.throws(() => names.parse_namespace('/ns'), /Invalid resource identifier/)
 })
 
 test('should throw error for resource with only extra paths', t => {
   t.throws(() => names.parse_namespace('/ns/pkg/action/extra'), /Invalid resource identifier/)
+  t.throws(() => names.parse_namespace('ns/pkg/action/extra'), /Invalid resource identifier/)
+})
+
+test('should throw error for resource with missing parts', t => {
+  t.throws(() => names.parse_namespace('/'), /Invalid resource identifier/)
 })
 
 test('should parse id from resource without explicit ns', t => {
   t.is(names.parse_id('hello'), 'hello')
 })
 
+test('should parse id from package resource without explicit ns', t => {
+  t.is(names.parse_id('pkg/hello'), 'pkg/hello')
+})
+
 test('should parse id from resource with explicit ns', t => {
   t.is(names.parse_id('/ns/hello'), 'hello')
 })
 
-test('should parse id from resource with explicit ns and package', t => {
+test('should parse id from package resource with explicit ns', t => {
   t.is(names.parse_id('/ns/pkg/hello'), 'pkg/hello')
 })
 
+test('should parse id from resource with explicit ns and package but missing leading slash', t => {
+  t.is(names.parse_id('ns/pkg/hello'), 'pkg/hello')
+})
+
 test('should throw error for resource with only namespace', t => {
   t.throws(() => names.parse_id('/ns'), /Invalid resource identifier/)
 })
 
 test('should throw error for resource with only extra paths', t => {
   t.throws(() => names.parse_id('/ns/pkg/action/extra'), /Invalid resource identifier/)
+  t.throws(() => names.parse_id('ns/pkg/action/extra'), /Invalid resource identifier/)
+})
+
+test('should throw error for resource with missing parts', t => {
+  t.throws(() => names.parse_id('/'), /Invalid resource identifier/)
 })