From 95481510d46ad4072f22440395bf0248effa1cf8 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Wed, 10 Jun 2026 17:16:04 +0200 Subject: [PATCH 1/8] chore: migrate motoko/send_http_post to icp-cli Replace dfx toolchain with icp-cli: add icp.yaml, update mops.toml to moc 1.9.0 / core 2.5.0 / ic 4.0.0, move main.mo to backend/app.mo, replace ic:aaaaa-aa with mo:ic import, add CI workflow, and delete obsolete dfx.json, BUILD.md, webpack.config.js, package.json, and .devcontainer. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/send_http_post.yml | 28 +++++ .../.devcontainer/devcontainer.json | 20 ---- motoko/send_http_post/.gitignore | 6 +- motoko/send_http_post/BUILD.md | 113 ------------------ motoko/send_http_post/Makefile | 27 +---- motoko/send_http_post/README.md | 34 +++--- .../main.mo => backend/app.mo} | 12 +- motoko/send_http_post/dfx.json | 15 --- motoko/send_http_post/icp.yaml | 4 + motoko/send_http_post/mops.toml | 18 +-- motoko/send_http_post/package.json | 48 -------- motoko/send_http_post/webpack.config.js | 96 --------------- 12 files changed, 76 insertions(+), 345 deletions(-) create mode 100644 .github/workflows/send_http_post.yml delete mode 100644 motoko/send_http_post/.devcontainer/devcontainer.json delete mode 100644 motoko/send_http_post/BUILD.md rename motoko/send_http_post/{src/send_http_post_backend/main.mo => backend/app.mo} (88%) delete mode 100644 motoko/send_http_post/dfx.json create mode 100644 motoko/send_http_post/icp.yaml delete mode 100644 motoko/send_http_post/package.json delete mode 100644 motoko/send_http_post/webpack.config.js diff --git a/.github/workflows/send_http_post.yml b/.github/workflows/send_http_post.yml new file mode 100644 index 000000000..2e1bd55cb --- /dev/null +++ b/.github/workflows/send_http_post.yml @@ -0,0 +1,28 @@ +name: send_http_post + +on: + push: + branches: [master] + pull_request: + paths: + - motoko/send_http_post/** + - .github/workflows/send_http_post.yml + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + motoko-send_http_post: + runs-on: ubuntu-24.04 + container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.1 + env: + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - name: Deploy and test + working-directory: motoko/send_http_post + run: | + icp network start -d + icp deploy + make test diff --git a/motoko/send_http_post/.devcontainer/devcontainer.json b/motoko/send_http_post/.devcontainer/devcontainer.json deleted file mode 100644 index ebb0b8bcc..000000000 --- a/motoko/send_http_post/.devcontainer/devcontainer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "ICP Dev Environment", - "image": "ghcr.io/dfinity/icp-dev-env-slim:22", - "forwardPorts": [4943, 5173], - "portsAttributes": { - "4943": { - "label": "dfx", - "onAutoForward": "ignore" - }, - "5173": { - "label": "vite", - "onAutoForward": "openBrowser" - } - }, - "customizations": { - "vscode": { - "extensions": ["dfinity-foundation.vscode-motoko"] - } - } -} diff --git a/motoko/send_http_post/.gitignore b/motoko/send_http_post/.gitignore index b75c888e0..fe93358fa 100644 --- a/motoko/send_http_post/.gitignore +++ b/motoko/send_http_post/.gitignore @@ -10,12 +10,12 @@ # dfx temporary files .dfx/ +# icp-cli cache +.icp/ + # generated files src/declarations/ # frontend code node_modules/ dist/ - -# environment variables -.env diff --git a/motoko/send_http_post/BUILD.md b/motoko/send_http_post/BUILD.md deleted file mode 100644 index 24cfcb754..000000000 --- a/motoko/send_http_post/BUILD.md +++ /dev/null @@ -1,113 +0,0 @@ -# Continue building locally - -Projects deployed through ICP Ninja are temporary; they will only be live for 20 minutes before they are removed. The command-line tool `dfx` can be used to continue building your ICP Ninja project locally and deploy it to the mainnet. - -To migrate your ICP Ninja project off of the web browser and develop it locally, follow these steps. - -### 1. Install developer tools. - -You can install the developer tools natively or use Dev Containers. - -#### Option 1: Natively install developer tools - -> Installing `dfx` natively is currently only supported on macOS and Linux systems. On Windows, it is recommended to use the Dev Containers option. - -1. Install `dfx` with the following command: - -``` - -sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)" - -``` - -> On Apple Silicon (e.g., Apple M1 chip), make sure you have Rosetta installed (`softwareupdate --install-rosetta`). - -2. [Install NodeJS](https://nodejs.org/en/download/package-manager). - -3. For Rust projects, you will also need to: - -- Install [Rust](https://doc.rust-lang.org/cargo/getting-started/installation.html#install-rust-and-cargo): `curl https://sh.rustup.rs -sSf | sh` - -- Install [candid-extractor](https://crates.io/crates/candid-extractor): `cargo install candid-extractor` - -4. For Motoko projects, you will also need to: - -- Install the Motoko package manager [Mops](https://docs.mops.one/quick-start#2-install-mops-cli): `npm i -g ic-mops` - -Lastly, navigate into your project's directory that you downloaded from ICP Ninja. - -#### Option 2: Dev Containers - -Continue building your projects locally by installing the [Dev Container extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) for VS Code and [Docker](https://docs.docker.com/engine/install/). - -Make sure Docker is running, then navigate into your project's directory that you downloaded from ICP Ninja and start the Dev Container by selecting `Dev-Containers: Reopen in Container` in VS Code's command palette (F1 or Ctrl/Cmd+Shift+P). - -> Note that local development ports (e.g. the ports used by `dfx` or `vite`) are forwarded from the Dev Container to your local machine. In the VS code terminal, use Ctrl/Cmd+Click on the displayed local URLs to open them in your browser. To view the current port mappings, click the "Ports" tab in the VS Code terminal window. - -### 2. Start the local development environment. - -``` -dfx start --background -``` - -### 3. Create a local developer identity. - -To manage your project's canisters, it is recommended that you create a local [developer identity](https://internetcomputer.org/docs/building-apps/getting-started/identities) rather than use the `dfx` default identity that is not stored securely. - -To create a new identity, run the commands: - -``` - -dfx identity new IDENTITY_NAME - -dfx identity use IDENTITY_NAME - -``` - -Replace `IDENTITY_NAME` with your preferred identity name. The first command `dfx start --background` starts the local `dfx` processes, then `dfx identity new` will create a new identity and return your identity's seed phase. Be sure to save this in a safe, secure location. - -The third command `dfx identity use` will tell `dfx` to use your new identity as the active identity. Any canister smart contracts created after running `dfx identity use` will be owned and controlled by the active identity. - -Your identity will have a principal ID associated with it. Principal IDs are used to identify different entities on ICP, such as users and canisters. - -[Learn more about ICP developer identities](https://internetcomputer.org/docs/building-apps/getting-started/identities). - -### 4. Deploy the project locally. - -Deploy your project to your local developer environment with: - -``` -npm install -dfx deploy - -``` - -Your project will be hosted on your local machine. The local canister URLs for your project will be shown in the terminal window as output of the `dfx deploy` command. You can open these URLs in your web browser to view the local instance of your project. - -### 5. Obtain cycles. - -To deploy your project to the mainnet for long-term public accessibility, first you will need [cycles](https://internetcomputer.org/docs/building-apps/getting-started/tokens-and-cycles). Cycles are used to pay for the resources your project uses on the mainnet, such as storage and compute. - -> This cost model is known as ICP's [reverse gas model](https://internetcomputer.org/docs/building-apps/essentials/gas-cost), where developers pay for their project's gas fees rather than users pay for their own gas fees. This model provides an enhanced end user experience since they do not need to hold tokens or sign transactions when using a dapp deployed on ICP. - -> Learn how much a project may cost by using the [pricing calculator](https://internetcomputer.org/docs/building-apps/essentials/cost-estimations-and-examples). - -Cycles can be obtained through [converting ICP tokens into cycles using `dfx`](https://internetcomputer.org/docs/building-apps/developer-tools/dfx/dfx-cycles#dfx-cycles-convert). - -### 6. Deploy to the mainnet. - -Once you have cycles, run the command: - -``` - -dfx deploy --network ic - -``` - -After your project has been deployed to the mainnet, it will continuously require cycles to pay for the resources it uses. You will need to [top up](https://internetcomputer.org/docs/building-apps/canister-management/topping-up) your project's canisters or set up automatic cycles management through a service such as [CycleOps](https://cycleops.dev/). - -> If your project's canisters run out of cycles, they will be removed from the network. - -## Additional examples - -Additional code examples and sample applications can be found in the [DFINITY examples repo](https://github.com/dfinity/examples). diff --git a/motoko/send_http_post/Makefile b/motoko/send_http_post/Makefile index 235f848c9..45acda99f 100644 --- a/motoko/send_http_post/Makefile +++ b/motoko/send_http_post/Makefile @@ -1,23 +1,8 @@ -.PHONY: all -all: build - -.PHONY: node_modules -.SILENT: node_modules -node_modules: - npm install - -.PHONY: deploy -.SILENT: deploy -build: node_modules - dfx canister deploy send_http_post_backend - .PHONY: test -.SILENT: test -test: deploy - dfx canister call send_http_post_backend send_http_post_request \ - | grep 'POST request from an ICP canister' && echo 'PASS' -.PHONY: clean -.SILENT: clean -clean: - rm -fr .dfx \ No newline at end of file +test: + @echo "=== Test 1: send_http_post_request returns POST echo ===" + @result=$$(icp canister call backend send_http_post_request '()') && \ + echo "$$result" && \ + echo "$$result" | grep -q 'POST request from an ICP canister' && \ + echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/send_http_post/README.md b/motoko/send_http_post/README.md index d27b0536e..cd1f3d233 100644 --- a/motoko/send_http_post/README.md +++ b/motoko/send_http_post/README.md @@ -1,27 +1,31 @@ # HTTP: POST -The purpose of this dapp is to give developers a minimal dapp that uses the IC's HTTPS outcalls feature to make a `POST` request. +[View this sample's code on GitHub](https://github.com/dfinity/examples/tree/master/motoko/send_http_post) -This demo goes in hand with the [developer documentation on HTTPS outcalls](https://internetcomputer.org/docs/building-apps/network-features/using-http/https-outcalls/post). +## Overview -## Deploying from ICP Ninja +This example demonstrates how to use the ICP HTTPS outcalls feature to make a `POST` request from a Motoko canister. It sends a plain-text body to `postman-echo.com/post`, which echoes back the request as JSON, allowing you to verify the POST body and headers were sent correctly. -[![](https://icp.ninja/assets/open.svg)](https://icp.ninja/editor?g=https://github.com/dfinity/examples/tree/master/motoko/send_http_post) +## Build and deploy from the command line -## Build and deploy from the command-line - -### 1. [Download and install the IC SDK.](https://internetcomputer.org/docs/building-apps/getting-started/install) - -### 2. Download your project from ICP Ninja using the 'Download files' button on the upper left corner, or [clone the GitHub examples repository.](https://github.com/dfinity/examples/) - -### 3. Navigate into the project's directory. - -### 4. Deploy the project to your local environment: +### Prerequisites +- Node.js +- icp-cli: `npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm` +### Install +```bash +git clone https://github.com/dfinity/examples +cd examples/motoko/send_http_post ``` -dfx start --background --clean && dfx deploy + +### Deploy and test +```bash +icp network start -d +icp deploy +make test +icp network stop ``` ## Security considerations and best practices -If you base your application on this example, it is recommended that you familiarize yourself with and adhere to the [security best practices](https://internetcomputer.org/docs/building-apps/security/overview) for developing on ICP. This example may not implement all the best practices. +Refer to the [security best practices](https://docs.internetcomputer.org/guides/security/overview) for information on security and best practices for your ICP dapp. diff --git a/motoko/send_http_post/src/send_http_post_backend/main.mo b/motoko/send_http_post/backend/app.mo similarity index 88% rename from motoko/send_http_post/src/send_http_post_backend/main.mo rename to motoko/send_http_post/backend/app.mo index e7270f5bd..fa46fdf81 100644 --- a/motoko/send_http_post/src/send_http_post_backend/main.mo +++ b/motoko/send_http_post/backend/app.mo @@ -1,8 +1,8 @@ import Blob "mo:core/Blob"; import Text "mo:core/Text"; -import IC "ic:aaaaa-aa"; +import { ic } "mo:ic"; -persistent actor { +persistent actor SendHttpPost { // #region transform // Strip HTTP response headers (date, cookies, tracking IDs) that vary across requests. @@ -11,8 +11,8 @@ persistent actor { // essential for consensus to succeed. public query func transform({ context : Blob; - response : IC.http_request_result; - }) : async IC.http_request_result { + response : ic.http_request_result; + }) : async ic.http_request_result { { response with headers = [] }; }; // #endregion transform @@ -21,7 +21,7 @@ persistent actor { public func send_http_post_request() : async Text { let body = Text.encodeUtf8("This is a POST request from an ICP canister."); - let request : IC.http_request_args = { + let request : ic.http_request_args = { url = "https://postman-echo.com/post"; // Always set max_response_bytes to a tight bound. The cycle cost scales // with this value, not the actual response size. If omitted, the system @@ -42,7 +42,7 @@ persistent actor { // Cycles must be explicitly attached to management canister calls. // The amount is based on request size and max_response_bytes. - let response = await (with cycles = 230_949_972_000) IC.http_request(request); + let response = await (with cycles = 230_949_972_000) ic.http_request(request); // postman-echo.com echoes back the request data as JSON, letting you // verify the POST body and headers were sent correctly. diff --git a/motoko/send_http_post/dfx.json b/motoko/send_http_post/dfx.json deleted file mode 100644 index 7609762a0..000000000 --- a/motoko/send_http_post/dfx.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "canisters": { - "send_http_post_backend": { - "main": "src/send_http_post_backend/main.mo", - "type": "motoko" - } - }, - "defaults": { - "build": { - "packtool": "mops sources" - } - }, - "output_env_file": ".env", - "version": 1 -} \ No newline at end of file diff --git a/motoko/send_http_post/icp.yaml b/motoko/send_http_post/icp.yaml new file mode 100644 index 000000000..fb741fade --- /dev/null +++ b/motoko/send_http_post/icp.yaml @@ -0,0 +1,4 @@ +canisters: + - name: backend + recipe: + type: "@dfinity/motoko@v5.0.0" diff --git a/motoko/send_http_post/mops.toml b/motoko/send_http_post/mops.toml index 2effb740c..7902c42eb 100644 --- a/motoko/send_http_post/mops.toml +++ b/motoko/send_http_post/mops.toml @@ -1,13 +1,15 @@ -# Motoko dependencies (https://mops.one/) - [toolchain] -moc = "1.5.1" +moc = "1.9.0" [dependencies] -core = "2.4.0" +core = "2.5.0" +ic = "4.0.0" [moc] -# M0236: use context dot notation (e.g. map.get(k) instead of Map.get(map, compare, k)) -# M0237: redundant explicit implicit arguments (e.g. Nat.compare is inferred automatically) -# M0223: redundant type instantiation (e.g. Array.tabulate instead of Array.tabulate) -args = ["-W=M0236,M0237,M0223"] +# M0236: use context dot notation +# M0237: redundant explicit implicit arguments +# M0223: redundant type instantiation +args = ["--default-persistent-actors", "-W=M0236,M0237,M0223"] + +[canisters.backend] +main = "backend/app.mo" diff --git a/motoko/send_http_post/package.json b/motoko/send_http_post/package.json deleted file mode 100644 index 93aeccd5f..000000000 --- a/motoko/send_http_post/package.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "send_http_post_frontend", - "version": "0.2.0", - "description": "Internet Computer starter application", - "keywords": [ - "Internet Computer", - "Motoko", - "JavaScript", - "Canister" - ], - "scripts": { - "build": "webpack", - "prebuild": "dfx generate", - "start": "webpack serve --mode development --env development", - "deploy:local": "dfx deploy --network=local", - "deploy:ic": "dfx deploy --network=ic", - "generate": "dfx generate send_http_post_motoko_backend" - }, - "dependencies": { - "@dfinity/agent": "^2.1.3", - "@dfinity/candid": "^2.1.3", - "@dfinity/principal": "^2.1.3" - }, - "devDependencies": { - "assert": "2.0.0", - "buffer": "6.0.3", - "copy-webpack-plugin": "^11.0.0", - "dotenv": "^16.0.3", - "events": "3.3.0", - "html-webpack-plugin": "5.5.0", - "process": "0.11.10", - "stream-browserify": "3.0.0", - "terser-webpack-plugin": "^5.3.3", - "util": "0.12.4", - "webpack": "^5.73.0", - "webpack-cli": "^4.10.0", - "webpack-dev-server": "^4.8.1" - }, - "engines": { - "node": "^12 || ^14 || ^16 || ^18" - }, - "browserslist": [ - "last 2 chrome version", - "last 2 firefox version", - "last 2 safari version", - "last 2 edge version" - ] -} diff --git a/motoko/send_http_post/webpack.config.js b/motoko/send_http_post/webpack.config.js deleted file mode 100644 index b0cbb6072..000000000 --- a/motoko/send_http_post/webpack.config.js +++ /dev/null @@ -1,96 +0,0 @@ -require("dotenv").config(); -const path = require("path"); -const webpack = require("webpack"); -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const TerserPlugin = require("terser-webpack-plugin"); -const CopyPlugin = require("copy-webpack-plugin"); - -const isDevelopment = process.env.NODE_ENV !== "production"; - -const frontendDirectory = "send_http_post_frontend"; - -const frontend_entry = path.join("src", frontendDirectory, "src", "index.html"); - -module.exports = { - target: "web", - mode: isDevelopment ? "development" : "production", - entry: { - // The frontend.entrypoint points to the HTML file for this build, so we need - // to replace the extension to `.js`. - index: path.join(__dirname, frontend_entry).replace(/\.html$/, ".js"), - }, - devtool: isDevelopment ? "source-map" : false, - optimization: { - minimize: !isDevelopment, - minimizer: [new TerserPlugin()], - }, - resolve: { - extensions: [".js", ".ts", ".jsx", ".tsx"], - fallback: { - assert: require.resolve("assert/"), - buffer: require.resolve("buffer/"), - events: require.resolve("events/"), - stream: require.resolve("stream-browserify/"), - util: require.resolve("util/"), - }, - }, - output: { - filename: "index.js", - path: path.join(__dirname, "dist", frontendDirectory), - }, - - // Depending in the language or framework you are using for - // front-end development, add module loaders to the default - // webpack configuration. For example, if you are using React - // modules and CSS as described in the "Adding a stylesheet" - // tutorial, uncomment the following lines: - // module: { - // rules: [ - // { test: /\.(ts|tsx|jsx)$/, loader: "ts-loader" }, - // { test: /\.css$/, use: ['style-loader','css-loader'] } - // ] - // }, - plugins: [ - new HtmlWebpackPlugin({ - template: path.join(__dirname, frontend_entry), - cache: false, - }), - new webpack.EnvironmentPlugin([ - ...Object.keys(process.env).filter((key) => { - if (key.includes("CANISTER")) return true; - if (key.includes("DFX")) return true; - return false; - }), - ]), - new webpack.ProvidePlugin({ - Buffer: [require.resolve("buffer/"), "Buffer"], - process: require.resolve("process/browser"), - }), - new CopyPlugin({ - patterns: [ - { - from: `src/${frontendDirectory}/src/.ic-assets.json*`, - to: ".ic-assets.json5", - noErrorOnMissing: true, - }, - ], - }), - ], - // proxy /api to port 4943 during development. - // if you edit dfx.json to define a project-specific local network, change the port to match. - devServer: { - proxy: { - "/api": { - target: "http://127.0.0.1:4943", - changeOrigin: true, - pathRewrite: { - "^/api": "/api", - }, - }, - }, - static: path.resolve(__dirname, "src", frontendDirectory, "assets"), - hot: true, - watchFiles: [path.resolve(__dirname, "src", frontendDirectory)], - liveReload: true, - }, -}; From 5c9e7dfea788491e83af87fc7af61cadfa7fe2ef Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Wed, 10 Jun 2026 18:32:14 +0200 Subject: [PATCH 2/8] fix: use IC.HttpRequestResult/HttpRequestArgs from mo:ic/Types; apply mops check --fix Co-Authored-By: Claude Sonnet 4.6 --- motoko/send_http_post/backend/app.mo | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/motoko/send_http_post/backend/app.mo b/motoko/send_http_post/backend/app.mo index fa46fdf81..5da601614 100644 --- a/motoko/send_http_post/backend/app.mo +++ b/motoko/send_http_post/backend/app.mo @@ -1,6 +1,7 @@ import Blob "mo:core/Blob"; import Text "mo:core/Text"; import { ic } "mo:ic"; +import IC "mo:ic/Types"; persistent actor SendHttpPost { @@ -11,17 +12,17 @@ persistent actor SendHttpPost { // essential for consensus to succeed. public query func transform({ context : Blob; - response : ic.http_request_result; - }) : async ic.http_request_result { + response : IC.HttpRequestResult; + }) : async IC.HttpRequestResult { { response with headers = [] }; }; // #endregion transform // #region post_request public func send_http_post_request() : async Text { - let body = Text.encodeUtf8("This is a POST request from an ICP canister."); + let body = "This is a POST request from an ICP canister.".encodeUtf8(); - let request : ic.http_request_args = { + let request : IC.HttpRequestArgs = { url = "https://postman-echo.com/post"; // Always set max_response_bytes to a tight bound. The cycle cost scales // with this value, not the actual response size. If omitted, the system @@ -46,7 +47,7 @@ persistent actor SendHttpPost { // postman-echo.com echoes back the request data as JSON, letting you // verify the POST body and headers were sent correctly. - switch (Text.decodeUtf8(response.body)) { + switch (response.body.decodeUtf8()) { case (?text) text; case null "Response is not valid UTF-8"; }; From f2d26a70dec0d08df9a681503905bff41c65ed81 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Wed, 10 Jun 2026 21:36:34 +0200 Subject: [PATCH 3/8] chore: retrigger CI Co-Authored-By: Claude Sonnet 4.6 From df65617b67ef171fad2850cc871c66429e10a473 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Wed, 10 Jun 2026 21:51:39 +0200 Subject: [PATCH 4/8] chore: remove GitHub link and Overview heading; improve tests and README Co-Authored-By: Claude Sonnet 4.6 --- motoko/send_http_post/Makefile | 2 +- motoko/send_http_post/README.md | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/motoko/send_http_post/Makefile b/motoko/send_http_post/Makefile index 45acda99f..a0e1a2993 100644 --- a/motoko/send_http_post/Makefile +++ b/motoko/send_http_post/Makefile @@ -1,7 +1,7 @@ .PHONY: test test: - @echo "=== Test 1: send_http_post_request returns POST echo ===" + @echo "=== Test 1/1: send_http_post_request returns POST echo ===" @result=$$(icp canister call backend send_http_post_request '()') && \ echo "$$result" && \ echo "$$result" | grep -q 'POST request from an ICP canister' && \ diff --git a/motoko/send_http_post/README.md b/motoko/send_http_post/README.md index cd1f3d233..62ac5e759 100644 --- a/motoko/send_http_post/README.md +++ b/motoko/send_http_post/README.md @@ -1,9 +1,5 @@ # HTTP: POST -[View this sample's code on GitHub](https://github.com/dfinity/examples/tree/master/motoko/send_http_post) - -## Overview - This example demonstrates how to use the ICP HTTPS outcalls feature to make a `POST` request from a Motoko canister. It sends a plain-text body to `postman-echo.com/post`, which echoes back the request as JSON, allowing you to verify the POST body and headers were sent correctly. ## Build and deploy from the command line From bb18151d542dce9dbe84436d692dd5dafa98355b Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Wed, 10 Jun 2026 21:55:16 +0200 Subject: [PATCH 5/8] chore: replace 'dapp' with 'app' Co-Authored-By: Claude Sonnet 4.6 --- motoko/send_http_post/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/motoko/send_http_post/README.md b/motoko/send_http_post/README.md index 62ac5e759..7641b2f38 100644 --- a/motoko/send_http_post/README.md +++ b/motoko/send_http_post/README.md @@ -24,4 +24,4 @@ icp network stop ## Security considerations and best practices -Refer to the [security best practices](https://docs.internetcomputer.org/guides/security/overview) for information on security and best practices for your ICP dapp. +Refer to the [security best practices](https://docs.internetcomputer.org/guides/security/overview) for information on security and best practices for your ICP app. From 16abae32ddaa5130c913edb444078c90d38b1271 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Thu, 11 Jun 2026 00:45:25 +0200 Subject: [PATCH 6/8] chore: bump icp-dev-env to 0.3.2 Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/send_http_post.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/send_http_post.yml b/.github/workflows/send_http_post.yml index 2e1bd55cb..8ec74874d 100644 --- a/.github/workflows/send_http_post.yml +++ b/.github/workflows/send_http_post.yml @@ -15,7 +15,7 @@ concurrency: jobs: motoko-send_http_post: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.1 + container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: From 27a4af8fa5c17a2f97a5cb161e2d5885793d9615 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Thu, 11 Jun 2026 00:50:40 +0200 Subject: [PATCH 7/8] revert: back to icp-dev-env 0.3.1 (0.3.2 not yet on ghcr.io) Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/send_http_post.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/send_http_post.yml b/.github/workflows/send_http_post.yml index 8ec74874d..2e1bd55cb 100644 --- a/.github/workflows/send_http_post.yml +++ b/.github/workflows/send_http_post.yml @@ -15,7 +15,7 @@ concurrency: jobs: motoko-send_http_post: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: From bdc11f79f9f84213d8a2c6006e146b8768072e2e Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Thu, 11 Jun 2026 01:21:09 +0200 Subject: [PATCH 8/8] chore: bump icp-dev-env to 0.3.2 (images now published) Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/send_http_post.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/send_http_post.yml b/.github/workflows/send_http_post.yml index 2e1bd55cb..8ec74874d 100644 --- a/.github/workflows/send_http_post.yml +++ b/.github/workflows/send_http_post.yml @@ -15,7 +15,7 @@ concurrency: jobs: motoko-send_http_post: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.1 + container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: