A platform returns a POST method to an url and I want to retrieve the data to firestore - google-cloud-firestore

I want to retrieve the data from a third party platform that generates a POST call to an url that I can define. But I can only configure the url. I cannot configure the headers or the body of the POST action.
I want to store the JSON into a firestore collection.
The platform calls a POST action to a URL y can define, and that POST action has a JSON with the parameters I want to store.
In another post they directed me to the firestore API
https://stackoverflow.com/a/50061155/18276916
But there it is stated that the body of the POST action must have the following structure:
{
"writes": [
{
object (Write)
}
],
"labels": {
string: string,
...
}
}
The body of the POST action is defined in the third party aplication, and I cant modify it.
Is it posible to do this with Firestore, or is there another method I can use?
What would be the path of the url?:
https://firestore.googleapis.com/v1/projects/[my-project-id]/databases/(default)/documents/[my-collection-name]
Also, can I set the firestore rules to allow everyone to perform create actions so the call doesn't need to be authenticated
I found a solution that works
https://www.jeansnyman.com/posts/google-firestore-rest-api-examples/
With the following structure:
Url: https://firestore.googleapis.com/v1/projects//databases/(default)/documents/
Body:
{
fields: {
title: { stringValue: title },
category: { stringValue: category }
}
}
But here the body has its defined structure. I would need the url to accept:
{
title: title,
category: category
}

Related

REST API - Endpoint syntax - get item by property - not by id

I'm implementing my first REST API, and I have a question about the syntax of the URL endpoints.
I know that I should use these endpoint for get, create, update and delete:
Get list of items
Method: GET, Url: /api/items
Get item by id
Method: GET, Url: /api/items/:id
Add item (new item data in the request body)
Method: POST, Url: /api/items
Modify item (modified item data in the request body)
Method: PUT, Url: /api/items/:id
Delete item
Method: DELETE, Url: /api/items/:id
But lets say the interface of item is
interface item
{
id: string;
name: string;
}
What should be the request url for getting an item by it's name?
I can't use Method: GET, Url: /api/items/:name, because this will match the get-by-id request. So how should I syntax this endpoint?
There is no standard REST URI syntax unless you are doing OData for example. You have perfect freedom designing your own URIs, even /resource/{id} is perfectly valid.
What I like to do is end the URIs of collections with / and use queries for filtering collections. So I would do /api/{version}/items/?name={name} if they have unique names and you expect an item instead of a collection, then I would do it this way: /api/{version}/items/name:{name}. But this is my style.
From client perspective the URI syntax is totally irrelevant, because the server gives the valid URI templates to the client according to the HATEOES constraint. If you thought otherwise, then probably you are building a CRUD API instead of a REST API.
You chould use a filter on the collections endpoint like:
Method: GET, Url: /api/items?name=foo
This filter could return all items which have a foo string in them (depending on how you want to handle wildcards in the search / filter term), e.g. the response could be a collection of items:
{
"data": [
{
"id": "d079d8e9-4d24-4514-b356-78587f6c2ba9",
"name": "foo"
},
{
"id": "7f5e558c-6a7f-4ebe-8f4f-a2d029a803ed",
"name": "foo bar"
}
]
}
If you want the response to return a single resource you could also use the name as identifier and apply the scheme from above using the name, e.g.
Method: GET, Url: /api/items/:name

REST API Multiple PUT or DELETE in one time

