Skip to content

Commit

Permalink
Merge pull request #20 from cheqd/content-types
Browse files Browse the repository at this point in the history
feat: Change supported content types [DEV-1582]
  • Loading branch information
Toktar authored Aug 8, 2022
2 parents 097f9f6 + 4c604cb commit 80ab7ae
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 63 deletions.
15 changes: 10 additions & 5 deletions cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
34 changes: 16 additions & 18 deletions services/request_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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 "<!DOCTYPE html><html><body><h1>Cheqd DID Resolver</h1><pre id=\"r\"></pre><script> var data = " +
result + ";document.getElementById(\"r\").innerHTML = JSON.stringify(data, null, 4);" +
"</script></body></html>", err
}
return result, err
}

Expand Down Expand Up @@ -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

}
Expand All @@ -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
}
Expand All @@ -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
}

Expand All @@ -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
}

Expand All @@ -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)
Expand Down Expand Up @@ -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
}

Expand Down
58 changes: 37 additions & 21 deletions services/request_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand All @@ -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,
},
}

Expand All @@ -200,15 +213,18 @@ 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:")
fmt.Println(resolutionResult.Did.VerificationMethod)
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)
Expand Down Expand Up @@ -280,47 +296,47 @@ func TestDereferencing(t *testing.T) {
didUrl: "unvalid_url",
dereferencingType: types.DIDJSONLD,
expectedMetadata: types.ResolutionDidDocMetadata{},
expectedError: types.DereferencingInvalidDIDUrl,
expectedError: types.InvalidDIDUrlError,
},
{
name: "not supported path",
ledgerService: NewMockLedgerService(cheqd.Did{}, cheqd.Metadata{}, resource.Resource{}),
dereferencingType: types.DIDJSONLD,
didUrl: validDid + "/unknown_path",
expectedMetadata: types.ResolutionDidDocMetadata{},
expectedError: types.DereferencingNotSupported,
expectedError: types.RepresentationNotSupportedError,
},
{
name: "not supported query",
ledgerService: NewMockLedgerService(cheqd.Did{}, cheqd.Metadata{}, resource.Resource{}),
dereferencingType: types.DIDJSONLD,
didUrl: validDid + "?unknown_query",
expectedMetadata: types.ResolutionDidDocMetadata{},
expectedError: types.DereferencingNotSupported,
expectedError: types.RepresentationNotSupportedError,
},
{
name: "key not found",
ledgerService: NewMockLedgerService(cheqd.Did{}, cheqd.Metadata{}, resource.Resource{}),
dereferencingType: types.DIDJSONLD,
didUrl: validDid + "#notFoundKey",
expectedMetadata: types.ResolutionDidDocMetadata{},
expectedError: types.DereferencingNotFound,
expectedError: types.NotFoundError,
},
{
name: "resource not found",
ledgerService: NewMockLedgerService(cheqd.Did{}, cheqd.Metadata{}, resource.Resource{}),
dereferencingType: types.DIDJSONLD,
didUrl: validDid + types.RESOURCE_PATH + "00000000-0000-0000-0000-000000000000",
expectedMetadata: types.ResolutionDidDocMetadata{},
expectedError: types.DereferencingNotFound,
expectedError: types.NotFoundError,
},
}

for _, subtest := range subtests {
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,
Expand Down
1 change: 1 addition & 0 deletions tests/pytest/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
22 changes: 12 additions & 10 deletions tests/pytest/test_resolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -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\":\[\]"),
Expand Down Expand Up @@ -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):
Expand All @@ -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\""),
]


Expand Down
Loading

0 comments on commit 80ab7ae

Please sign in to comment.