Skip to content

Commit

Permalink
Merge pull request #1051 from dfinity/fix/remove-http-type-defintions
Browse files Browse the repository at this point in the history
🔥 remove redundant http type defintions
  • Loading branch information
letmejustputthishere authored Nov 20, 2024
2 parents a4dc2ae + 23a8cb4 commit 2586e76
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 341 deletions.
71 changes: 0 additions & 71 deletions motoko/send_http_get/src/send_http_get_backend/Types.mo

This file was deleted.

172 changes: 72 additions & 100 deletions motoko/send_http_get/src/send_http_get_backend/main.mo
Original file line number Diff line number Diff line change
Expand Up @@ -2,142 +2,114 @@ import Blob "mo:base/Blob";
import Cycles "mo:base/ExperimentalCycles";
import Nat64 "mo:base/Nat64";
import Text "mo:base/Text";

//import the custom types we have in Types.mo
import Types "Types";

import IC "ic:aaaaa-aa";

//Actor
actor {

//This method sends a GET request to a URL with a free API we can test.
//This method returns Coinbase data on the exchange rate between USD and ICP
//for a certain day.
//The API response looks like this:
// [
// [
// 1682978460, <-- start timestamp
// 5.714, <-- lowest price during time range
// 5.718, <-- highest price during range
// 5.714, <-- price at open
// 5.714, <-- price at close
// 243.5678 <-- volume of ICP traded
// ],
// ]
//This method sends a GET request to a URL with a free API we can test.
//This method returns Coinbase data on the exchange rate between USD and ICP
//for a certain day.
//The API response looks like this:
// [
// [
// 1682978460, <-- start timestamp
// 5.714, <-- lowest price during time range
// 5.718, <-- highest price during range
// 5.714, <-- price at open
// 5.714, <-- price at close
// 243.5678 <-- volume of ICP traded
// ],
// ]

//function to transform the response
public query func transform(raw : Types.TransformArgs) : async Types.CanisterHttpResponsePayload {
let transformed : Types.CanisterHttpResponsePayload = {
status = raw.response.status;
body = raw.response.body;
headers = [
{
name = "Content-Security-Policy";
value = "default-src 'self'";
},
{ name = "Referrer-Policy"; value = "strict-origin" },
{ name = "Permissions-Policy"; value = "geolocation=(self)" },
{
name = "Strict-Transport-Security";
value = "max-age=63072000";
},
{ name = "X-Frame-Options"; value = "DENY" },
{ name = "X-Content-Type-Options"; value = "nosniff" },
];
};
transformed;
public query func transform({
context : Blob;
response : IC.http_request_result;
}) : async IC.http_request_result {
{
response with headers = []; // not intersted in the headers
};
};

public func get_icp_usd_exchange() : async Text {

//1. DECLARE IC MANAGEMENT CANISTER
//We need this so we can use it to make the HTTP request
let ic : Types.IC = actor ("aaaaa-aa");

//2. SETUP ARGUMENTS FOR HTTP GET request
public func get_icp_usd_exchange() : async Text {

// 2.1 Setup the URL and its query parameters
//1. SETUP ARGUMENTS FOR HTTP GET request
let ONE_MINUTE : Nat64 = 60;
let start_timestamp : Types.Timestamp = 1682978460; //May 1, 2023 22:01:00 GMT
let start_timestamp : Nat64 = 1682978460; //May 1, 2023 22:01:00 GMT
let host : Text = "api.exchange.coinbase.com";
let url = "https://" # host # "/products/ICP-USD/candles?start=" # Nat64.toText(start_timestamp) # "&end=" # Nat64.toText(start_timestamp) # "&granularity=" # Nat64.toText(ONE_MINUTE);

// 2.2 prepare headers for the system http_request call
// 1.2 prepare headers for the system http_request call
let request_headers = [
{ name = "Host"; value = host # ":443" },
{ name = "User-Agent"; value = "exchange_rate_canister" },
{ name = "User-Agent"; value = "price-feed" },
];

// 2.2.1 Transform context
let transform_context : Types.TransformContext = {
function = transform;
context = Blob.fromArray([]);
};

// 2.3 The HTTP request
let http_request : Types.HttpRequestArgs = {
url = url;
max_response_bytes = null; //optional for request
headers = request_headers;
body = null; //optional for request
method = #get;
transform = ?transform_context;
// 1.3 The HTTP request
let http_request : IC.http_request_args = {
url = url;
max_response_bytes = null; //optional for request
headers = request_headers;
body = null; //optional for request
method = #get;
transform = ?{
function = transform;
context = Blob.fromArray([]);
};
};

//3. ADD CYCLES TO PAY FOR HTTP REQUEST
//2. ADD CYCLES TO PAY FOR HTTP REQUEST

//The IC specification spec says, "Cycles to pay for the call must be explicitly transferred with the call"
//IC management canister will make the HTTP request so it needs cycles
//See: https://internetcomputer.org/docs/current/motoko/main/cycles

//The way Cycles.add() works is that it adds those cycles to the next asynchronous call
//"Function add(amount) indicates the additional amount of cycles to be transferred in the next remote call"
//See: https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-http_request
//See:
// - https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-http_request
// - https://internetcomputer.org/docs/current/references/https-outcalls-how-it-works#pricing
// - https://internetcomputer.org/docs/current/developer-docs/gas-cost
Cycles.add<system>(230_949_972_000);

//4. MAKE HTTPS REQUEST AND WAIT FOR RESPONSE
//Since the cycles were added above, we can just call the IC management canister with HTTPS outcalls below
let http_response : Types.HttpResponsePayload = await ic.http_request(http_request);

//5. DECODE THE RESPONSE

//As per the type declarations in `src/Types.mo`, the BODY in the HTTP response
//comes back as [Nat8s] (e.g. [2, 5, 12, 11, 23]). Type signature:

//public type HttpResponsePayload = {

//3. MAKE HTTPS REQUEST AND WAIT FOR RESPONSE
let http_response : IC.http_request_result = await IC.http_request(http_request);

//4. DECODE THE RESPONSE

//As per the type declarations, the BODY in the HTTP response
//comes back as Blob. Type signature:

//public type http_request_result = {
// status : Nat;
// headers : [HttpHeader];
// body : [Nat8];
// body : Blob;
// };

//We need to decode that [Nat8] array that is the body into readable text.
//We need to decode that Blob that is the body into readable text.
//To do this, we:
// 1. Convert the [Nat8] into a Blob
// 2. Use Blob.decodeUtf8() method to convert the Blob to a ?Text optional
// 3. We use a switch to explicitly call out both cases of decoding the Blob into ?Text
let response_body: Blob = Blob.fromArray(http_response.body);
let decoded_text: Text = switch (Text.decodeUtf8(response_body)) {
case (null) { "No value returned" };
case (?y) { y };
// 1. Use Text.decodeUtf8() method to convert the Blob to a ?Text optional
// 2. We use a switch to explicitly call out both cases of decoding the Blob into ?Text
let decoded_text : Text = switch (Text.decodeUtf8(http_response.body)) {
case (null) { "No value returned" };
case (?y) { y };
};

//6. RETURN RESPONSE OF THE BODY
//5. RETURN RESPONSE OF THE BODY
//The API response will looks like this:

//
// ("[[1682978460,5.714,5.718,5.714,5.714,243.5678]]")

//Which can be formatted as this
//
//The API response looks like this:
// [
// [
// 1682978460, <-- start/timestamp
// 5.714, <-- low
// 5.718, <-- high
// 5.714, <-- open
// 5.714, <-- close
// 243.5678 <-- volume
// 1682978460, <-- start timestamp
// 5.714, <-- lowest price during time range
// 5.718, <-- highest price during range
// 5.714, <-- price at open
// 5.714, <-- price at close
// 243.5678 <-- volume of ICP traded
// ],
// ]
decoded_text
decoded_text;
};

};
68 changes: 0 additions & 68 deletions motoko/send_http_post/src/send_http_post_backend/Types.mo

This file was deleted.

Loading

0 comments on commit 2586e76

Please sign in to comment.