Skip to content

Commit

Permalink
feat: implement vc-api for holder
Browse files Browse the repository at this point in the history
Signed-off-by: Nam Hoang <hoangxuannam160493@gmail.com>
  • Loading branch information
namhoang1604 committed Jun 22, 2023
1 parent 100b35d commit 8615407
Show file tree
Hide file tree
Showing 5 changed files with 277 additions and 1 deletion.
199 changes: 199 additions & 0 deletions packages/vc-api/src/controllers/holder-controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
import {
IAgent,
UniqueVerifiableCredential,
UniqueVerifiablePresentation,
VerifiableCredential,
} from '@vckit/core-types';
import { Response } from 'express';
import { errorHandler } from '../error-handler.js';
import { RequestWithAgent } from '../types/request-type.js';

/**
* Retrieves a specific verifiable credential based on its ID.
* @public
* @param {RequestWithAgent} req - The request object.
* @param {Response} res - The response object.
* @throws {Error} If the agent is not available.
*/
export const getCredential = async (req: RequestWithAgent, res: Response) => {
if (!req.agent) throw Error('Agent not available');
try {
const result = await getUniqueVerifiableCredential(
req.agent,
req.params.id
);
if (!result) {
res.status(404).json({ error: 'Credential not found' });
} else {
res.status(200).json(result.verifiableCredential);
}
} catch (e) {
const error = errorHandler(e);
res.status(error.code).json({ error: error.message });
}
};

/**
* Retrieves all verifiable credentials.
* @public
* @param {RequestWithAgent} req - The request object.
* @param {Response} res - The response object.
* @throws {Error} If the agent is not available.
*/
export const getCredentials = async (req: RequestWithAgent, res: Response) => {
if (!req.agent) throw Error('Agent not available');
try {
const result: Array<VerifiableCredential> = await getVerifiableCredentials(
req.agent
);
if (result.length === 0) {
res.status(410).json({ error: 'Gone! There is no data here' });
} else {
res.status(200).json(result);
}
} catch (e) {
const error = errorHandler(e);
res.status(error.code).json({ error: error.message });
}
};

/**
* Deletes a specific verifiable credential based on its ID.
* @public
* @param {RequestWithAgent} req - The request object.
* @param {Response} res - The response object.
* @throws {Error} If the agent is not available.
*/
export const deleteCredential = async (
req: RequestWithAgent,
res: Response
) => {
if (!req.agent) throw Error('Agent not available');
try {
const result = await deleteVerifiableCredential(req.agent, req.params.id);
if (!result) {
res.status(404).json({ error: 'Credential not found' });
} else {
res.status(202).json({ message: 'Credential deleted' });
}
} catch (e) {
const error = errorHandler(e);
res.status(error.code).json({ error: error.message });
}
};

/**
* Retrieves a specific verifiable presentation based on its ID.
* @public
* @param {RequestWithAgent} req - The request object.
* @param {Response} res - The response object.
* @throws {Error} If the agent is not available.
*/
export const getPresentation = async (req: RequestWithAgent, res: Response) => {
if (!req.agent) throw Error('Agent not available');
try {
const result = await getUniqueVerifiablePresentation(
req.agent,
req.params.id
);
if (!result) {
res.status(404).json({ error: 'Presentation not found' });
} else {
res.status(200).json(result.verifiablePresentation);
}
} catch (e) {
const error = errorHandler(e);
res.status(error.code).json({ error: error.message });
}
};

/**
* Retrieves all verifiable presentations.
* @public
* @param {RequestWithAgent} req - The request object.
* @param {Response} res - The response object.
* @throws {Error} If the agent is not available.
*/
export const getPresentations = async (
req: RequestWithAgent,
res: Response
) => {
if (!req.agent) throw Error('Agent not available');
try {
const result = await getVerifiablePresentations(req.agent);
if (result.length === 0) {
res.status(410).json({ error: 'Gone! There is no data here' });
} else {
res.status(200).json(result);
}
} catch (e) {
const error = errorHandler(e);
res.status(error.code).json({ error: error.message });
}
};