Greeting everyone, I have a datatable in my html page that I populated using REST API. I can create new row and also update or delete by selecting a row and clicking the edit or delete button.
But currently I am unable to delete update or delete multiple row at once due to url error,
e.g : PUT http://127.0.0.1:8000/dashboard/content_detail/5,7,9/ 404 (Not Found)
how can I split this this into several separate url with respective id when I update or delete.
e.g :
/dashboard/content_detail/5
/dashboard/content_detail/7
/dashboard/content_detail/9
Below is my code, any help is much appreciated thank you.
idSrc: 'id',
ajax: {
create: {
type: 'POST',
url: content_path,
data: function (content_data) {
var create_data = {};
$.each(content_data.data, function (id, value) {
create_data['name'] = value['name'];
create_data['description'] = value['description'];
create_data['category'] = value['category'];
});
return create_data;
},
success: function () {
content_table.api().ajax.reload();
}
},
edit: {
type: 'PUT',
url: '/dashboard/content_detail/_id_/',
data: function (content_data) {
var updated_data = {};
$.each(content_data.data, function (id, value) {
updated_data['description'] = value['description'];
updated_data['category'] = value['category'];
updated_data['name'] = value['name'];
});
return updated_data;
},
success: function () {
content_table.api().ajax.reload();
}
},
remove: {
type: 'DELETE',
url: '/dashboard/content_detail/_id_/',
data: function (content_data) {
var deleted_data = {};
$.each(content_data.data, function (id, value) {
deleted_data['id'] = id;
});
return deleted_data;
},
success: function () {
content_table.api().ajax.reload();
}
}
},
If you're going to allow the update of a large number of items at once, then PATCH might be your friend:
Looking at the RFC 6902 (which defines the Patch standard), from the client's perspective the API could be called like
PATCH /authors/{authorId}/book
[
{ "op": "replace", "path": "/dashboard/content_detail/5", "value": "test"},
{ "op": "remove", "path": "/dashboard/content_detail", "value": [ "7", "9" ]}
]
From a design perspective you don't want several ids in your url.
I would prefer single calls for each change, thinking in resources you only manipulate one at a time.
In case this is a perfomance issue, I recommend a special url marked with action or something simliar, to make clear this ist not REST.
In HTTP it is not required for information to only exist on a single resource. It is possible to have multiple resources that represent the same underlying data.
It's therefore not out of the question to create a resource that 'represents' a set of other resources that you wish to DELETE or PUT to.
I do agree that it might not be the most desirable. I think we tend to prefer having information only exist in a single part of tree, and I think we like to avoid situations where updating a resource effects a secondary resource's state. However, if you are looking for a strictly RESTful solution to solve this problem, I think it's the right way.
Therefore a url design such as:
/dashboard/content_detail/5,7,9/
Is not necessarily non-RESTful or goes against the HTTP protocol. The fact that you're getting a 404 on that URL currently has to do with your application framework, not the protocol (HTTP) or architecture (REST) of your API.
However, for cases such as these I feel I would personally be inclined to sometimes create a separate POST endpoint that, acting outside of REST like an RPC endpoint. Specifically for these types of batch requests.

Rest API get resource id by field

What is a correct rest way of getting a resource ID by a field, for example a name. Take a look at the following operations:
GET /users/mike-thomas
GET /users/rick-astley
I don't want to use these operations at my API end, instead I want to write an API operation that will get me the ID when submitting a field (name in the case of users) for example:
GET /users/id-by-field
Submitted data:
{
"fullName": "Mike Thomas"
}
Return data:
{
"data": {
"id": "123456789012345678901234"
}
}
What you want is known as an algorithmic URL where the parameters for the algorithm are passed as URL parameters:
GET /users?name="Mike Thomas"
Advantages are that you are using the "root" resource (users) and the search parameters are easily extended without having to change anything in the routing. For example:
GET /users?text="Mike"&year=1962&gender=M
where text would be searched for in more than just the name.
The resultant data would be a list of users and could return more than the identification of those users. Unless fullName uniquely identifies users, that is what you need to allow for anyway. And of course the list could contain a single user if the parameters uniquely identified that user.
{
users: [
{
id: "123456789012345678901234",
fullName: "Mike Thomas",
dateJoined: 19620228
}
, {
id: "234567890123456789012345"
fullName: "Rick Astley",
dateJoined: 19620227
}
]
}

Using HATEOAS and Backbone.js

