Skip to content

Commit

Permalink
Template ID to JsString JSON serialization (#3991)
Browse files Browse the repository at this point in the history
* test cases: domain.TemplateId JSON serialization to JsString

* JSON protocol updated

* Fixing json-api test cases

* test cases: domain.TemplateId JSON serialization to JsString

* JSON protocol updated

* Fixing json-api test cases

* Adapt daml2ts and support libraries

* Update documentation

CHANGELOG_BEGIN

[JSON API - Experimental]
- Use JSON string to encode template IDs. Use colon (``:``) to separate parts of the ID.
  The request format, with optional package ID:
  - "<module>:<entity>"
  - "<package ID>:<module>:<entity>"
  The response always contains fully qualified template ID in the format:
  - "<package ID>:<module>:<entity>"
  See #3647.

CHANGELOG_END

* Minor documentation formatting changes.

Co-authored-by: Martin Huschenbett <martin.huschenbett@posteo.me>
  • Loading branch information
leo-da and hurryabit committed Jan 9, 2020
1 parent c0f387f commit 93216a0
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 143 deletions.
104 changes: 39 additions & 65 deletions docs/source/json-api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -158,12 +158,15 @@ For production use, we have a tool in development for generating proper
RSA-encrypted tokens locally, which will arrive when the service also
supports such tokens.

GET http://localhost:7575/contracts/search
==========================================
GET ``/contracts/search``
=========================

List all currently active contracts for all known templates. Note that the retrieved contracts do not get persisted into query store database.

POST http://localhost:7575/contracts/search
===========================================
The response is the same as for the POST method below.

POST ``/contracts/search``
==========================

List currently active contracts that match a given query.

Expand All @@ -175,7 +178,7 @@ application/json body, formatted according to the :doc:`search-query-language`:
.. code-block:: json
{
"%templates": [{"moduleName": "Iou", "entityName": "Iou"}],
"%templates": ["Iou:Iou"],
"amount": 999.99
}
Expand Down Expand Up @@ -212,18 +215,14 @@ Each contract formatted according to :doc:`lf-value-specification`.
"Alice"
],
"contractId": "#52:0",
"templateId": {
"packageId": "b10d22d6c2f2fae41b353315cf893ed66996ecb0abe4424ea6a81576918f658a",
"moduleName": "Iou",
"entityName": "Iou"
}
"templateId": "b10d22d6c2f2fae41b353315cf893ed66996ecb0abe4424ea6a81576918f658a:Iou:Iou"
}
],
"status": 200
}
POST http://localhost:7575/command/create
=========================================
POST ``/command/create``
========================

Create a contract.

