Skip to content

Commit

Permalink
http chapter is complete
Browse files Browse the repository at this point in the history
  • Loading branch information
lastmjs committed Oct 4, 2023
1 parent 3364c13 commit 2998d6b
Show file tree
Hide file tree
Showing 5 changed files with 475 additions and 439 deletions.
314 changes: 163 additions & 151 deletions the_azle_book/book/http.html
Original file line number Diff line number Diff line change
Expand Up @@ -153,64 +153,71 @@ <h2 id="incoming-http-requests"><a class="header" href="#incoming-http-requests"
</ul>
<pre><code class="language-typescript">import {
blob,
bool,
Canister,
Func,
nat16,
None,
Opt,
$query,
Query,
query,
Record,
text,
Tuple,
Variant,
Vec
} from 'azle';

type HttpRequest = Record&lt;{
method: string;
url: string;
headers: Vec&lt;Header&gt;;
body: blob;
}&gt;;

type HttpResponse = Record&lt;{
status_code: nat16;
headers: Vec&lt;Header&gt;;
body: blob;
streaming_strategy: Opt&lt;StreamingStrategy&gt;;
upgrade: Opt&lt;boolean&gt;;
}&gt;;

type Header = Tuple&lt;[string, string]&gt;;

type StreamingStrategy = Variant&lt;{
Callback: CallbackStrategy;
}&gt;;

type CallbackStrategy = Record&lt;{
callback: Callback;
token: Token;
}&gt;;

type Callback = Func&lt;Query&lt;(t: Token) =&gt; StreamingCallbackHttpResponse&gt;&gt;;

type StreamingCallbackHttpResponse = Record&lt;{
body: blob;
token: Opt&lt;Token&gt;;
}&gt;;

type Token = Record&lt;{
arbitrary_data: string;
}&gt;;

$query;
export function http_request(req: HttpRequest): HttpResponse {
return {
status_code: 200,
headers: [],
body: Uint8Array.from([]),
streaming_strategy: Opt.None,
upgrade: Opt.Some(false)
};
}
const Token = Record({
// add whatever fields you'd like
arbitrary_data: text
});

const StreamingCallbackHttpResponse = Record({
body: blob,
token: Opt(Token)
});

export const Callback = Func([text], StreamingCallbackHttpResponse, 'query');

const CallbackStrategy = Record({
callback: Callback,
token: Token
});

const StreamingStrategy = Variant({
Callback: CallbackStrategy
});

type HeaderField = [text, text];
const HeaderField = Tuple(text, text);

const HttpResponse = Record({
status_code: nat16,
headers: Vec(HeaderField),
body: blob,
streaming_strategy: Opt(StreamingStrategy),
upgrade: Opt(bool)
});

const HttpRequest = Record({
method: text,
url: text,
headers: Vec(HeaderField),
body: blob,
certificate_version: Opt(nat16)
});

export default Canister({
http_request: query([HttpRequest], HttpResponse, (req) =&gt; {
return {
status_code: 200,
headers: [],
body: Buffer.from('hello'),
streaming_strategy: None,
upgrade: None
};
})
});
</code></pre>
<h2 id="outgoing-http-requests"><a class="header" href="#outgoing-http-requests">Outgoing HTTP requests</a></h2>
<p>Examples:</p>
Expand All @@ -219,117 +226,122 @@ <h2 id="outgoing-http-requests"><a class="header" href="#outgoing-http-requests"
<li><a href="https://github.com/demergent-labs/azle/tree/main/examples/outgoing_http_requests">outgoing_http_requests</a></li>
</ul>
<pre><code class="language-typescript">import {
Canister,
ic,
$init,
match,
init,
nat32,
$query,
Principal,
query,
Some,
StableBTreeMap,
$update,
Opt
text,
update
} from 'azle';
import {
HttpResponse,
HttpTransformArgs,
managementCanister
} from 'azle/canisters/management';
import decodeUtf8 from 'decode-utf8';
import encodeUtf8 from 'encode-utf8';

type JSON = string;

let stableStorage = new StableBTreeMap&lt;string, string&gt;(0, 25, 1_000);

$init;
export function init(ethereumUrl: string): void {
stableStorage.insert('ethereumUrl', ethereumUrl);
}