I've started experimenting with Backbone.js, and was struck by the documentation for the documentation for the url property on Backbone.Model.
In particular, I'm building out a REST API that uses HATEOAS/hypermedia to drive the client(s).
I can see the usefulness of Backbone's default behaviour of building up URLs itself for items in a collection, but for my case, would prefer to have the model URLs built out of the data that is parsed.
Has anyone extended/built on Backbone to make it do this? Maybe building upon a "standard" like HAL?
EDIT:
For clarification, let's say I have the following:
GET /orders >>
[
{
"_links": {
"self": "/orders/123"
}
"name": "Order #123",
"date": "2012/02/23"
},
{
"_links": {
"self": "/orders/6666"
}
"name": "Order #666",
"date": "2012/03/01"
},
]
and I have an Order model like:
var Order = Backbone.Model.extend({
});
I would like the url property to be automatically pulled out of the "self" reference in the HAL. I think creating a new base model something like (not tested):
var HalModel = Backbone.Model.extend({
url: function() {
return get("_links").self;
},
});
Thoughts?
I've extended backbone to do exactly this, the library is available here:
https://github.com/mikekelly/backbone.hal
Thanks for the clarification #Pete.
I think I see what your proposing and I suppose it could work. However, in your example, you first had to know the /Orders url before you were able to get the orders. And if you reworked your json to have an id property, you'd be pretty close to the default implementation of backbone.
Now if you just want to use a generic model or base model (e.g. HALModel) and just bootstrap it with data, your approach could be useful and definitely could work. However, I would look at overriding parse to pull the url out and set it on the model:
parse: function(response) {
this.url = response._links.self;
delete response._links;
return response;
}
I complement here the response of Simon to explain how to easily do it using gomoob/backbone.hateoas.
// Instanciation of an Hal.Model object is done the same way as you're
// used to with a standard Backbone model
var user = new Hal.Model({
firstName: "John",
lastName: "Doe",
_links: {
avatar: {
href: "http://localhost/api/users/1/avatar.png"
},
self: {
href: "http://localhost/api/users/1"
}
},
_embedded: {
address: {
"city" : "Paris",
"country" : "France",
"street" : "142 Rue de Rivoli",
"zip" : "75001",
"_links" : {
"self" : {
"href" : "http://localhost/api/addresses/1"
}
}
}
}
});
// Now we you can easily get links, those lines are equivalent
var link1 = user.getLink('avatar');
var link2 = user.getLinks().get('avatar');
// So getting self link is simple too
var self = user.getLink('self');
// All the Hal.Link objects returned by backbone.hateoas are in fact
// standard Backbone models so its standard Backbone
link1.get('href');
link1.getHref();
// You can do more with shortcut methods if your HAL links
// have more properties
link1.get('deprecation');
link1.getDeprecation();
link1.get('name');
link1.getName();
link1.get('hreflang');
link1.getHreflang();
link1.get('profile');
link1.getProfile();
link1.get('title');
link1.getTitle();
link1.get('type');
link1.getType();
linke1.get('templated');
link1.isTemplated();
// You can also manipulate embedded resources if you need
user.getEmbedded('address').get('city');
user.getEmbedded('address').getLink('self');
...
Finally we provide an Hal.Model.url() implementation which is more powerful than standard Backbone url() and which is very useful if you use HAL.
// By default url() returns the href of the self link if this self
// link is present
user.url();
// If the self link is not defined then url() has the same behavior
// as standard Backbone url() method
// My user is link to a user collection having a URL equal to
// 'http://localhost/user1'
user.url(); // http://localhost/users/1
// My user is not link to a user collection in this case the URL is
// generate using the model urlRoot property by default
user.urlRoot = 'http://myserver/users';
user.url(); // http://localhost/users/1
// backbone.hateoas also allows you to define an application wide root
// URL which prevent to use absolute URLs everywhere in your code
Hal.urlRoot = 'http://localhost/api'; // HAL root API URL
var user = new Hal.Model({ id : 1});
user.urlMiddle = 'users';
user.url(); // http://localhost/api/users/1
Hope this helps, don't hesitate to post issues on our github if you need help on this.
You can override the url function on the model to calculate the URL however you want; it's completely extensible.

In WCF Data Services, can I enclose a list of references to another entity while creating a new object?

I have a table Article, a table Tag and a joint table to associate a tag to an article.
While creating a new Article, by sending a POST request to /Service.svc/Articles, is it possible to enclose in the JSON object a list of Tag ids to be associated?
Something like:
{
title: "My article title",
text: "The content:",
Tags: [ { id: 1 }, { id: 2 }, { id: 3 } ]
}
If not can I send the list of tags in one request? For example:
/Service.svc/Articles(1)/Tags
[ { id: 1 }, { id: 2 }, { id: 3 } ]
Or do I have to make as many requests as they are tags?
Thank you very much in advance.
You can modify just the links by POST/PUT/DELETE to the $links URL as described here: http://www.odata.org/developers/protocols/operations#CreatingLinksbetweenEntries
The samples there use ATOM/XML, but the respective JSON format is also possible.
To send multiple operations to the server in one request (to save the roundtrips) you can create a batch request as described here:
http://www.odata.org/developers/protocols/batch