Skip to content
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

PLT-7701, PLT-7702, PLT-7703, PLT-8427: Implement remaining 1-1 endpoints #128

Merged
merged 12 commits into from
Dec 14, 2023
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
### @marlowe.io/runtime-rest-client

- PLT-7701: Extend the rest client with procedure `getContractSourceById`. (Implemented in [PR-128](https://github.com/input-output-hk/marlowe-ts-sdk/pull/128))
- PLT-7702: Extend the rest client with procedure `getContractSourceAdjacency`. (Implemented in [PR-128](https://github.com/input-output-hk/marlowe-ts-sdk/pull/128))
- PLT-7703: Extend the rest client with procedure `getContractSourceClosure`. (Implemented in [PR-128](https://github.com/input-output-hk/marlowe-ts-sdk/pull/128))
- PLT-8427: Extend the rest client with procedure `getNextStepsForContract`. (Implemented in [PR-128](https://github.com/input-output-hk/marlowe-ts-sdk/pull/128))
2 changes: 1 addition & 1 deletion examples/js/poc-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function logJSON(message, json) {
export function getRuntimeUrl() {
const runtimeUrlInput = document.getElementById("runtimeUrl");
return (
runtimeUrlInput.value ||
(runtimeUrlInput && runtimeUrlInput.value) ||
"https://marlowe-runtime-preprod-web.demo.scdev.aws.iohkdev.io/"
);
}
Expand Down
37 changes: 37 additions & 0 deletions examples/rest-client-flow/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,43 @@ <h2>Request</h2>
>/contracts/:contractId/transactions/:transactionId</a
>
<br />
<input
id="getContractSourceById"
type="button"
value="Get contract source by contract Source id"
class="endpoint"
/>
GETs contract source by contract Source ID
<a
href="https://input-output-hk.github.io/marlowe-ts-sdk/interfaces/_marlowe_io_runtime_rest_client.index.RestClient.html#getContractSourceById"
>/contracts/sources/:contractSourceId</a
>
<br />
<input
id="getContractSourceAdjacency"
type="button"
value="Get adjacent contract Source IDs"
class="endpoint"
/>
GETs the contract Source IDs which are adjacent to a contract
<a
href="https://input-output-hk.github.io/marlowe-ts-sdk/interfaces/_marlowe_io_runtime_rest_client.index.RestClient.html#getContractSourceAdjacency"
>/contracts/sources/:contractSourceId/adjacency</a
>
<br />
<input
id="getContractSourceClosure"
type="button"
value="Get contract Source IDs in contract"
class="endpoint"
/>
GETs the contract Source IDs which appear in the full hierarchy of a
contract source
<a
href="https://input-output-hk.github.io/marlowe-ts-sdk/interfaces/_marlowe_io_runtime_rest_client.index.RestClient.html#getContractSourceClosure"
>/contracts/sources/:contractSourceId/closure</a
>
<br />
</div>

<h2>Console</h2>
Expand Down
7 changes: 6 additions & 1 deletion packages/marlowe-object/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
export { Action, Deposit, Notify, Choice } from "./actions.js";
export { ChoiceName, ChoiceId, Bound, ChosenNum } from "./choices.js";
export { Reference, Label } from "./reference.js";
export {
Reference,
Label,
ContractSourceId,
ContractSourceIdGuard,
} from "./reference.js";
export { Address, Role, Party } from "./participants.js";
export { Payee, PayeeAccount, PayeeParty, AccountId } from "./payee.js";

Expand Down
12 changes: 11 additions & 1 deletion packages/marlowe-object/src/reference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ export type Label = string;

export const LabelGuard: t.Type<Label> = t.string;

/**
* A label for one of the {@link ObjectType}
* @category Object
*/
Comment on lines +11 to +14
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment block for ContractSourceId appears to be a duplicate of the one for Label. It should be updated to accurately describe ContractSourceId.

 /**
- * A label for one of the {@link ObjectType}
+ * An identifier for a contract source within the system
  * @category Object
  */

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
/**
* A label for one of the {@link ObjectType}
* @category Object
*/
/**
* An identifier for a contract source within the system
* @category Object
*/

export type ContractSourceId = string;

export const ContractSourceIdGuard: t.Type<ContractSourceId> = t.string;

/**
* A reference to an {@link ObjectType}.
* @category Object
Expand All @@ -20,4 +28,6 @@ export interface Reference {
* {@link !io-ts-usage | Dynamic type guard} for the {@link Reference | reference type}.
* @category Object
*/
export const ReferenceGuard: t.Type<Reference> = t.type({ ref: t.string });
export const ReferenceGuard: t.Type<Reference> = t.type({
ref: ContractSourceIdGuard,
});
108 changes: 102 additions & 6 deletions packages/runtime/client/rest/src/contract/endpoints/sources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,26 @@ import * as E from "fp-ts/lib/Either.js";
import { pipe } from "fp-ts/lib/function.js";
import { formatValidationErrors } from "jsonbigint-io-ts-reporters";

import { BuiltinByteString } from "@marlowe.io/language-core-v1";
import { Bundle, Label } from "@marlowe.io/marlowe-object";
import { Contract } from "@marlowe.io/language-core-v1";
import {
Bundle,
Label,
ContractSourceId,
ContractSourceIdGuard,
} from "@marlowe.io/marlowe-object";
import { AxiosInstance } from "axios";

export interface CreateContractSourcesResponse {
contractSourceId: BuiltinByteString;
contractSourceId: ContractSourceId;
intermediateIds: {
[key: Label]: BuiltinByteString;
[key: Label]: ContractSourceId;
};
}

const CreateContractSourcesResponseGuard: t.Type<CreateContractSourcesResponse> =
t.type({
contractSourceId: G.BuiltinByteString,
intermediateIds: t.record(t.string, G.BuiltinByteString),
contractSourceId: ContractSourceIdGuard,
intermediateIds: t.record(t.string, ContractSourceIdGuard),
});

export const createContractSources = (axiosInstance: AxiosInstance) => {
Expand All @@ -40,3 +45,94 @@ export const createContractSources = (axiosInstance: AxiosInstance) => {
);
};
};

export interface GetContractBySourceIdRequest {
contractSourceId: ContractSourceId;
expand?: boolean;
}

export type GetContractBySourceIdResponse = Contract;

const GetContractBySourceIdResponseGuard: t.Type<GetContractBySourceIdResponse> =
G.Contract;

export const getContractSourceById =
(axiosInstance: AxiosInstance) =>
async ({
contractSourceId,
expand,
}: GetContractBySourceIdRequest): Promise<GetContractBySourceIdResponse> => {
const response = await axiosInstance.get(
`/contracts/sources/${encodeURIComponent(contractSourceId)}`,
{ params: { expand } }
);
Comment on lines +65 to +68
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding error handling for the HTTP request to handle network errors or non-200 status codes.

Also applies to: 96-98, 126-128

return pipe(
GetContractBySourceIdResponseGuard.decode(response.data),
E.match(
(e) => {
throw formatValidationErrors(e);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider improving error handling by wrapping validation errors in a user-friendly message or a custom error type to avoid exposing internal details and to provide more informative messages to the caller.

Also applies to: 103-103, 133-133

},
(e) => e
)
);
};
bjornkihlberg marked this conversation as resolved.
Show resolved Hide resolved

export interface GetContractSourceAdjacencyRequest {
contractSourceId: ContractSourceId;
}

export interface GetContractSourceAdjacencyResponse {
results: ContractSourceId[];
}

const GetContractSourceAdjacencyResponseGuard: t.Type<GetContractSourceAdjacencyResponse> =
t.type({ results: t.array(ContractSourceIdGuard) });

export const getContractSourceAdjacency =
(axiosInstance: AxiosInstance) =>
async ({
contractSourceId,
}: GetContractSourceAdjacencyRequest): Promise<GetContractSourceAdjacencyResponse> => {
const response = await axiosInstance.get(
`/contracts/sources/${encodeURIComponent(contractSourceId)}/adjacency`
);
return pipe(
GetContractSourceAdjacencyResponseGuard.decode(response.data),
E.match(
(e) => {
throw formatValidationErrors(e);
},
(e) => e
)
);
};
bjornkihlberg marked this conversation as resolved.
Show resolved Hide resolved

export interface GetContractSourceClosureRequest {
contractSourceId: ContractSourceId;
}

export interface GetContractSourceClosureResponse {
results: ContractSourceId[];
}

const GetContractSourceClosureResponseGuard: t.Type<GetContractSourceClosureResponse> =
t.type({ results: t.array(ContractSourceIdGuard) });

export const getContractSourceClosure =
(axiosInstance: AxiosInstance) =>
async ({
contractSourceId,
}: GetContractSourceClosureRequest): Promise<GetContractSourceClosureResponse> => {
const response = await axiosInstance.get(
`/contracts/sources/${encodeURIComponent(contractSourceId)}/closure`
);
return pipe(
GetContractSourceClosureResponseGuard.decode(response.data),
E.match(
(e) => {
throw formatValidationErrors(e);
},
(e) => e
)
);
};
bjornkihlberg marked this conversation as resolved.
Show resolved Hide resolved
45 changes: 45 additions & 0 deletions packages/runtime/client/rest/src/contract/next/endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,48 @@ export const getViaAxios: (axiosInstance: AxiosInstance) => GET =

const contractNextEndpoint = (contractId: ContractId): string =>
`/contracts/${encodeURIComponent(unContractId(contractId))}/next`;

export interface GetNextStepsForContractRequest {
contractId: ContractId;
validityStart: bigint;
validityEnd: bigint;
parties?: Party[];
}

export type GetNextStepsForContractResponse = Next;

const GetNextStepsForContractResponseGuard = Next;
bjornkihlberg marked this conversation as resolved.
Show resolved Hide resolved

export const getNextStepsForContract =
(axiosInstance: AxiosInstance) =>
async ({
contractId,
validityStart,
validityEnd,
parties,
}: GetNextStepsForContractRequest): Promise<GetNextStepsForContractResponse> => {
const response = await axiosInstance.get(
`/contracts/${encodeURIComponent(
unContractId(contractId)
)}/next?${stringify({
validityStart: posixTimeToIso8601(validityStart),
validityEnd: posixTimeToIso8601(validityEnd),
party: parties,
})}`,
{
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
}
);
return pipe(
GetNextStepsForContractResponseGuard.decode(response.data),
E.match(
(e) => {
throw formatValidationErrors(e);
},
(e) => e
)
);
bjornkihlberg marked this conversation as resolved.
Show resolved Hide resolved
};
Loading