$update;
export async function ethGetBalance(ethereumAddress: string): Promise&lt;JSON&gt; {
const httpResult = await managementCanister
.http_request({
url: match(stableStorage.get('ethereumUrl'), {
Some: (url) =&gt; url,
None: () =&gt; ''
}),
max_response_bytes: Opt.Some(2_000n),
method: {
post: null
},
headers: [],
body: Opt.Some(
new Uint8Array(
encodeUtf8(
JSON.stringify({
jsonrpc: '2.0',
method: 'eth_getBalance',
params: [ethereumAddress, 'earliest'],
id: 1
})
)
)
),
transform: Opt.Some({
function: [ic.id(), 'ethTransform'],
context: Uint8Array.from([])
})
})
.cycles(50_000_000n)
.call();

return match(httpResult, {
Ok: (httpResponse) =&gt; decodeUtf8(Uint8Array.from(httpResponse.body)),
Err: (err) =&gt; ic.trap(err)
});
}

$update;
export async function ethGetBlockByNumber(number: nat32): Promise&lt;JSON&gt; {
const httpResult = await managementCanister
.http_request({
url: match(stableStorage.get('ethereumUrl'), {
Some: (url) =&gt; url,
None: () =&gt; ''
}),
max_response_bytes: Opt.Some(2_000n),
method: {
post: null
},
headers: [],
body: Opt.Some(
new Uint8Array(
encodeUtf8(
JSON.stringify({
jsonrpc: '2.0',
method: 'eth_getBlockByNumber',
params: [`0x${number.toString(16)}`, false],
id: 1
})
)
)
),
transform: Opt.Some({
function: [ic.id(), 'ethTransform'],
context: Uint8Array.from([])
})
})
.cycles(50_000_000n)
.call();

return match(httpResult, {
Ok: (httpResponse) =&gt; decodeUtf8(Uint8Array.from(httpResponse.body)),
Err: (err) =&gt; ic.trap(err)
});
}

$query;
export function ethTransform(args: HttpTransformArgs): HttpResponse {
return {
...args.response,
headers: []
};
}

let stableStorage = StableBTreeMap(text, text, 0);

export default Canister({
init: init([text], (ethereumUrl) =&gt; {
stableStorage.insert('ethereumUrl', ethereumUrl);
}),
ethGetBalance: update([text], text, async (ethereumAddress) =&gt; {
const urlOpt = stableStorage.get('ethereumUrl');

if ('None' in urlOpt) {
throw new Error('ethereumUrl is not defined');
}

const url = urlOpt.Some;

const httpResponse = await ic.call(managementCanister.http_request, {
args: [
{
url,
max_response_bytes: Some(2_000n),
method: {
post: null
},
headers: [],
body: Some(
Buffer.from(
JSON.stringify({
jsonrpc: '2.0',
method: 'eth_getBalance',
params: [ethereumAddress, 'earliest'],
id: 1
}),
'utf-8'
)
),
transform: Some({
function: [ic.id(), 'ethTransform'] as [
Principal,
string
],
context: Uint8Array.from([])
})
}
],
cycles: 50_000_000n
});

return Buffer.from(httpResponse.body.buffer).toString('utf-8');
}),
ethGetBlockByNumber: update([nat32], text, async (number) =&gt; {
const urlOpt = stableStorage.get('ethereumUrl');

if ('None' in urlOpt) {
throw new Error('ethereumUrl is not defined');
}

const url = urlOpt.Some;

const httpResponse = await ic.call(managementCanister.http_request, {
args: [
{
url,
max_response_bytes: Some(2_000n),
method: {
post: null
},
headers: [],
body: Some(
Buffer.from(
JSON.stringify({
jsonrpc: '2.0',
method: 'eth_getBlockByNumber',
params: [`0x${number.toString(16)}`, false],
id: 1
}),
'utf-8'
)
),
transform: Some({
function: [ic.id(), 'ethTransform'] as [
Principal,
string
],
context: Uint8Array.from([])
})
}
],
cycles: 50_000_000n
});

return Buffer.from(httpResponse.body.buffer).toString('utf-8');
}),
ethTransform: query([HttpTransformArgs], HttpResponse, (args) =&gt; {
return {
...args.response,
headers: []
};
})
});
</code></pre>

</main>
Expand Down
Loading

0 comments on commit 2998d6b

Please sign in to comment.