diff --git a/cmd/serve.go b/cmd/serve.go index 44afbfa8..e2ca14d0 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -69,14 +69,19 @@ func serve() { didUrl := c.Param("did") log.Debug().Msgf("DID: %s", didUrl) - accept := strings.Split(c.Request().Header.Get(echo.HeaderAccept), ";")[0] + accept := c.Request().Header.Get(echo.HeaderAccept) log.Trace().Msgf("Accept: %s", accept) - requestedContentType := types.ContentType(accept) - if accept == "*/*" { + var requestedContentType types.ContentType + + if strings.Contains(accept, "*/*") || strings.Contains(accept, string(types.DIDJSONLD)) { requestedContentType = types.DIDJSONLD - } else if strings.Contains(accept, string(types.HTML)) { - requestedContentType = types.HTML + } else if strings.Contains(accept, string(types.DIDJSON)) { + requestedContentType = types.DIDJSON + } else if strings.Contains(accept, string(types.JSONLD)) { + requestedContentType = types.JSONLD + } else { + requestedContentType = types.JSON } log.Debug().Msgf("Requested content type: %s", requestedContentType) diff --git a/services/request_service.go b/services/request_service.go index 3b59c072..fd1025ef 100644 --- a/services/request_service.go +++ b/services/request_service.go @@ -4,7 +4,6 @@ import ( // jsonpb Marshaller is deprecated, but is needed because there's only one way to proto // marshal in combination with our proto generator version "encoding/json" - "fmt" "github.com/rs/zerolog/log" @@ -45,12 +44,6 @@ func (rs RequestService) ProcessDIDRequest(didUrl string, resolutionOptions type log.Trace().Msgf("Resolving %s", didUrl) result, err = rs.prepareResolutionResult(didUrl, resolutionOptions) } - - if resolutionOptions.Accept == types.HTML { - return "

Cheqd DID Resolver

", err
-	}
 	return result, err
 }
 
@@ -109,15 +102,18 @@ func (rs RequestService) prepareDereferencingResult(did string, dereferencingOpt
 
 // https://w3c-ccg.github.io/did-resolution/#resolving
 func (rs RequestService) Resolve(did string, resolutionOptions types.ResolutionOption) (types.DidResolution, error) {
+	if !resolutionOptions.Accept.IsSupported() {
+		return types.DidResolution{ResolutionMetadata: types.NewResolutionMetadata(did, types.JSON, types.RepresentationNotSupportedError)}, nil
+	}
 	didResolutionMetadata := types.NewResolutionMetadata(did, resolutionOptions.Accept, "")
 
 	if didMethod, _, _, _ := cheqdUtils.TrySplitDID(did); didMethod != rs.didMethod {
-		didResolutionMetadata.ResolutionError = types.ResolutionMethodNotSupported
+		didResolutionMetadata.ResolutionError = types.MethodNotSupportedError
 		return types.DidResolution{ResolutionMetadata: didResolutionMetadata}, nil
 	}
 
 	if !cheqdUtils.IsValidDID(did, "", rs.ledgerService.GetNamespaces()) {
-		didResolutionMetadata.ResolutionError = types.ResolutionInvalidDID
+		didResolutionMetadata.ResolutionError = types.InvalidDIDError
 		return types.DidResolution{ResolutionMetadata: didResolutionMetadata}, nil
 
 	}
@@ -133,16 +129,14 @@ func (rs RequestService) Resolve(did string, resolutionOptions types.ResolutionO
 	}
 
 	if !isFound {
-		didResolutionMetadata.ResolutionError = types.ResolutionNotFound
+		didResolutionMetadata.ResolutionError = types.NotFoundError
 		return types.DidResolution{ResolutionMetadata: didResolutionMetadata}, nil
 	}
 
 	if didResolutionMetadata.ContentType == types.DIDJSONLD || didResolutionMetadata.ContentType == types.JSONLD {
 		didDoc.Context = append(didDoc.Context, types.DIDSchemaJSONLD)
-	} else if didResolutionMetadata.ContentType == types.DIDJSON || didResolutionMetadata.ContentType == types.HTML {
-		didDoc.Context = []string{}
 	} else {
-		return types.DidResolution{}, fmt.Errorf("content type %s is not supported", didResolutionMetadata.ContentType)
+		didDoc.Context = []string{}
 	}
 	return types.DidResolution{Did: didDoc, Metadata: resolvedMetadata, ResolutionMetadata: didResolutionMetadata}, nil
 }
@@ -152,14 +146,18 @@ func (rs RequestService) Dereference(didUrl string, dereferenceOptions types.Der
 	did, path, query, fragmentId, err := cheqdUtils.TrySplitDIDUrl(didUrl)
 	log.Info().Msgf("did: %s, path: %s, query: %s, fragmentId: %s", did, path, query, fragmentId)
 
+	if !dereferenceOptions.Accept.IsSupported() {
+		return types.DidDereferencing{DereferencingMetadata: types.NewDereferencingMetadata(did, types.JSON, types.RepresentationNotSupportedError)}, nil
+	}
+
 	if err != nil || !cheqdUtils.IsValidDIDUrl(didUrl, "", []string{}) {
-		dereferencingMetadata := types.NewDereferencingMetadata(didUrl, dereferenceOptions.Accept, types.DereferencingInvalidDIDUrl)
+		dereferencingMetadata := types.NewDereferencingMetadata(didUrl, dereferenceOptions.Accept, types.InvalidDIDUrlError)
 		return types.DidDereferencing{DereferencingMetadata: dereferencingMetadata}, nil
 	}
 
 	// TODO: implement
 	if query != "" {
-		dereferencingMetadata := types.NewDereferencingMetadata(didUrl, dereferenceOptions.Accept, types.DereferencingNotSupported)
+		dereferencingMetadata := types.NewDereferencingMetadata(didUrl, dereferenceOptions.Accept, types.RepresentationNotSupportedError)
 		return types.DidDereferencing{DereferencingMetadata: dereferencingMetadata}, nil
 	}
 
@@ -181,7 +179,7 @@ func (rs RequestService) dereferencePrimary(path string, did string, didUrl stri
 	resourceId := utils.GetResourceId(path)
 	// Only `resource` path is supported
 	if resourceId == "" {
-		dereferencingMetadata := types.NewDereferencingMetadata(didUrl, dereferenceOptions.Accept, types.DereferencingNotSupported)
+		dereferencingMetadata := types.NewDereferencingMetadata(didUrl, dereferenceOptions.Accept, types.RepresentationNotSupportedError)
 		return types.DidDereferencing{DereferencingMetadata: dereferencingMetadata}, nil
 	}
 
@@ -190,7 +188,7 @@ func (rs RequestService) dereferencePrimary(path string, did string, didUrl stri
 		return types.DidDereferencing{}, err
 	}
 	if !isFound {
-		dereferencingMetadata := types.NewDereferencingMetadata(didUrl, dereferenceOptions.Accept, types.DereferencingNotFound)
+		dereferencingMetadata := types.NewDereferencingMetadata(didUrl, dereferenceOptions.Accept, types.NotFoundError)
 		return types.DidDereferencing{DereferencingMetadata: dereferencingMetadata}, nil
 	}
 	jsonFragment, err := rs.didDocService.MarshallContentStream(&resource, dereferenceOptions.Accept)
@@ -223,7 +221,7 @@ func (rs RequestService) dereferenceSecondary(did string, fragmentId string, did
 	}
 
 	if protoContent == nil {
-		dereferencingMetadata := types.NewDereferencingMetadata(didUrl, dereferenceOptions.Accept, types.DereferencingNotFound)
+		dereferencingMetadata := types.NewDereferencingMetadata(didUrl, dereferenceOptions.Accept, types.NotFoundError)
 		return types.DidDereferencing{DereferencingMetadata: dereferencingMetadata}, nil
 	}
 
diff --git a/services/request_service_test.go b/services/request_service_test.go
index c1dead4b..82a73ad9 100644
--- a/services/request_service_test.go
+++ b/services/request_service_test.go
@@ -119,15 +119,16 @@ func TestResolve(t *testing.T) {
 	validMetadata := validMetadata()
 	validResource := validResource()
 	subtests := []struct {
-		name             string
-		ledgerService    MockLedgerService
-		resolutionType   types.ContentType
-		identifier       string
-		method           string
-		namespace        string
-		expectedDID      cheqd.Did
-		expectedMetadata types.ResolutionDidDocMetadata
-		expectedError    types.ErrorType
+		name                   string
+		ledgerService          MockLedgerService
+		resolutionType         types.ContentType
+		identifier             string
+		method                 string
+		namespace              string
+		expectedDID            cheqd.Did
+		expectedMetadata       types.ResolutionDidDocMetadata
+		expectedResolutionType types.ContentType
+		expectedError          types.ErrorType
 	}{
 		{
 			name:             "successful resolution",
@@ -149,7 +150,7 @@ func TestResolve(t *testing.T) {
 			namespace:        validNamespace,
 			expectedDID:      cheqd.Did{},
 			expectedMetadata: types.ResolutionDidDocMetadata{},
-			expectedError:    types.ResolutionNotFound,
+			expectedError:    types.NotFoundError,
 		},
 		{
 			name:             "invalid DID",
@@ -160,7 +161,7 @@ func TestResolve(t *testing.T) {
 			namespace:        validNamespace,
 			expectedDID:      cheqd.Did{},
 			expectedMetadata: types.ResolutionDidDocMetadata{},
-			expectedError:    types.ResolutionInvalidDID,
+			expectedError:    types.InvalidDIDError,
 		},
 		{
 			name:             "invalid method",
@@ -171,7 +172,7 @@ func TestResolve(t *testing.T) {
 			namespace:        validNamespace,
 			expectedDID:      cheqd.Did{},
 			expectedMetadata: types.ResolutionDidDocMetadata{},
-			expectedError:    types.ResolutionMethodNotSupported,
+			expectedError:    types.MethodNotSupportedError,
 		},
 		{
 			name:             "invalid namespace",
@@ -182,7 +183,19 @@ func TestResolve(t *testing.T) {
 			namespace:        "invalid_namespace",
 			expectedDID:      cheqd.Did{},
 			expectedMetadata: types.ResolutionDidDocMetadata{},
-			expectedError:    types.ResolutionInvalidDID,
+			expectedError:    types.InvalidDIDError,
+		},
+		{
+			name:                   "representation is not supported",
+			ledgerService:          NewMockLedgerService(validDIDDoc, validMetadata, validResource),
+			resolutionType:         "text/html,application/xhtml+xml",
+			identifier:             validIdentifier,
+			method:                 validMethod,
+			namespace:              validNamespace,
+			expectedDID:            cheqd.Did{},
+			expectedMetadata:       types.ResolutionDidDocMetadata{},
+			expectedResolutionType: types.JSON,
+			expectedError:          types.RepresentationNotSupportedError,
 		},
 	}
 
@@ -200,7 +213,10 @@ func TestResolve(t *testing.T) {
 			} else {
 				subtest.expectedDID.Context = nil
 			}
-
+			expectedContentType := subtest.expectedResolutionType
+			if expectedContentType == "" {
+				expectedContentType = subtest.resolutionType
+			}
 			resolutionResult, err := requestService.Resolve(id, types.ResolutionOption{Accept: subtest.resolutionType})
 
 			fmt.Println(subtest.name + ": resolutionResult:")
@@ -208,7 +224,7 @@ func TestResolve(t *testing.T) {
 			fmt.Println(subtest.expectedDID.VerificationMethod)
 			require.EqualValues(t, subtest.expectedDID, resolutionResult.Did)
 			require.EqualValues(t, subtest.expectedMetadata, resolutionResult.Metadata)
-			require.EqualValues(t, subtest.resolutionType, resolutionResult.ResolutionMetadata.ContentType)
+			require.EqualValues(t, expectedContentType, resolutionResult.ResolutionMetadata.ContentType)
 			require.EqualValues(t, subtest.expectedError, resolutionResult.ResolutionMetadata.ResolutionError)
 			require.EqualValues(t, expectedDIDProperties, resolutionResult.ResolutionMetadata.DidProperties)
 			require.Empty(t, err)
@@ -280,7 +296,7 @@ func TestDereferencing(t *testing.T) {
 			didUrl:            "unvalid_url",
 			dereferencingType: types.DIDJSONLD,
 			expectedMetadata:  types.ResolutionDidDocMetadata{},
-			expectedError:     types.DereferencingInvalidDIDUrl,
+			expectedError:     types.InvalidDIDUrlError,
 		},
 		{
 			name:              "not supported path",
@@ -288,7 +304,7 @@ func TestDereferencing(t *testing.T) {
 			dereferencingType: types.DIDJSONLD,
 			didUrl:            validDid + "/unknown_path",
 			expectedMetadata:  types.ResolutionDidDocMetadata{},
-			expectedError:     types.DereferencingNotSupported,
+			expectedError:     types.RepresentationNotSupportedError,
 		},
 		{
 			name:              "not supported query",
@@ -296,7 +312,7 @@ func TestDereferencing(t *testing.T) {
 			dereferencingType: types.DIDJSONLD,
 			didUrl:            validDid + "?unknown_query",
 			expectedMetadata:  types.ResolutionDidDocMetadata{},
-			expectedError:     types.DereferencingNotSupported,
+			expectedError:     types.RepresentationNotSupportedError,
 		},
 		{
 			name:              "key not found",
@@ -304,7 +320,7 @@ func TestDereferencing(t *testing.T) {
 			dereferencingType: types.DIDJSONLD,
 			didUrl:            validDid + "#notFoundKey",
 			expectedMetadata:  types.ResolutionDidDocMetadata{},
-			expectedError:     types.DereferencingNotFound,
+			expectedError:     types.NotFoundError,
 		},
 		{
 			name:              "resource not found",
@@ -312,7 +328,7 @@ func TestDereferencing(t *testing.T) {
 			dereferencingType: types.DIDJSONLD,
 			didUrl:            validDid + types.RESOURCE_PATH + "00000000-0000-0000-0000-000000000000",
 			expectedMetadata:  types.ResolutionDidDocMetadata{},
-			expectedError:     types.DereferencingNotFound,
+			expectedError:     types.NotFoundError,
 		},
 	}
 
@@ -320,7 +336,7 @@ func TestDereferencing(t *testing.T) {
 		t.Run(subtest.name, func(t *testing.T) {
 			requestService := NewRequestService("cheqd", subtest.ledgerService)
 			var expectedDIDProperties types.DidProperties
-			if subtest.expectedError != types.DereferencingInvalidDIDUrl {
+			if subtest.expectedError != types.InvalidDIDUrlError {
 				expectedDIDProperties = types.DidProperties{
 					DidString:        validDid,
 					MethodSpecificId: validIdentifier,
diff --git a/tests/pytest/helpers.py b/tests/pytest/helpers.py
index 8feda6f0..244dc455 100644
--- a/tests/pytest/helpers.py
+++ b/tests/pytest/helpers.py
@@ -23,6 +23,7 @@
 DIDJSON = "application/did+json"
 DIDLDJSON = "application/did+ld+json"
 LDJSON = "application/ld+json"
+JSON = "application/json"
 HTML = "text/html"
 
 IMPLICIT_TIMEOUT = 40
diff --git a/tests/pytest/test_resolution.py b/tests/pytest/test_resolution.py
index 34b329c2..8973c697 100644
--- a/tests/pytest/test_resolution.py
+++ b/tests/pytest/test_resolution.py
@@ -5,13 +5,14 @@
 
 from helpers import run, TESTNET_DID, MAINNET_DID, TESTNET_FRAGMENT, MAINNET_FRAGMENT, \
     FAKE_TESTNET_DID, FAKE_MAINNET_DID, FAKE_TESTNET_FRAGMENT, FAKE_MAINNET_FRAGMENT, RESOLVER_URL, PATH, \
-    LDJSON, DIDJSON, DIDLDJSON, HTML, FAKE_TESTNET_RESOURCE, TESTNET_RESOURCE, TESTNET_RESOURCE_NAME
+    LDJSON, DIDJSON, DIDLDJSON, HTML, FAKE_TESTNET_RESOURCE, TESTNET_RESOURCE, TESTNET_RESOURCE_NAME, JSON
 
 
 @pytest.mark.parametrize(
     "did_url, expected_output",
     [
-        (TESTNET_DID, fr"didResolutionMetadata(.*?)didDocument(.*?)\"id\":\"{TESTNET_DID}\"(.*?)didDocumentMetadata(.*?){TESTNET_RESOURCE_NAME}"),
+        (TESTNET_DID,
+         fr"didResolutionMetadata(.*?)didDocument(.*?)\"id\":\"{TESTNET_DID}\"(.*?)didDocumentMetadata(.*?){TESTNET_RESOURCE_NAME}"),
         (MAINNET_DID, fr"didResolutionMetadata(.*?)didDocument(.*?)\"id\":\"{MAINNET_DID}\"(.*?)didDocumentMetadata"),
         (FAKE_TESTNET_DID, r"\"didResolutionMetadata(.*?)\"error\":\"notFound\"(.*?)"
                            r"didDocument\":null,\"didDocumentMetadata\":\[\]"),
@@ -46,12 +47,13 @@ def test_resolution(did_url, expected_output):
                                r"(.*?)didDocument(.*?)@context(.*?)didDocumentMetadata"),
         (DIDLDJSON, DIDLDJSON, True, "(.*?)didResolutionMetadata(.*?)application/did\+ld\+json"
                                      "(.*?)didDocument(.*?)@context(.*?)didDocumentMetadata"),
-        ("", DIDLDJSON, True, "(.*?)didResolutionMetadata(.*?)application/did\+ld\+json"
-                              "(.*?)didDocument(.*?)@context(.*?)didDocumentMetadata"),
+        ("*/*", DIDLDJSON, True, "(.*?)didResolutionMetadata(.*?)application/did\+ld\+json"
+                                 "(.*?)didDocument(.*?)@context(.*?)didDocumentMetadata"),
         (DIDJSON, DIDJSON, False, r"(.*?)didResolutionMetadata(.*?)application/did\+json"
                                   r"(.*?)didDocument(.*?)(?!`@context`)(.*?)didDocumentMetadata"),
-        (HTML + ",application/xhtml+xml", HTML, False, fr"(.*?)didResolutionMetadata(.*?){HTML}"
-                                                       fr"(.*?)didDocument(.*?)(?!`@context`)(.*?)didDocumentMetadata"),
+        (HTML + ",application/xhtml+xml", JSON, False,
+         "(.*?)didResolutionMetadata(.*?)\"error\":\"representationNotSupported\""
+         "(.*?)\"didDocument\":null,\"didDocumentMetadata\":\[\]"),
     ]
 )
 def test_resolution_content_type(accept, expected_header, expected_body, has_context):
@@ -75,15 +77,15 @@ def test_resolution_content_type(accept, expected_header, expected_body, has_con
     (DIDLDJSON, DIDLDJSON, True,
      "(.*?)contentStream(.*?)@context(.*?)contentMetadata"
      "(.*?)dereferencingMetadata(.*?)application/did\+ld\+json"),
-    ("", DIDLDJSON, True,
+    ("*/*", DIDLDJSON, True,
      "(.*?)contentStream(.*?)@context(.*?)contentMetadata"
      "(.*?)dereferencingMetadata(.*?)application/did\+ld\+json"),
     (DIDJSON, DIDJSON, False,
      r"(.*?)contentStream(.*?)contentMetadata"
      r"(.*?)dereferencingMetadata(.*?)application/did\+json"),
-    (HTML + ",application/xhtml+xml", HTML, False,
-     fr"(.*?)contentStream(.*?)contentMetadata"
-     fr"(.*?)dereferencingMetadata(.*?){HTML}"),
+    (HTML + ",application/xhtml+xml", JSON, False,
+     "(.*?)\"contentStream\":null,\"contentMetadata\":\[\],"
+     "\"dereferencingMetadata(.*?)\"error\":\"representationNotSupported\""),
 ]
 
 
diff --git a/types/constants.go b/types/constants.go
index db344280..09de6502 100644
--- a/types/constants.go
+++ b/types/constants.go
@@ -3,16 +3,32 @@ package types
 type ErrorType string
 
 const (
-	ResolutionInvalidDID         ErrorType = "invalidDid"
-	ResolutionNotFound           ErrorType = "notFound"
-	ResolutionMethodNotSupported ErrorType = "methodNotSupported"
+	InvalidDIDError                 ErrorType = "invalidDid"
+	InvalidDIDUrlError              ErrorType = "invalidDidUrl"
+	NotFoundError                   ErrorType = "notFound"
+	RepresentationNotSupportedError ErrorType = "representationNotSupported"
+	MethodNotSupportedError         ErrorType = "methodNotSupported"
+	InternalError                   ErrorType = "internalError"
 )
 
-const (
-	DereferencingInvalidDIDUrl ErrorType = "invalidDidUrl"
-	DereferencingNotFound      ErrorType = "notFound"
-	DereferencingNotSupported  ErrorType = "urlNotSupported"
-)
+func (e ErrorType) GetStatusCode() int {
+	switch e {
+	case InvalidDIDError:
+		return 400
+	case InvalidDIDUrlError:
+		return 400
+	case NotFoundError:
+		return 404
+	case RepresentationNotSupportedError:
+		return 406
+	case MethodNotSupportedError:
+		return 406
+	case "":
+		return 200
+	default:
+		return 500
+	}
+}
 
 type ContentType string
 
@@ -20,9 +36,18 @@ const (
 	DIDJSON   ContentType = "application/did+json"
 	DIDJSONLD ContentType = "application/did+ld+json"
 	JSONLD    ContentType = "application/ld+json"
-	HTML      ContentType = "text/html"
+	JSON      ContentType = "application/json"
 )
 
+func (cType ContentType) IsSupported() bool {
+	supportedTypes := map[ContentType]bool{
+		DIDJSON:   true,
+		DIDJSONLD: true,
+		JSONLD:    true,
+	}
+	return supportedTypes[cType]
+}
+
 const (
 	DIDSchemaJSONLD = "https://www.w3.org/ns/did/v1"
 )