Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic constructor failing !isBasic assertion #5

Open
tbusot opened this issue Jun 12, 2023 · 8 comments
Open

Basic constructor failing !isBasic assertion #5

tbusot opened this issue Jun 12, 2023 · 8 comments

Comments

@tbusot
Copy link

tbusot commented Jun 12, 2023

I'm using the API from a flutter app (iOS and Android). Based on the docs, being a client-app, I instantiate Cloudflare using the basic constructor:

Future<void> savePhoto(File img) async {
  final cloudflare = Cloudflare.basic();
   await cloudflare.init();
      final response = await cloudflare.imageAPI.createDirectUpload();
      final dataUploadDraft = response.body;
      try {
        await cloudflare.imageAPI.directUpload(
            dataUploadDraft: dataUploadDraft!,
            contentFromFile: DataTransmit<File>(
                data: img,
                progressCallback: (count, total) {
                  print(
                      'Image upload to direct upload URL from file: $count/$total');
                }));
      } catch (e) {
        print(e);
      }}

On execution, I receive the following:

package: 'cloudflare/src/apiservice/image_api.dart': Failed assertion: line 429 pos 12: '!isBasic': Thsi endpoing requires an authorized request, check the Cloudflare constructure you are using and make sure you are using a valid 'accountId' and 'token'.

When I switch the non-basic constructor, it works perfectly:

       final cloudflare = Cloudflare(
         accountId: "my_account_id",
         token: "my_token",
       );

I'm using cloudflare: ^3.1.0+16

@luis901101
Copy link
Owner

Yep that's correct you can't use createDirectUpload if the Cloudflare instance is basic, as this function requires Cloudflare's credentials. If you go to image_api.dart line 429 as the logs indicates, you will see it.
This package can be used from server side or client side apps, depending on which app you are developing is the Cloudflare instance and functions you should use. So client side apps should not do signed requests as it's not secure to store Cloudflare's credentials like token, apiKey/accountEmail or userServiceKey, instead it should only do unsigned requests like the directUploads, the thing is you will need to do the createDirectUpload from server side, so your backend should do this part not your app.

Here some important notes from package readme:

@tbusot
Copy link
Author

tbusot commented Jun 12, 2023

Taken from your documentation:
/// Direct uploads allow users to upload images without API keys. A common /// place to use direct uploads is on web apps, client side applications, or /// on mobile devices where users upload content directly to Cloudflare /// Images. Method creates a draft record for a future image and returns /// upload URL and image identifier that can be used later to verify if image /// itself has been uploaded or not with the draft: true property in the /// image response.

This would indicate that the createDirectUpload is, in fact, for unsigned access, wouldn't it?

So if I'm needing to upload a photo from a flutter iOS app, which endpoint should I use in the since directUpload requires a DataUploadDraft in the body, which, I presume is only available by calling createDirectUpload.

@tbusot
Copy link
Author

tbusot commented Jun 12, 2023

Trying this with Cloudflare.basic():

await cloudflare.init();
      final DataUploadDraft dataUploadDraft = const DataUploadDraft(
        id: "abscasdf",
        uploadURL:
            "https://api.cloudflare.com/client/v4/accounts/xxx/images/v1",
      );
      await cloudflare.imageAPI.directUpload(
          dataUploadDraft: dataUploadDraft,
          contentFromFile: DataTransmit<File>(
              data: img,
              progressCallback: (count, total) {
                print(
                    'Image upload to direct upload URL from file: $count/$total');
              }));

Uploads bytes, but throws a DioException status 400 at the end.

(I replaced my client id with XXX above. Using valid url). Leaving out the uploadURL from the DataUploadDraft constructor throw an error.

@luis901101
Copy link
Owner

Taken from your documentation: /// Direct uploads allow users to upload images without API keys. A common /// place to use direct uploads is on web apps, client side applications, or /// on mobile devices where users upload content directly to Cloudflare /// Images. Method creates a draft record for a future image and returns /// upload URL and image identifier that can be used later to verify if image /// itself has been uploaded or not with the draft: true property in the /// image response.

