(Help)Motoko Syntax for http_request serving Jpeg Image

Hello, I want to serve dynamic images via http request, but I think I am not getting right syntax for http_response and there is no motoko example also for serving assets.

if(path == "/image.png") {
            return {
                body = imageBlob;
                headers = [("Content-Type", "image/jpeg")];
                status_code = 200;
            };
        };


getting this as response. Although when i change header to = or text/html, I am getting right imageBlob as response.
Please provide some motoko example for this or help me with syntax.

1 Like

Shouldn’t the content type be image/png?

There is an example here, but not for images per se:

1 Like

Actually thats just path, I used as example, ImageBlob is jpeg in real.

1 Like
public query func http_request(req: HttpRequest): async (HttpResponse) {
        let path = removeQuery(req.url);
        var temp : Blob = Text.encodeUtf8("");
        var imageBlob : Blob = Option.get(Trie.find(containerFile, keyT("/image"), Text.equal), temp);
        if(path == "/image") {
            return {
                body = imageBlob;
                headers = [("Content-Type", "image/jpeg")];
                status_code = 200;
            };
        };
        return {
            body = Text.encodeUtf8("404 Not found :");
            headers = [];
            status_code = 404;
        };
    };

this above sample code is delivering above white picture with black bg, however if i change Header to Text html, its delivering correct Image Blob. I dont know what is wrong. Must be some syntax error or else.

I compared the header of the url you provided with those of Papyrs but did not notice any difference beside accept-ranges: bytes which I set because I stream the response but it is not your case, so not sure where the issue is.

As an experiment, if you return the blob without http_request - from a query endpoint - and then save the outcome, it’s a valid image? i.e. 100% that the image is encoded correctly in the canister?

Otherwise, your project is open source or do you have a sample repo?

I also opened your url in my browser (:wink:) but like I said above, beside the particular header did not notice any difference.

Indeed chrome preview the image as broken when I try https://c6hao-fyaaa-aaaak-aatpq-cai.raw.ic0.app/civol. Cannot tell more from my side without a sample repo I have to say, sorry

1 Like

Thanks for helping. I dropped plan of using content type image/jpeg. There is surely some problem with content type image/jpeg. So I used html to serve image.

There is no issue with content type image/jpeg on the IC. e.g. my profile picture on my blog is a jpeg.

Hey, thanks for clearing this up. I might be missing something. Can you please some sample code or example from your repo, or your repo if its open source?

Sure, this my custom assets canister: ic/canisters/src/storage at main · papyrs/ic · GitHub

Another repo in Motoko for custom assets canister which I find really interesting is the one of Aviate-labs: GitHub - aviate-labs/asset-storage.mo: Interface of the Asset Storage Canister

Note: both above example stream the response (to support assets > 1.x mb), which you don’t. Don’t think it is linked to your issue but just fyi

2 Likes

Out of curiosity: How does the canister know how to make sense of request.url (resolve a URL) when HttpRequest is a custom type? I’ve looked at a couple of examples and tried to implement a very simplified http_request method that works in Candid but gives me Failed to fetch response: Error: Not a record type when I call the url https://<CANISTER_ID>/ic0.app/funfun:

    type HttpRequest = {
        method: Text;
        url: Text;
        headers: [(Text, Text)];
        // body: Blob;
    };

    type HttpResponse = {
        statusCode: Nat;
        headers: [(Text, Text)]; // i.e. [("content-type", "image/png")]
        body: Blob; // This will be type Blob for an image
    };

    public query func http_request(request: HttpRequest) : async ?HttpResponse {
        switch (request.method, request.url) {
            case ("GET", "/funfun") {
                let response : HttpResponse = {
                    statusCode = 200;
                    headers = [("content-type", "text/plain")];
                    body = Text.encodeUtf8("lorem ipsum dolor sit amet");
                };
                return ?response;
            };
            case _ {
                let response : HttpResponse = {
                    statusCode = 400;
                    headers = [];
                    body = "";
                };
                return ?response;
            };
        };
    };

Judging by the examples, shouldn’t this work as well?

I.e. I’m thinking: If request.url is just a parameter of type Text passed to a query function, how does the canister know it’s supposed to resolve to https://<CANISTER_ID>.ic0.app/PARAMETER_OF_QUERY_FUNCTION?

Hey, What format you use to store your images ? (Just conforming), I am converting jpeg to base64 using online tool, then encoding it to Blob for Http request. Did you done same in above Blog ? I can see that you store them as [Nat8], what tool do you use for conversion of jpeg?

You can probably use [Nat8] or Blob.

I do not use any tool to convert the images. Just JavaScript conversion, transforming the images / Blob to chunks and then each chunk to array

e.g. ic/storage.api.ts at 85aa48f59b4af6cf8ff52e01f147542412090bb7 · papyrs/ic · GitHub