-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Accept contentType params for DID URL Resolution [DEV-4722] #325
base: develop
Are you sure you want to change the base?
Changes from all commits
cfe32ba
6284383
548d6da
c3660bb
1a2176d
69bc0f2
252c4fc
5baced8
71e3c57
2eb9dab
0f83b53
4b94645
8e35502
2c9f08f
d8e2036
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ package services | |
|
||
import ( | ||
"net/url" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/cheqd/did-resolver/types" | ||
|
@@ -39,3 +40,48 @@ func PrepareQueries(c echo.Context) (rawQuery string, flag *string) { | |
func GetDidParam(c echo.Context) (string, error) { | ||
return url.QueryUnescape(c.Param("did")) | ||
} | ||
|
||
func GetHighestPriorityHeaderAndParams(acceptHeader string) (string, map[string]string) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Error handlingThis should work...as long as the
...the value
And then your current code works. Where should this be calledCurrently, seems to be called specifically when processing queries for DLRs. Should this not be done across the board for any request? Since this kind of logic theoretically applies not just to resource requests, but to all requests (including those for DID resolution). |
||
bestHeader := "" | ||
bestParams := make(map[string]string) | ||
highestQ := -1.0 | ||
position := 0 | ||
|
||
// Split by ',' to separate multiple headers | ||
headers := strings.Split(acceptHeader, ",") | ||
for index, entry := range headers { | ||
entry = strings.TrimSpace(entry) | ||
parts := strings.Split(entry, ";") | ||
|
||
params := make(map[string]string) | ||
q := 1.0 | ||
|
||
// Parse parameters | ||
for _, param := range parts[1:] { | ||
param = strings.TrimSpace(param) | ||
keyValue := strings.SplitN(param, "=", 2) | ||
if len(keyValue) == 2 { | ||
key, value := keyValue[0], strings.Trim(keyValue[1], "\"") | ||
params[key] = value | ||
} | ||
} | ||
|
||
// Extract q value if present | ||
if qStr, exists := params["q"]; exists { | ||
if parsedQ, err := strconv.ParseFloat(qStr, 64); err == nil { | ||
q = parsedQ | ||
} | ||
} | ||
|
||
// Determine the highest priority header | ||
if q > highestQ || (q == highestQ && position > index) { | ||
highestQ = q | ||
position = index | ||
bestHeader = parts[0] // Only header | ||
delete(params, "q") // Remove q from params | ||
bestParams = params // Update best parameters | ||
} | ||
} | ||
|
||
return bestHeader, bestParams | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package resources | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/cheqd/did-resolver/migrations" | ||
"github.com/cheqd/did-resolver/services" | ||
"github.com/cheqd/did-resolver/types" | ||
"github.com/cheqd/did-resolver/utils" | ||
) | ||
|
||
type ResourceDataWithMetadataDereferencingService struct { | ||
services.BaseRequestService | ||
ResourceId string | ||
} | ||
|
||
func (dr *ResourceDataWithMetadataDereferencingService) Setup(c services.ResolverContext) error { | ||
dr.IsDereferencing = true | ||
return nil | ||
} | ||
|
||
func (dr *ResourceDataWithMetadataDereferencingService) SpecificPrepare(c services.ResolverContext) error { | ||
dr.ResourceId = c.Param("resource") | ||
return nil | ||
} | ||
|
||
func (dr ResourceDataWithMetadataDereferencingService) Redirect(c services.ResolverContext) error { | ||
migratedDid := migrations.MigrateDID(dr.GetDid()) | ||
|
||
path := types.RESOLVER_PATH + migratedDid + types.RESOURCE_PATH + dr.ResourceId | ||
return c.Redirect(http.StatusMovedPermanently, path) | ||
} | ||
|
||
func (dr *ResourceDataWithMetadataDereferencingService) SpecificValidation(c services.ResolverContext) error { | ||
if !utils.IsValidUUID(dr.ResourceId) { | ||
return types.NewInvalidDidUrlError(dr.ResourceId, dr.RequestedContentType, nil, dr.IsDereferencing) | ||
} | ||
|
||
// We not allow query here | ||
if len(dr.Queries) != 0 { | ||
return types.NewInvalidDidUrlError(dr.GetDid(), dr.RequestedContentType, nil, dr.IsDereferencing) | ||
} | ||
return nil | ||
} | ||
|
||
func (dr *ResourceDataWithMetadataDereferencingService) Query(c services.ResolverContext) error { | ||
result, err := c.ResourceService.DereferenceResourceDataWithMetadata(dr.GetDid(), dr.ResourceId, dr.GetContentType()) | ||
if err != nil { | ||
err.IsDereferencing = dr.IsDereferencing | ||
return err | ||
} | ||
|
||
return dr.SetResponse(result) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,6 @@ import ( | |
|
||
"strings" | ||
|
||
resourceTypes "github.com/cheqd/cheqd-node/api/v2/cheqd/resource/v2" | ||
"github.com/cheqd/did-resolver/types" | ||
) | ||
|
||
|
@@ -36,9 +35,9 @@ func (rds ResourceService) DereferenceResourceMetadata(did string, resourceId st | |
context = types.ResolutionSchemaJSONLD | ||
} | ||
|
||
contentStream := types.NewDereferencedResourceListStruct(did, []*resourceTypes.Metadata{resource.Metadata}) | ||
metadata := types.NewDereferencedResource(did, resource.Metadata) | ||
|
||
return &types.ResourceDereferencing{Context: context, ContentStream: contentStream, DereferencingMetadata: dereferenceMetadata}, nil | ||
return &types.ResourceDereferencing{Context: context, Metadata: metadata, DereferencingMetadata: dereferenceMetadata}, nil | ||
} | ||
|
||
func (rds ResourceService) DereferenceCollectionResources(did string, contentType types.ContentType) (*types.ResourceDereferencing, *types.IdentityError) { | ||
|
@@ -79,3 +78,31 @@ func (rds ResourceService) DereferenceResourceData(did string, resourceId string | |
|
||
return &types.ResourceDereferencing{ContentStream: &result, DereferencingMetadata: dereferenceMetadata}, nil | ||
} | ||
|
||
func (rds ResourceService) DereferenceResourceDataWithMetadata(did string, resourceId string, contentType types.ContentType) (*types.ResourceDereferencing, *types.IdentityError) { | ||
dereferenceMetadata := types.NewDereferencingMetadata(did, contentType, "") | ||
|
||
resource, err := rds.ledgerService.QueryResource(did, strings.ToLower(resourceId)) | ||
if err != nil { | ||
err.ContentType = contentType | ||
return nil, err | ||
} | ||
|
||
var context string | ||
if contentType == types.DIDJSONLD || contentType == types.JSONLD { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bit confused as to why this As in...if it's a resource, will it ever be these two content types? Side note: we seem to be using a lot of different terms: sometimes There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should populdate context if it's jsonLD right. This condition is for that. |
||
context = types.ResolutionSchemaJSONLD | ||
} | ||
|
||
dereferenceMetadata.ContentType = types.ContentType(resource.Metadata.MediaType) | ||
|
||
var result types.ContentStreamI | ||
result = types.NewDereferencedResourceData(resource.Resource.Data) | ||
metadata := types.NewDereferencedResource(did, resource.Metadata) | ||
if dereferenceMetadata.ContentType == types.JSON || dereferenceMetadata.ContentType == types.TEXT { | ||
if res, err := types.NewResourceData(resource.Resource.Data); err == nil { | ||
result = res | ||
} | ||
} | ||
|
||
return &types.ResourceDereferencing{Context: context, ContentStream: result, Metadata: metadata, DereferencingMetadata: dereferenceMetadata}, nil | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unless I'm missing something, I don't see a test case here that would logically return "Accept: application/ld+json;profile="https://w3id.org/did-url-dereferencing" → Returns resource + metadata in a single response", since both of the test cases defined here would just return the resource which is JSON? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. EDIT: Maybe just needs better test descriptions There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would also like to see a test case where the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They are added under data_with_metadata folder |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A separate note about function and variable names here: this is not getting the "header". It's specifically the Accept header. So it could be misleading that a lot of the function and variable names are called "header". I would suggest renaming functions and variables to call them "acceptHeader" or similar. (There's a similar comment I have made about variables called
contentType
below.)