const getUniqueVerifiableCredential = async (
agent: IAgent,
id: string
): Promise<UniqueVerifiableCredential | null> => {
const params = {
where: [{ column: 'id', value: [id], not: false, op: 'Equal' }],
};
const result: Array<UniqueVerifiableCredential> = await agent.execute(
'dataStoreORMGetVerifiableCredentials',
params
);
return result[0] ? result[0] : null;
};

const deleteVerifiableCredential = async (
agent: IAgent,
id: string
): Promise<boolean> => {
const credential = await getUniqueVerifiableCredential(agent, id);
if (!credential) throw Error('not_found: Credential not found');

const params = {
hash: credential.hash,
};
return agent.execute('dataStoreDeleteVerifiableCredential', params);
};

const getVerifiableCredentials = async (
agent: IAgent
): Promise<VerifiableCredential[]> => {
const params = {};
const result = await agent.execute(
'dataStoreORMGetVerifiableCredentials',
params
);
return result.map(
(credential: UniqueVerifiableCredential) => credential.verifiableCredential
);
};

const getUniqueVerifiablePresentation = async (
agent: IAgent,
id: string
): Promise<UniqueVerifiablePresentation | null> => {
const params = {
where: [{ column: 'id', value: [id], not: false, op: 'Equal' }],
};
const result: Array<UniqueVerifiablePresentation> = await agent.execute(
'dataStoreORMGetVerifiablePresentations',
params
);
return result[0] ? result[0] : null;
};

const getVerifiablePresentations = async (agent: IAgent) => {
const params = {};
const result = await agent.execute(
'dataStoreORMGetVerifiablePresentations',
params
);
return result.map(
(presentation: UniqueVerifiablePresentation) =>
presentation.verifiablePresentation
);
};
36 changes: 36 additions & 0 deletions packages/vc-api/src/error-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Defines the structure of a VC API error.
*/
interface VCApiError {
code: number;
message: string;
data?: any;
}

/**
* Handles and transforms an error into a VCApiError object.
* @param {Error} error - The error to be handled.
* @returns {VCApiError} The transformed VCApiError object.
*/
export const errorHandler = (error: Error): VCApiError => {
let vcApiError: VCApiError;
const errorType = error.message.split(':')[0];
const errorMessage = error.message.split(':')[1];
switch (errorType) {
case 'not_found':
return (vcApiError = {
code: 404,
message: errorMessage,
});
case 'not_implemented':
return (vcApiError = {
code: 501,
message: errorMessage,
});
default:
return (vcApiError = {
code: 500,
message: error.message,
});
}
};
31 changes: 31 additions & 0 deletions packages/vc-api/src/holder-router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Router, json } from 'express';
import {
deleteCredential,
getCredential,
getCredentials,
getPresentation,
getPresentations,
} from './controllers/holder-controller.js';

/**
*
* Creates a router for handling holder-related routes.
* @public
* @returns {Router} The Express router configured for holder routes.
*/
export const HolderRouter = (): Router => {
const router = Router();
router.use(json({ limit: '10mb' }));

router.get('/credentials/:id', getCredential);

router.get('/credentials', getCredentials);

router.delete('/credentials/:id', deleteCredential);

router.get('/presentations/:id', getPresentation);

router.get('/presentations', getPresentations);

return router;
};
3 changes: 2 additions & 1 deletion packages/vc-api/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { IssuerRouter, IssuerRouterOptions } from './issuer-router.js'
export { IssuerRouter, IssuerRouterOptions } from './issuer-router.js';
export { HolderRouter } from './holder-router.js';
9 changes: 9 additions & 0 deletions packages/vc-api/src/types/request-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { IAgent } from '@vckit/core-types';
import { Request } from 'express';

/**
* @public
*/
export interface RequestWithAgent extends Request {
agent?: IAgent;
}

0 comments on commit 8615407

Please sign in to comment.