Any way to bypass Etag check in People API? - google-contacts-api

Google Contacts allows us to bypass Etag verification by passing * instead of the contact's current Etag for Edit/Delete requests.
Google Contacts API documentation
Note: The special Etag value * can be used to bypass this verification and process the update regardless of updates from other clients.
Is there any similar way to bypass the Etag verification for edit/delete in People API?
Facing the following error if the etag value is not sent in Person object during update. The value " * " is also not working in People API.
Request:
{
"emailAddresses": [
{
"displayName": "test1#gmail.com",
"value": "test1#gmail.com",
"type": "home"
}
]
}
Response:
{
"error": {
"code": 400,
"message": "Request must set person.etag or person.metadata.sources.etag for the source that is being updated.",
"status": "INVALID_ARGUMENT"
}
}

You have to send the resource name in both the delete and the update requests.
Delete request only requires resource name.
Update request requires the resource name and the person. IMO the best way to update is to fetch the Person first then update the data then push it back.
updateMask is also required if you are not using one of their APIs
https://developers.google.com/people/api/rest/v1/people/updateContact?hl=en
See https://developers.google.com/people/api/rest/v1/people/updateContact?hl=en
The server returns a 400 error with reason "failedPrecondition" if person.metadata.sources.etag is different than the contact's etag, which indicates the contact has changed since its data was read. Clients should get the latest person and merge their updates into the latest person.
In short, you maybe out of luck using just the *

Related

Create Etag string using Google apps script

I use Google people API to update a contact.
I save the resourceName of the created contact and when I update the contact, I just use this code
People.People.updateContact({"emailAddresses": [{
"type": "work",
"value": "example#gmail.com"
}]}, "people/c6679930577989153852")
But this throws error - GoogleJsonResponseException: API call to people.people.updateContact failed with error: Request must set person.etag or person.metadata.sources.etag for the source that is being updated.
How do I create an etag if I dont store the created etag at the time of contact creation?
Is there a way I can create a new etag using a function so I can force update the entire contact?
if so how do I create a updatePersonFields mask?
How to deal with the etag Contacts API error.
The server returns a 400 error with reason "failedPrecondition" if person.metadata.sources.etag is different than the contact's etag, which indicates the contact has changed since its data was read. Clients should get the latest person and merge their updates into the latest person.
Source
So you are right in thinking that you need the etag to be able to complete the operation you want.
However, generating it is not the right way to go.
You would need to first make a simple get request with any personFields to get the current etag value. Then you would use this etag value in the update.
This is to prevent you from overwriting and duplicating possibly important information.
Reference
updateContact
get

How to design RESTful services with server side logging capability of client information

I'm designing RESTful web services to expose functionalities in a SOA Architecture. Clients of the services are logged in the enterprise intranet, have a client name, ID and other technical information (not business relevant I mean).
I have a requirement which says that all calls to the RESTful services must be logged and must contain the client "not business" information (id, application name, logged user, etc.).
I want to collect all the technical information in a JSON object "technicalData" and the business data (the Data Transfer Object) for PUT/POST in another JSON object "dto".
Is it correct to put this information in the request body for GET, POST, PUT, DELETE?
This information in the GET/DELETE body does not have a semantic meaning to the request since they are used only for logging purpose see this answer on SO
Examples:
GET /books?author=AUTHOR
{
"technicalData":
{
"id": "...",
"loggedUser": "...",
"applicationName": "..."
}
}
POST /books
{
"technicalData":
{
"id": "...",
"loggedUser": "...",
"applicationName": "..."
}
"dto":
{
...
}
}
PUT /books/ID
{
"technicalData":
{
"id": "...",
"loggedUser": "...",
"applicationName": "..."
}
"dto":
{
...
}
}
DELETE /books/ID
{
"technicalData":
{
"id": "...",
"loggedUser": "...",
"applicationName": "..."
}
}
No, you shouldn't pass that information in the body of every request. You certainly shouldn't pass it up the wire in GET and DELETE calls, as that violates the spec:
sending a payload body on a GET request might cause some existing implementations to reject the request. (RFC 7231)
sending a payload body on a DELETE request might cause some existing implementations to reject the request. (RFC 7231)
Meta information like this belongs in headers. Presumably you're using an Authorization header or other means of identifying the user? That will give you the username. If not, maybe the From header would be an appropriate place to store it. Perhaps User-Agent can be used to specify the application. Alternately, look at using a JWT, which will let you embed arbitrary information.
Usually, the information called "technicalData" are not sharing between client and server by request call. You should share only a request token that identify the current session. The token will be related on the server with loggedUser and so on...

Create customer in GoCardless sandbox returns 403 forbidden

