Google Storage Json Api - access "folders" from api fails? - google-cloud-storage

I am having problems accessing objects that use slashes through the api. For example I have objects with the names "folder1/folder2/name". When I use this with the api I get a 400 bad request. Is this not supported yet by the Api? or is a special character needed? This also fails for me on the API explorer.

This is a URL encoding issue. The object name is a single URL path part, and thus all slashes in the name need to be %-encoded. (i.e., folder1%2ffolder2%2fname)
API explorer, unfortunately, has a known issue (reported internally) with storage.objects.get. The method returns actual file data, and the API explorer is expecting JSON metadata and things go poorly from there.

Related

Data Factory v2 - connecting using REST

The aim is to connect to a public REST api using ADF. It's my first stab at sending requests to a REST api in ADF. It is the Companies House ('CH') governement website's API in England.
I have created an account and obtained a key. Apparently, it is basic authentication and the user name is the API key and password will be ignored (CH note on authentication)
I want to explore the contents of the 'Search all' API (CH note on Search All) and want to copy the results to Blob Storage.
I therefore set the linked service to use REST as below, the obfuscated User Name is the key I obtained from CH, the password is jsut the key repeated as their documentation states they ignore the password:
[
I then have added a REST dataset referencing this linked service:
And the testing of the connection works fine.
Problems then arise in the copy data task, I am getting an error when previewing and also when I attempt a copy to blob of 'Invalid Authorization Header':
I'd be grateful for pointers on where I'm going wrong.
I can't reproduce your Auth error but i notice that you want to add some parameters with your GET request in the Request Body.
I think you need to add parameters in relativeUrl property:
A relative URL to the resource that contains the data. When this
property isn't specified, only the URL that's specified in the linked
service definition is used. The HTTP connector copies data from the
combined URL: [URL specified in linked service]/[relative URL
specified in dataset].
Also i suggest you checking the correct REST API format of Search Api you are using.There is no other special features in the ADF REST connector. Just make sure the GET request works locally and duplicate it.

Google Cloud Bucket custom metadata set but not returned in the HTTP request

I've managed to add custom metadata to my public file stored in Google Cloud Bucket, but that custom header is not returned in the HTTP response.
The image below shows that my custom metadata (X-Content-Type-Options) was added to my object. When I request that file from my browser, this custom header is not part of the response.
It is possible to add custom headers, but they will be prefixed with x-goog-meta-. AWS S3 suffers from the same limitation. It seems that this is due to security reasons. The leanest solution I've found to overcome this limitation is to use an edge such as AWS Lambda Edge or Cloudflare Edge Workers. The idea is to rewrite the headers on the fly. In my case, that would mean catching all headers that start with x-goog-meta-, and removing that prefix.
Here is an article of somebody who did that with AWS Lambda Edge: https://medium.com/#tom.cook/edge-lambda-cloudfront-custom-headers-3d134a2c18a2
You can use the x-goog-meta- for setting the metadata to the object (some examples here for adding a single metadata or for adding it in a cp operation).
You can get the custom metadata with the gsutil command and the -L param. You can also recover the custom metadata with the HTTP request API (try it out here).
But the custom metadata aren't provided in your browser when you access to the object via the URL https://storage.cloud.google.com/.... You have to build a proxy which requests the object with Storage API (for getting the content and the custom metadata) and which provides the object with the expected metadata.

How can I make a Google Cloud Storage object publicly visible while uploading it?

I have an application which is uploading objects to Google Cloud Storage using signed URLs and I'd like to know if it's possible to make the object public during the sign/upload step.
I know it's possible to make the object publicly visible by setting the policy on its bucket or by using the client library/making a REST request after it's been uploaded, but in order to minimize the impact on my workflow, I'd like to do it all in one go. Is this possible? If it can be done, I'm assuming it's by setting a header when signing the URL or when making the REST request using the signed URL but I haven't been able to find documentation which covers this.
UPDATE:
I've just found the Extension/Custom Headers section of the XML API docs which claims that this can be achieved using the x-goog-acl header (e.g. x-goog-acl: public-read). Unfortunately, this does not work. The object is not publicly visible after setting the header when signing the URL and when uploading the file.
Quoting the Cloud Storage documenation regarding Signed URLs:
When specifying the name:value pairs for headers, keep in mind the following:
Remove any whitespace around the colon that appears after the header name.
For example, using the custom header x-goog-acl: private without removing the space after the colon returns a 403 Forbidden error, because the request signature you calculate does not match the signature Google calculates.
So the solution could be setting the header value as x-goog-acl:public-read instead of x-goog-acl: public-read.

What's the correct uri for QBO v3 API update operation?

I'm trying to use the QBO v3 API object update function described here. The API explorer shows a different uri.
I'm trying to update an account with Id 42. Both of the following URIs get me a 401:
As the documentation would suggest:
https://quickbooks.api.intuit.com/v3/company/0123456789/account?requestid=42
(the above at least gives me a json blob with the 401)
As the api explorer would suggest:
https://qb.sbfinance.intuit.com/v3/company/0123456789/account?operation=update
(here I don't even get the json, just a plain 401)
My request body is successful when I use the api explorer, so I don't believe that's the problem. I also don't believe authentication is the problem, because I can successfully create objects and also make queries with the same headers.
What might I be missing?
Don't put the Account object's ID into the URL. The [?requestid=] from the documentation you mentioned apparently refers to an id related to the request (not the object in question). The API Explorer's URI appears to simply mislead (although I could certainly be missing something here).
In your example, just use this:
https://quickbooks.api.intuit.com/v3/company/0123456789/account
Let the headers and request body do the rest.
Correct BASE URI: https://quickbooks.api.intuit.com/v3/company/
you can refer example request/response section of any entity doc.
Ref -https://developer.intuit.com/docs/0025_quickbooksapi/0050_data_services/030_entity_services_reference/bill
To debug(401 authentication issue), you can use any standard RestClient.
In the following thread, I've explained how to use RestClinet plugin of Mozilla to test any QBO V3 endpoint.
InvalidTokenException: Unauthorized-401
You can download IPP's devkit and using that devkit you can call any endpoints easily.
https://developer.intuit.com/docs/0025_quickbooksapi/0055_devkits
Hope it will be useful.
Thanks

How do you implement resource "edit" forms in a RESTful way?

We are trying to implement a REST API for an application we have now. We want to expose read/write capabilities for various resources using the REST API. How do we implement the "form" part of this? I get how to expose "read" of our data by creating RESTful URLs that essentially function as method calls and return the data:
GET /restapi/myobject?param=object-id-maybe
...and an XML document representing some data structure is returned. Fine.
But, normally, in a web application, an "edit" would involve two requests: one to load the current version of the resources and populate the form with that data, and one to post the modified data back.
But I don't get how you would do the same thing with HTTP methods that REST is sort of mapped to. It's a PUT, right? Can someone explain this?
(Additional consideration: The UI would be primarily done with AJAX)
--
Update: That definitely helps. But, I am still a bit confused about the server side? Obviously, I am not simply dealing with files here. On the server, the code that answers the requests should be filtering the request method to determine what to do with it? Is that the "switch" between reads and writes?
There are many different alternatives you can use. A good solution is provided at the microformats wiki and has also been referenced by the RESTful JSON crew. As close as you can get to a standard, really.
Operate on a Record
GET /people/1
return the first record
DELETE /people/1
destroy the first record
POST /people/1?_method=DELETE
alias for DELETE, to compensate for browser limitations
GET /people/1/edit
return a form to edit the first record
PUT /people/1
submit fields for updating the first record
POST /people/1?_method=PUT
alias for PUT, to compensate for browser limitations
I think you need to separate data services from web UI. When providing data services, a RESTful system is entirely appropriate, including the use of verbs that browsers can't support (like PUT and DELETE).
When describing a UI, I think most people confuse "RESTful" with "nice, predictable URLs". I wouldn't be all that worried about a purely RESTful URL syntax when you're describing web UI.
If you're submitting the data via plain HTML, you're restricted to doing a POST based form. The URI that the POST request is sent to should not be the URI for the resource being modified. You should either POST to a collection resource that ADDs a newly created resource each time (with the URI for the new resource in the Location header and a 202 status code) or POST to an updater resource that updates a resource with a supplied URI in the request's content (or custom header).
If you're using an XmlHttpRequest object, you can set the method to PUT and submit the data to the resource's URI. This can also work with empty forms if the server supplies a valid URI for the yet-nonexistent resource. The first PUT would create the resource (returning 202). Subsequent PUTs will either do nothing if it's the same data or modify the existing resource (in either case a 200 is returned unless an error occurs).
The load should just be a normal GET request, and the saving of new data should be a POST to the URL which currently has the data...
For example, load the current data from http://www.example.com/record/matt-s-example and then, change the data, and POST back to the same URL with the new data.
A PUT request could be used when creating a new record (i.e. PUT the data at a URL which doesn't currently exist), but in practice just POSTing is probably a better approach to get started with.