Embedding Apexlang into Apps
Apexlang is most commonly used as a code generator for your projects. In some cases, your system may need to read in the information contained in an Apexlang specification. This could be useful for platforms or tools to inspect specifications dynamically. Some scenarios include:
- Validating or sanitizing input data
- Comparing two versions to detect a breaking change
- Discovering data elements that are sensitive (PCI/DSS) or encrypted
Libraries
Apexlang libraries exist for TypeScript and Go.
- @apexlang/core - TypeScript Apexlang parser used by the CLI and VS Code extension
- @apexlang/codegen - TypeScript code generation modules loaded by the
apex
CLI (e.g.apex generate
) - github.com/apexlang/apex-go - Go Apexlang parser for embedding in Go platforms
WebAssembly module
To reach a broader set of languages, the Apexlang Go parser is also released as a WebAssembly module and loadable via a Wasm runtime such as Wasmtime. The module parses and validates an Apexlang specification and returns a JSON representation that is easier to interpret in languages with JSON support.
Download
Two implementations of the Wasm module can be downloaded from the Apexlang Go releases page.
- waPC - Uses the waPC protocol to invoke the Apexlang parser. This is the easiest method for integration, however you must be using a programming language that has a waPC host implementation.
- Core Wasm - Loadable by any programming language with a WebAssembly runtime (e.g. Wasmtime); however, puts the responsibility of passing in the specification on your application.
Each parser accepts an Apexlang specification as a string and returns the JSON string represention. The JSON follows this schema.
waPC (apex-wapc.wasm)
parse
guest call
Operation: apexlang.v1.Parser/parse
Input formatted as MsgPack
{
"source": "... Apexlang specification as string ..."
}
Output formatted as MsgPack
{
"namespace": { /* The parsed Apexlang namespace. See model spec. */ },
/* or */
"errors": [
{
"message": "... The error message ...",
"positions": [ 1032 /* array of positions in the document where the error occurs*/ ],
"locations": [
{
"line": 123, /* The line number of the error */
"column": 10 /* The column number of the error */
}
]
}
]
}
resolve
host call
Namespace: apexlang.v1.Resolver
Operation: resolve
Input formatted as MsgPack
{
"location": "The imported specification to resolve",
"from": "The specification performing the import"
}
Core Wasm (apex-perser.wasm)
Parsing and validating
The Wasm module exposes 3 functions:
_malloc(size u32) u32
- Allocate memory to pass in Apexlang specifications_free(ptr u32)
- Free memory allocated by_malloc
parse(ptr u32, size u32) u64
- The main parse function that returns a valid JSON representation
Returned u64
values represents a 32-bit pointer and size pair of a buffer. The upper 32-bits is for the pointer in the WebAssembly module's linear memory. The lower 32-bits stores the size of the buffer.
ptr := uintptr(ptrsize >> 32)
size := uint32(ptrsize & 0xFFFFFFFF)
Embedding Apexlang parsing in your application follows these steps:
- calls
_malloc
to receive a buffer for the byte count of the Apexlang specification - copies or directly load the Apexlang specification into the allocated buffer
- calls
parse
with the buffer pointer and size - extract the JSON (or error) string from the buffer returned
- call
_free
to release the memory allocated by_malloc
in step 1
If the returned string starts with error:
then the string represents and error in the parser. Otherwise, it contains a valid JSON representation of your Apexlang specification.
Resolving imports
If a specification contains imports, the module makes a host call to apex::resolve
to retrieve the contents of the imported specification.
resolve(location_ptr u32, location_size u32, from_ptr u32, from_size u32) u64
- Loads an imported Apexlang specification
location
and from
are string values. location
is the specification to load and from
is the specification performing the import. The apex
CLI installs importable definitions in ~/.apex/definitions
your implementation could load them from alternate locations.
Example
Here is an example using wazero to invoke the Apexlang parser.