Expand All @@ -235,10 +234,7 @@ application/json body, ``argument`` formatted according to :doc:`lf-value-specif
.. code-block:: json
{
"templateId": {
"moduleName": "Iou",
"entityName": "Iou"
},
"templateId": "Iou:Iou",
"argument": {
"observers": [],
"issuer": "Alice",
Expand Down Expand Up @@ -268,21 +264,17 @@ Response
"signatories": [
"Alice"
],
"contractId": "#52:0",
"templateId": {
"packageId": "b10d22d6c2f2fae41b353315cf893ed66996ecb0abe4424ea6a81576918f658a",
"moduleName": "Iou",
"entityName": "Iou"
}
"contractId": "#124:0",
"templateId": "11c8f3ace75868d28136adc5cfc1de265a9ee5ad73fe8f2db97510e3631096a2:Iou:Iou"
}
}
POST http://localhost:7575/command/exercise
============================================
POST ``/command/exercise``
==========================

Exercise a choice on a contract.

``"contractId": "#52:0"`` is the value from the create output.
``"contractId": "#124:0"`` is the value from the create output.

Request
-------
Expand All @@ -292,11 +284,8 @@ application/json body:
.. code-block:: json
{
"templateId": {
"moduleName": "Iou",
"entityName": "Iou"
},
"contractId": "#52:0",
"templateId": "Iou:Iou",
"contractId": "#124:0",
"choice": "Iou_Transfer",
"argument": {
"newOwner": "Alice"
Expand All @@ -311,16 +300,12 @@ Response
{
"status": 200,
"result": {
"exerciseResult": "#205:1",
"exerciseResult": "#201:1",
"contracts": [
{
"archived": {
"contractId": "#52:0",
"templateId": {
"packageId": "b10d22d6c2f2fae41b353315cf893ed66996ecb0abe4424ea6a81576918f658a",
"moduleName": "Iou",
"entityName": "Iou"
}
"contractId": "#124:0",
"templateId": "11c8f3ace75868d28136adc5cfc1de265a9ee5ad73fe8f2db97510e3631096a2:Iou:Iou"
}
},
{
Expand All @@ -340,12 +325,8 @@ Response
"signatories": [
"Alice"
],
"contractId": "#205:1",
"templateId": {
"packageId": "b10d22d6c2f2fae41b353315cf893ed66996ecb0abe4424ea6a81576918f658a",
"moduleName": "Iou",
"entityName": "IouTransfer"
}
"contractId": "#201:1",
"templateId": "11c8f3ace75868d28136adc5cfc1de265a9ee5ad73fe8f2db97510e3631096a2:Iou:IouTransfer"
}
}
]
Expand All @@ -357,8 +338,8 @@ Where:
- ``exerciseResult`` -- the return value of the exercised contract choice.
- ``contracts`` -- an array containing contracts that were archived and created as part of the exercised choice. The array may contain: **zero or many** ``{"archived": {...}}`` and **zero or many** ``{"created": {...}}`` elements. The order of the contracts is the same as on the ledger.

GET http://localhost:7575/parties
=================================
GET ``/parties``
================

Response
--------
Expand All @@ -375,8 +356,8 @@ Response
]
}
POST http://localhost:7575/contracts/lookup
============================================
POST ``/contracts/lookup``
==========================

Lookup by Contract ID
---------------------
Expand All @@ -389,7 +370,7 @@ application/json body:
.. code-block:: json
{
"contractId": "#205:1"
"contractId": "#201:1"
}
Contract Not Found Response
Expand Down Expand Up @@ -425,12 +406,8 @@ Contract Found Response
"signatories": [
"Alice"
],
"contractId": "#205:1",
"templateId": {
"packageId": "b10d22d6c2f2fae41b353315cf893ed66996ecb0abe4424ea6a81576918f658a",
"moduleName": "Iou",
"entityName": "IouTransfer"
}
"contractId": "#201:1",
"templateId": "11c8f3ace75868d28136adc5cfc1de265a9ee5ad73fe8f2db97510e3631096a2:Iou:IouTransfer"
}
}
Expand All @@ -445,10 +422,7 @@ application/json body:
.. code-block:: json
{
"templateId": {
"moduleName": "Account",
"entityName": "Account"
},
"templateId": "Account:Account",
"key": [
"Alice",
"abc123"
Expand Down Expand Up @@ -477,7 +451,11 @@ Contract Found Response
"agreementText": "",
"payload": {
"owner": "Alice",
"number": "abc123"
"number": "abc123",
"status": {
"tag": "Enabled",
"value": "2020-01-01T00:00:01Z"
}
},
"signatories": [
"Alice"
Expand All @@ -486,11 +464,7 @@ Contract Found Response
"_1": "Alice",
"_2": "abc123"
},
"contractId": "#1:0",
"templateId": {
"packageId": "d7be7966c36fb3588bee1b727cef78a7251caabe3ae4105ba62f06a7af97272b",
"moduleName": "Account",
"entityName": "Account"
}
"contractId": "#697:0",
"templateId": "11c8f3ace75868d28136adc5cfc1de265a9ee5ad73fe8f2db97510e3631096a2:Account:Account"
}
}
31 changes: 12 additions & 19 deletions language-support/ts/codegen/src/TsCodeGenMain.hs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ daml2ts Options{..} pkgId pkg mbPkgName = do
T.writeFileUtf8 (outputDir </> "packageId.ts") $ T.unlines
["export default '" <> unPackageId pkgId <> "';"]
forM_ (packageModules pkg) $ \mod -> do
whenJust (genModule mod) $ \modTxt -> do
whenJust (genModule pkgId mod) $ \modTxt -> do
let outputFile = outputDir </> joinPath (map T.unpack (unModuleName (moduleName mod))) <.> "ts"
putStrLn $ "Generating " ++ outputFile
createDirectoryIfMissing True (takeDirectory outputFile)
Expand All @@ -76,8 +76,8 @@ daml2ts Options{..} pkgId pkg mbPkgName = do
dup :: a -> (a, a)
dup x = (x, x)

genModule :: Module -> Maybe T.Text
genModule mod
genModule :: PackageId -> Module -> Maybe T.Text
genModule curPkgId mod
| null serDefs = Nothing
| otherwise =
let curModName = moduleName mod
Expand All @@ -87,7 +87,7 @@ genModule mod
where
lenModName = length (unModuleName curModName)
tpls = moduleTemplates mod
(defSers, refs) = unzip (map (genDataDef curModName tpls) serDefs)
(defSers, refs) = unzip (map (genDataDef curPkgId curModName tpls) serDefs)
header =
["// Generated from " <> T.intercalate "/" (unModuleName curModName) <> ".daml"
,"/* eslint-disable @typescript-eslint/camelcase */"
Expand All @@ -103,34 +103,27 @@ genModule mod
PRImport pkgId -> "../" <> unPackageId pkgId <> "/"
, let modNameStr = genModuleRef modRef
]
templateId
| null (moduleTemplates mod) = []
| otherwise =
["import packageId from '" <> pkgRootPath <> "/packageId';"
,"const moduleName = '" <> T.intercalate "." (unModuleName curModName) <> "';"
,"const templateId = (entityName: string): daml.TemplateId => ({packageId, moduleName, entityName});"
]
defs = map (\(def, ser) -> def ++ ser) defSers
in
Just $ T.unlines $ intercalate [""] $ filter (not . null) $ header : imports : templateId : defs
Just $ T.unlines $ intercalate [""] $ filter (not . null) $ header : imports : defs
where
serDefs = filter (getIsSerializable . dataSerializable) (NM.toList (moduleDataTypes mod))

genDataDef :: ModuleName -> NM.NameMap Template -> DefDataType -> (([T.Text], [T.Text]), Set.Set ModuleRef)
genDataDef curModName tpls def = case unTypeConName (dataTypeCon def) of
genDataDef :: PackageId -> ModuleName -> NM.NameMap Template -> DefDataType -> (([T.Text], [T.Text]), Set.Set ModuleRef)
genDataDef curPkgId curModName tpls def = case unTypeConName (dataTypeCon def) of
[] -> error "IMPOSSIBLE: empty type constructor name"
_: _: _: _ -> error "IMPOSSIBLE: multi-part type constructor of more than two names"
[conName] -> genDefDataType conName curModName tpls def
[conName] -> genDefDataType curPkgId conName curModName tpls def
[c1, c2] -> ((makeNamespace $ map (" " <>) typs, makeNamespace $ map (" " <>) sers), refs)
where
((typs, sers), refs) = genDefDataType c2 curModName tpls def
((typs, sers), refs) = genDefDataType curPkgId c2 curModName tpls def
ns = c1 <> "_NS"
makeNamespace stuff =
[ "// eslint-disable-next-line @typescript-eslint/no-namespace"
, "export namespace " <> ns <> " {"] ++ stuff ++ ["} //namespace " <> ns] ++ [""]

genDefDataType :: T.Text -> ModuleName -> NM.NameMap Template -> DefDataType -> (([T.Text], [T.Text]), Set.Set ModuleRef)
genDefDataType conName curModName tpls def =
genDefDataType :: PackageId -> T.Text -> ModuleName -> NM.NameMap Template -> DefDataType -> (([T.Text], [T.Text]), Set.Set ModuleRef)
genDefDataType curPkgId conName curModName tpls def =
case dataCons def of
DataVariant bs ->
let
Expand Down Expand Up @@ -190,7 +183,7 @@ genDefDataType conName curModName tpls def =
[" " <> x <> ": daml.Choice<" <> conName <> ", " <> t <> ", " <> rtyp <> " >;" | (x, t, rtyp, _) <- chcs] ++
["} = {"
] ++
[" templateId: templateId('" <> conName <> "'),"
[" templateId: '" <> unPackageId curPkgId <> ":" <> T.intercalate "." (unModuleName curModName) <> ":" <> conName <> "',"
," keyDecoder: " <> keySer <> ","
] ++
map (" " <>) (onHead ("decoder: " <>) serDesc) ++
Expand Down
23 changes: 5 additions & 18 deletions language-support/ts/codegen/tests/ts/daml-json-types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,12 @@ export interface Serializable<T> {
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
export const STATIC_IMPLEMENTS_SERIALIZABLE_CHECK = <T>(_: Serializable<T>) => {}

/**
* Identifier of a DAML template.
*/
export type TemplateId = {
packageId: string;
moduleName: string;
entityName: string;
}

/**
* Interface for objects representing DAML templates. It is similar to the
* `Template` type class in DAML.
*/
export interface Template<T extends object, K = unknown> extends Serializable<T> {
templateId: TemplateId;
templateId: string;
keyDecoder: () => jtv.Decoder<K>;
Archive: Choice<T, {}, {}>;
}
Expand All @@ -51,11 +42,8 @@ export interface Choice<T extends object, C, R> {

const registeredTemplates: {[key: string]: Template<object>} = {};

const templateIdToString = ({packageId, moduleName, entityName}: TemplateId) =>
`${packageId}:${moduleName}:${entityName}`;

export const registerTemplate = <T extends object>(template: Template<T>) => {
const templateId = templateIdToString(template.templateId);
const templateId = template.templateId;
const oldTemplate = registeredTemplates[templateId];
if (oldTemplate === undefined) {
registeredTemplates[templateId] = template;
Expand All @@ -65,11 +53,10 @@ export const registerTemplate = <T extends object>(template: Template<T>) => {
}
}

export const lookupTemplate = (templateId: TemplateId): Template<object> => {
const templateIdStr = templateIdToString(templateId);
const template = registeredTemplates[templateIdStr];
export const lookupTemplate = (templateId: string): Template<object> => {
const template = registeredTemplates[templateId];
if (template === undefined) {
throw Error(`Trying to look up template ${templateIdStr}.`);
throw Error(`Trying to look up template ${templateId}.`);
}
return template;
}
Expand Down

0 comments on commit 93216a0

Please sign in to comment.