From dd4735284bf09b8d390ef7d67c970b72da56301e Mon Sep 17 00:00:00 2001 From: DaevMithran Date: Wed, 19 Oct 2022 12:57:48 +0530 Subject: [PATCH] fix: Error handling && swagger schemas --- src/controllers/did.ts | 73 ++++++++++-------- src/service/cheqd.ts | 2 +- swagger.json | 163 +++++++++++++++++++++++++++++++---------- 3 files changed, 169 insertions(+), 69 deletions(-) diff --git a/src/controllers/did.ts b/src/controllers/did.ts index 6c8df64..3ec76ad 100644 --- a/src/controllers/did.ts +++ b/src/controllers/did.ts @@ -20,7 +20,8 @@ export class DidController { public static updateValidator = [ check('didDocument').isArray().withMessage('didDocument is required'), check('secret').isObject().custom((value) => value.keys).withMessage('secret with keys is required'), - check('did').isString().contains('did:cheqd:').withMessage('cheqd DID is required') + check('did').isString().contains('did:cheqd:').withMessage('cheqd DID is required'), + check('didDocumentOperation').optional().isArray().custom((value) => value.includes(DidDocumentOperation.Set) ? value.length==1 : value.length<=2 ).withMessage('Set operation can\'t be used with Add/Remove') ] public async create(request: Request, response: Response) { @@ -39,17 +40,24 @@ export class DidController { await CheqdRegistrar.instance.connect(options?.network) let { didPayload, keys, signInputs } = createDidPayloadWithSignInputs(secret.seed, secret.keys) if (didDocument) didPayload = jsonConcat(didPayload, didDocument) - await CheqdRegistrar.instance.create(signInputs, didPayload) - return response.status(201).json({ - jobId: null, - didState: { - did: didPayload.id, - state: "finished", - secret: { keys }, - didDocument: didPayload - } - }) + try { + await CheqdRegistrar.instance.create(signInputs, didPayload) + return response.status(201).json({ + jobId: null, + didState: { + did: didPayload.id, + state: "finished", + secret: { keys }, + didDocument: didPayload + } + }) + } catch (error) { + return response.status(500).json({ + message: `Internal server error: ${error}` + }) + } + } public async update(request: Request, response: Response) { @@ -61,7 +69,7 @@ export class DidController { }) } - const { secret, options, didDocument, didDocumentOperation, did } = request.body as IDIDUpdateRequest + const { secret, options, didDocument, didDocumentOperation=[DidDocumentOperation.Set], did } = request.body as IDIDUpdateRequest await CheqdRegistrar.instance.connect(options?.network) // check if did is registered on the ledger let resolvedDocument = await CheqdResolver(did) @@ -70,35 +78,42 @@ export class DidController { message: `${did} DID not found` }) } + console.log(didDocumentOperation) var i=0 + let updatedDocument = resolvedDocument.didDocument for (var operation of didDocumentOperation) { switch (operation) { case DidDocumentOperation.Set: - didDocument[i].versionId = resolvedDocument.didDocumentMetadata.versionId - resolvedDocument = didDocument + // TODO: validate didDocument schema + updatedDocument = didDocument[i] break case DidDocumentOperation.Add: - resolvedDocument = jsonConcat(resolvedDocument.didDocument, didDocument) + updatedDocument = jsonConcat(updatedDocument, didDocument[i]) break case DidDocumentOperation.Remove: - resolvedDocument = jsonSubtract(resolvedDocument.didDocument, didDocument) + updatedDocument = jsonSubtract(updatedDocument, didDocument[i]) break } i++ } + updatedDocument.versionId = resolvedDocument.didDocumentMetadata.versionId - const {didDocument: didPayload, signInputs} = await createUpdateDidPayloadWithSignInputs(resolvedDocument, secret.keys) - - await CheqdRegistrar.instance.update(signInputs, didPayload) - - return response.status(201).json({ - jobId: null, - didState: { - did: didPayload.id, - state: "finished", - secret, - didDocument: didPayload - } - }) + try { + const {didDocument: didPayload, signInputs} = await createUpdateDidPayloadWithSignInputs(updatedDocument, secret.keys) + await CheqdRegistrar.instance.update(signInputs, didPayload) + return response.status(201).json({ + jobId: null, + didState: { + did: didPayload.id, + state: "finished", + secret, + didDocument: didPayload + } + }) + } catch (error) { + return response.status(500).json({ + message: `Internal server error: ${error}` + }) + } } } \ No newline at end of file diff --git a/src/service/cheqd.ts b/src/service/cheqd.ts index 0e31915..2c1c356 100644 --- a/src/service/cheqd.ts +++ b/src/service/cheqd.ts @@ -82,7 +82,7 @@ export class CheqdRegistrar { } export async function CheqdResolver(id: string) { - const result = await fetch(`${DefaultResolverUrl.Cheqd}/${id}`) + const result = await fetch(`${DefaultResolverUrl.Cheqd}/1.0/identifiers/${id}`) if (!result.ok) { return null } diff --git a/swagger.json b/swagger.json index 52e75d0..63fa14b 100644 --- a/swagger.json +++ b/swagger.json @@ -10,9 +10,20 @@ "version": "1.0.0", "title": "Cheqd Did Registrar" }, + "tags": [ + { + "name": "DID", + "externalDocs": { + "url": "https://github.com/cheqd/did-registrar#readme" + } + } + ], "paths": { "/create": { "post": { + "tags": [ + "DID" + ], "summary": "Create a DID.", "description": "

This endpoint creates a DID. As input it takes the DID plus options, a DID document, and optionally secrets needed to create a DID. The output is a state object that represents the current state of the DID creation process.

See the DID Registration specification for additional details.

", "operationId": "create", @@ -63,6 +74,9 @@ }, "/update": { "post": { + "tags": [ + "DID" + ], "summary": "Update a DID.", "description": "

This endpoint updates a DID. As input it takes the existing DID plus options, a DID document, and optionally secrets needed to update a DID. The output is a state object that represents the current state of the DID update process.

See the DID Registration specification for additional details.

", "operationId": "update", @@ -103,6 +117,9 @@ }, "/deactivate": { "post": { + "tags": [ + "DID" + ], "summary": "Deactivate a DID.", "description": "

This endpoint deactivates a DID. As input it takes the existing DID plus options, and optionally secrets needed to deactivate a DID. The output is a state object that represents the current state of the DID deactivation process.

See the DID Registration specification for additional details.

", "operationId": "deactivate", @@ -158,10 +175,33 @@ "$ref": "#/components/schemas/Options" }, "secret": { - "$ref": "#/components/schemas/Secret" + "description": "This input field accepts a seed or an array of keyPairs.", + "type": "object", + "properties": { + "seed": { + "type": "string" + }, + "keys": { + "type": "array", + "items": { + "$ref": "#/components/schemas/KeyPair" + } + } + }, + "example": { + "seed": "72WGp7NgFR1Oqdi8zlt7jQQ434XR0cNQ" + } }, "didDocument": { - "$ref": "#/components/schemas/DidDocument" + "type": "object", + "properties": { + "service": { + "$ref": "#/components/schemas/Service" + } + }, + "example": { + + } } } }, @@ -170,7 +210,9 @@ "type": "object", "additionalProperties": false, "required": [ - "did" + "did", + "secret", + "didDocument" ], "properties": { "jobId": { @@ -187,29 +229,48 @@ "$ref": "#/components/schemas/Options" }, "secret": { - "$ref": "#/components/schemas/Secret" + "description": "This input field requires a keyPair.", + "type": "object", + "required": [ + "keys" + ], + "properties": { + "keys": { + "type": "array", + "items": { + "$ref": "#/components/schemas/KeyPair" + } + } + } }, "didDocumentOperation": { "type": "array", "items": { "type": "string" }, - "example": ["addToDidDocument", "removeFromDidDocument"] + "example": [ + "addToDidDocument" + ], + "default": [ + "setToDidDocument" + ] }, "didDocument": { "type": "array", "items": { "$ref": "#/components/schemas/DidDocument" }, - "example": [{ - "service": [ - { - "id": "did:cheqd:testnet:zApY6E8Prv1rWcjRtBKENGaVm2kRk1VQ#rand", - "type": "rand", - "serviceEndpoint": "https://rand.in" - } - ] - }] + "example": [ + { + "service": [ + { + "id": "did:cheqd:testnet:zApY6E8Prv1rWcjRtBKENGaVm2kRk1VQ#rand", + "type": "rand", + "serviceEndpoint": "https://rand.in" + } + ] + } + ] } } }, @@ -218,7 +279,8 @@ "type": "object", "additionalProperties": false, "required": [ - "did" + "did", + "secret" ], "properties": { "jobId": { @@ -235,7 +297,19 @@ "$ref": "#/components/schemas/Options" }, "secret": { - "$ref": "#/components/schemas/Secret" + "description": "This input field requires a keyPair.", + "type": "object", + "required": [ + "keys" + ], + "properties": { + "keys": { + "type": "array", + "items": { + "$ref": "#/components/schemas/KeyPair" + } + } + } } } }, @@ -418,61 +492,55 @@ "controller": { "type": "array", "items": { - "type": "string" + "type": "string" }, - "example": - [ - "did:cheqd:testnet:zApY6E8Prv1rWcjRtBKENGaVm2kRk1VQ" + "example": [ + "did:cheqd:testnet:zApY6E8Prv1rWcjRtBKENGaVm2kRk1VQ" ] }, "authentication": { "type": "array", "items": { - "type": "string" + "type": "string" }, "example": [ - "did:cheqd:testnet:zApY6E8Prv1rWcjRtBKENGaVm2kRk1VQ#key-0" - ]}, + "did:cheqd:testnet:zApY6E8Prv1rWcjRtBKENGaVm2kRk1VQ#key-0" + ] + }, "assertionMethod": { "type": "array", "items": { - "type": "string" + "type": "string" } }, "capabilityInvocation": { "type": "array", "items": { - "type": "string" + "type": "string" } }, "capabilityDelegation": { "type": "array", "items": { - "type": "string" + "type": "string" } }, "keyAgreement": { "type": "array", "items": { - "type": "string" + "type": "string" } }, - "alsoKnownAs": { + "verificationMethod": { "type": "array", "items": { - "type": "string" + "$ref": "#/components/schemas/VerificationMethod" } }, - "verificationMethod": { - "type": "array", - "items": { - "type": "string" - }} - , "service": { "type": "array", "items": { - "type": "object" + "$ref": "#/components/schemas/Service" } } } @@ -486,15 +554,15 @@ }, "type": { "type": "string", - "example":"Ed25519VerificationKey2020" + "example": "Ed25519VerificationKey2020" }, "controller": { "type": "string", - "example":"did:cheqd:testnet:zApY6E8Prv1rWcjRtBKENGaVm2kRk1VQ" + "example": "did:cheqd:testnet:zApY6E8Prv1rWcjRtBKENGaVm2kRk1VQ" }, "publicKeyMultibase": { "type": "string", - "example":"zApY6E8Prv1rWcjRtBKENGaVm2kRk1VQsFzQoQNbAoVdp" + "example": "zApY6E8Prv1rWcjRtBKENGaVm2kRk1VQsFzQoQNbAoVdp" }, "publicKeyJwk": { "type": "array", @@ -503,6 +571,23 @@ } } } + }, + "Service": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "did:cheqd:testnet:zH7YZn7RcjdaTLBtEkvU9B5rVtrP6cMo#rand," + }, + "type": { + "type": "string", + "example": "rand," + }, + "serviceEndpoint": { + "type": "string", + "example": "https://rand.in" + } + } } } }