I am attempting to use the GoCardless API sandbox to create a customer but only get a 403 forbidden error
{"error": {
"message": "Forbidden request",
"errors": [ {
"reason": "forbidden",
"message": "Forbidden request"
}],
"documentation_url": "https://developer.gocardless.com/api-reference#forbidden",
"type": "invalid_api_usage",
"request_id": "8b870491-e8ca-436c-a602-bb613bba7d96",
"code": 403
}}
I have used OAuth to get a bearer token which I am using for my post to the sandbox url
https://api-sandbox.gocardless.com/customers
Using this url and the bearer token i can get customers and update a customer that i created manually via the sandbox client portal. If i purposefully make the token an invalid value i get a 401 error instead so I am sure the token is correct.
The documentation for the error type "invalid_api_usage" is as follows
This is an error with the request you made. It could be an invalid
URL, the authentication header could be missing, invalid, or grant
insufficient permissions, you may have reached your rate limit, or the
syntax of your request could be incorrect. The errors will give more
detail of the specific issue.
The fact i can update a customer i believe crosses most of those potential issues of that list.
I am now using the exact post body content of the GoCardless API example for creating customer to verify the syntax should be correct.
{
"customers": {
"email": "user#example.com",
"given_name": "Frank",
"family_name": "Osborne",
"address_line1": "27 Acer Road",
"address_line2": "Apt 2",
"city": "London",
"postal_code": "E8 3GX",
"country_code": "GB",
"metadata": {
"salesforce_id": "ABCD1234"
}
}
}
I am running these requests from SoapUI instead of my application so I can be sure I am sending exactly what i am expecting to send.
From the API documentation I understand my application must have approved payment pages to create customers in the live environment however this is prefixed by a statement that this is not restricted in the sandbox environment.
Restrictions
Whilst the entire GoCardless API is accessible in the sandbox
environment, the following restrictions exist in live.
Payment page restrictions
Unless your payment pages have been approved as scheme rules compliant
by our sponsor bank you must use the Redirect Flow API to create
customers, bank accounts and mandates.
The following endpoints are therefore restricted:
Customers: Create
Customer bank accounts: Create
Mandate: Create, Reinstate
Javascript flow: All endpoints
It seems to me the 403 forbidden response is exactly what i would be getting if Create Customer was restricted in the sandbox environment however the API documentation explicitly states that this is not the case.
My question is basically what could I be doing wrong? Maybe somebody can spot something I have forgotten or am misunderstanding.
The answer is that the sandbox is restricted in the same way as the live environment.
The API documentation appears to be worded in a way that suggest the sandbox is unrestricted however this is not the case.
To remove the restriction in the sandbox environment you need to contact GoCardless support and request it.

Restful API - JSON response with single or all error(s)

My current project, a restful API, validates a POST request to create a new user and multiple errors could occur (with HTTP status):
username not set (400 BadRequest)
username is taken (409 Conflict)
server can't establish db connection (500 Internal Server Error)
...
Should I immediatly send back a JSON response like this
{
"status": 400,
"Message": "No username is set"
}
if an error was detected or should is it better if I accumulate all errors like here:
{
"status": <HTTP STATUS CODE>,
"errors": [
{"message": "Username is not set."},
{"message": "Can't access the database."}
]
}
The last approach would not require multiple request to send a valid payload. But which status code should be used, if the username is not set (400 Bad Request) or the server can't access the database (500 Internal Server Error)?
I think if you foresee the need for multiple errors in one request, then the second JSON (with the multiple errors) is preferred. Another benefit of doing the multiple errors response is that as a user of your service, if i get back multiple errors, I can address them all at one shot, instead of addressing them one at a time as I get them.
After some research, the best (most standard) way to respond is a JSON structure of this form:
{
"error": {
"code": "400",
"message": "main error message here",
"target": "approx what the error came from",
"details": [
{
"code": "23-098a",
"message": "Disk drive has frozen up again. It needs to be replaced",
"target": "not sure what the target is"
}
],
"innererror": {
"trace": [ ... ],
"context": [ ... ]
}
}
}
The multiple errors you want to place would be individual elements in the "details" array. Using this structure you would still need some overall summary of the error, however the details would contain as many individual error messages as you want.
This is the format proposed by the OASIS data standard OASIS OData and seems to be the most standard option out there, however there does not seem to be high adoption rates of any standard at this point.
This also conforms to the JSON RPC 2.0 Spec as it requires that the error be an object in a "error" member, and that you have a code and message.
You can find the complete open source library that implements this at: Mendocino JSON Utilities. This library supports the JSON Objects as well as the exceptions.
The details are discussed in my blog post on Error Handling in JSON REST API

400 error returned when using Box2.0 Delete method

I am using Box 2.0 API to delete a file. Using Postman, i enter the following:
https://api.box.com/2.0/files/2605672883
specifying the DELETE action. I've set the authorization header appropriately. When I submit the request, I get the following error:
{
"type": "error",
"status": 400,
"code": "bad_request",
"help_url": "http://developers.box.com/docs/#errors",
"message": "Could not parse JSON",
"request_id": "4934716064fff2a0a70988"
}
This makes me think that i need a JSON object as part of the message body, the documentation specifies that the File ID is the only thing necessary as part of the request. Is this a bug or am I doing something wrong ?
thanks
DELETE /files/{id} requests require (as of last week) an If-Match header with the sha1 of the file in order to prevent race conditions. You can see the updated documentation here: http://developers.box.com/docs/#files-delete-a-file
EDIT: There is a bug in POSTMAN in how it sends DELETE requests. If you send an empty JSON object {} as the body, it should work successfully.