This would indicate that the createDirectUpload is, in fact, for unsigned access, wouldn't it?

So if I'm needing to upload a photo from a flutter iOS app, which endpoint should I use in the since directUpload requires a DataUploadDraft in the body, which, I presume is only available by calling createDirectUpload.

I agree it could be a bit confusing but that is the official documentation for createDirectUpload endpoint on Cloudflare's API, you can check it here: https://developers.cloudflare.com/api/operations/cloudflare-images-create-authenticated-direct-upload-url-v-2. (the function doc also points to the cloudflare's official api url, but Cloudflare migrated to a new API docs and url now don't match, I have to take a time and update it, but the documentation and functioning is the same.)

My recommendation is for you to check cloudflare's official docs for the whole Cloudflare Images API so you can have the whole idea of functioning because some other things could be confusing as well.


In my first comment I already mentioned what you need to do:

the thing is you will need to do the createDirectUpload from server side, so your backend should do this part not your app.

@luis901101
Copy link
Owner

Trying this with Cloudflare.basic():

await cloudflare.init();
      final DataUploadDraft dataUploadDraft = const DataUploadDraft(
        id: "abscasdf",
        uploadURL:
            "https://api.cloudflare.com/client/v4/accounts/xxx/images/v1",
      );
      await cloudflare.imageAPI.directUpload(
          dataUploadDraft: dataUploadDraft,
          contentFromFile: DataTransmit<File>(
              data: img,
              progressCallback: (count, total) {
                print(
                    'Image upload to direct upload URL from file: $count/$total');
              }));

Uploads bytes, but throws a DioException status 400 at the end.

(I replaced my client id with XXX above. Using valid url). Leaving out the uploadURL from the DataUploadDraft constructor throw an error.

According to the 400 error code it is a bad request, the url you are using seems not right.
This is how it looks an upload url from a DataUploadDraft: https://upload.imagedelivery.net/Cu24r3g8NxCd9Xb8sEY3yA/ZZZZZZZZ where ZZZZ is the image ID that will be uploaded.

I recommend you to check the Cloudflare's official documentation so you can understand how it works... otherwise you will be struggling with a test/error approach

Check here Developers portal and here Cloudflare Image API.

Also you could use the package sample code and integration tests to check how it work and what would be the expected results for each api endpoint.

Check here this a test I just run to check image direct upload.

Screenshot 2023-06-12 at 17 35 27

@tbusot
Copy link
Author

tbusot commented Jun 13, 2023

Oh jeez - My apologies - I didn't realize that the two steps were discrete where the DataUploadDraft was initiated from the server and then the directUpload was from the client.
The documentation on Cloudflare's side is a bit weak in that regard. Would you be open to some help with the docs on your side in a PR?

@luis901101
Copy link
Owner

Yep Cloudflare's documentation is not too clear and sometimes there are implicit contents that requires a previous reading to properly understand it. Anyway this package is a Dart Wrapper for the official Cloudflare's apis, that's why I decided to document the entire project using the official Cloudflare's documentation, so if anything is not clear the developer can go deeper checking the Cloudflare's documentation.
PR are always welcome, but keep in mine I don't have intention on documenting apis different than Cloudflare's even if Cloudflare's are not clear enough.
What I mentioned above in my second comment about updating the function doc was specifically to the official url it points to as Cloudfare's changed the API documentation urls, but the rest should be more less the same

@tbusot
Copy link
Author

tbusot commented Jun 13, 2023

Understood - I think the readme is where I'd like to add some color. You obviously know the APIs backward and front. I am new to both your package and to the Cloudflare Image/Stream APIs so I don't have the luxury of deep dives while also building my product. I could offer a fresh-eyed perspective.
Anyway, I really appreciate your responsiveness and answers here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants