New tags using POST in /tags asana API endpoint does'nt create the new tag - asana

we constructed the new tag JSON like
data:{
name:"busy Tag"
notes:"This is new tag to b created in API"
workspace:"xyz456987"
}
on post http request to /tags api we get the response
data = {
color = "<null>";
"created_at" = "2014-07-19T12:59:13.162Z";
followers = (
);
id = 14895043902988;
name = "busy tag";
notes = "This is new tag to b created in API";
workspace = {
id = 6486925687953;
name = t;
};
};
Yet the created tag doesn't appear in the web app tags list and also the api call doesn't retrieve the newly created tag.
UPDATE:
when i put id of the new tag in the address bar like
https://app.asana.com/0/14896850962516/14896850962516
shows the tag in the webapp. Yet the api call is unable retrieve the the newly created tag item.

I'll quote my answer from Asana tag API query often misses newly created Tags:
The answer is that tags which aren't associated with any tasks are - unfortunately - hidden in the app, and consequently also in the API. As you discovered, you can get the ID back from the POST to create and then associate it with a task from there (since there's little purpose in creating a tag if you're not associating it with something that shouldn't typically be a problem, but it is clunky). We are looking at changing our data model for tags to be a bit more intuitive in future, but that's still a ways off, so this is the reality for the foreseeable future.

Related

GraphServiceClient to create a new SharePoint Online Site

I am trying to create a new subsite of another site in SP Online using the Graph SDK GraphServiceClient. I have successfully authenticated but I cant seem to get a site created - documentation is scarce as are examples so its basically hit and miss and I don't wish to use Graph REST for this purpose. Any help out there? The below code returns a Site object with an error of "invalid request". I'm sure I must be missing some required properties for the new Site object but which ones?
ItemReference parent = new ItemReference();
parent.Id = SiteRootForSubsite.Id;
Site newSite = new Site
{
ParentReference = parent,
Name = SubsiteName,
WebUrl = "/documentcenter909/mynewsite"
};
Site createdSite = await _graphClient.Sites
.Request()
.AddAsync(newSite);
Unfortunately you don't have the feature to create the site at this point as it only has Read only properties for the site. Being said that you can use the following workaround - can create an office 365 group, then assign owners & members then you will see a new SharePoint Online site will be created automatically.

Grails - how to display result page at a unique URL

I have a grails application that takes user input (create page/method), the user then clicks a Save button (save method that executes service) and then the results are displayed (list method) on a page, for example http://localhost:8080/myApp/myclass/save.
The users would like each results run to be saved to a unique URL so they can share it, bookmark it, save it later, whatever. I have NO idea how to go about this and google searches turn up little to nothing.
For example an application run would result in the data being displayed at http://localhost:8080/myApp/myclass/systemname/datetimestring/someuniquedata/
Is this even possible? Any pointers GREATLY appreciated.
EDIT
Here is my urlMappings contents.
class UrlMappings {
static mappings = {
"/$controller/$action?/$id?"{
constraints {
// apply constraints here
}
}
"/" {
controller = "api"
action = "create"
}
"500"(view:'/error')
}
}
When I display the results it's done through the list method shown here.
def list(Integer max) {
List<Api> api = Api.findAllBySessionId(session.id, [sort:'dateCreated'])
api = api[-2..-1]
[apiInstanceList: api, apiInstanceTotal: api.size()]
}
So I have the unique session ID. How do I need to modify "mappings"?
Every domain object that you're saving will have an autogenerated ID (assuming you're using GORM, which is definitely likely). It sounds like all you're asking for is a /show/id page where you can access a particular object via ID.
A url mapping for "/$controller/$action?/$id?" is a pretty straightfoward way to handle this, and is provided by default (and used by scaffolded controllers also).
If you'd rather not use an autogenerated ID (maybe you're moving objects from one database to another, or updating the ID for some reason?) you can consider using java.util.UUID.randomUUID() to generate a random, unique identifier and save that as a field on your object. You could then use .findByUuid with the input parameter.

Zend Apigility : DELETE HTTP method Validation

I have recently explored Apigility I want to use HTTP DELETE method to delete some entity but before deleting I need to validate "entityId" must be given and must be Digit and trim.
Problem is documentation mentions that:
Content Validation currently only works for POST, PATCH, and PUT requests. If you need to validate query string parameters, you will need to write your own logic for those tasks.
https://apigility.org/documentation/content-validation/intro
I have make some custome modification in config file as bellow:
'NetworkingNightAPI\\V1\\Rpc\\DeleteSlotByLoginUser\\Controller' => [
'DELETE' => 'NetworkingNightAPI\\V1\\Rpc\\AssignTimeSlotToLoginUser\\Validator',
],
As I have mention DELETE method to validate same as NetworkingNightAPI\V1\Rpc\AssignTimeSlotToLoginUser\Validator but the issue is it always return 'Value could not be empty' even I have added valid row JSON values using PostMan
Thanks!
Thank you for your reply
What I have found is Apigility uses 'zf-content-validation' module for validating the input data (https://github.com/zfcampus/zf-content-validation)
This module dose not restrict such HTTP Methods you can apply validation to DELETE method as well Like it says that
"In the above example, the Application\Controller\HelloWorld\Validator service will be selected for PATCH, PUT, or DELETE requests, while the Application\Controller\HelloWorld\CreationValidatorwill be selected for POST requests."
So you just need to add manual entry for DELETE method in config file as below:
'NetworkingNightAPI\\V1\\Rpc\\DeleteSlotByLoginUser\\Controller' => [
'input_filter' => 'NetworkingNightAPI\\V1\\Rpc\\DeleteSlotByLoginUser\\Validator',
'DELETE' => 'NetworkingNightAPI\\V1\\Rpc\\DeleteSlotByLoginUser\\Validator',
],
In addition HTTP DELETE method will not validate using JSON row body from POSTMAN you have to pass query parameters and in your controller you need to get validated data using plugin like below:
$recruiterId = $this->getInputFilter()->getValues()['recruiterId'];
$timeSlotId = $this->getInputFilter()->getValues()['timeSlotId'];
If you want to delete a resource your should use the url that includes the route to that entity. This means the id would be in your route parameters, not in your query parameters. So the id is a route parameter/identifier and the RestController will search your entity using the identifier in the fetch($id) method of your resource listener. The listener should return a not found (404) response in case the entity with that identifier doesn't exist.
The content validation you mention in your question is for validating POST/GET parameters. So there is no need for such validator in case of a delete request.
So say for example you want to delete a Slot you would have a route:
api/v1/slots/[slot_id]
And if you want to delete Slot with id 1 you would send a delete request to:
DELETE
api/v1/slots/1
Your listener should simply return a 404 response in case a Slot with slot_id 1 doesn't exist.
I see you're using RPC Rather than Rest style - if you're passing the parameter using the query string you will have to validate it yourself inside the controller, for example:
public function someActionMethod()
{
$id = $this->getRequest()->getQuery('id');
$validator = new Input('id');
$validator->getValidatorChain()
->attach(new \Zend\Validator\NotEmpty())
;
$validator->getFilterChain()
->attach(new StringToUpper())
;
$inputFilter = new InputFilter();
$inputFilter
->add($validator)
->setData($this->getRequest()->getQuery())
;
if( ! $inputFilter->isValid()) {
return new \ZF\ApiProblem\ApiProblemResponse(
new ApiProblem(400, $inputFilter)
);
}
}
Apigility won't use any of the config generated using the UI to validate those fields for you wuen passed via query string as it says in the docs - they will be ignored. You would need to generate the valaidator yourself.
You could set it up to generate the validation using a config if you wished and then load the validator inside the controller to save writing boiler plate code as above.

Zapier multi step triggers and passing variables

I am getting stuck creating my own app to use within Zapier. It is for an unsupported CRM
https://www.brightpearl.com/developer/latest/
I have been able to authenticate and create a test trigger - a simple call to retrive information about one product ID where the ID is provided in the request URL manually.
Example Use Case
Using an Email sent to a GMail account, search for a customerand add the body of the email as a note to the customer.
I can search using Zapier->Searches to retrieve a result.
The Brightpearl API search returns an ID for any matched contacts.
https://www.brightpearl.com/support/documentation/resource-search
The ID can be accessed in the json response
{
response: {
results: [
[
4,
"admin#email.com",
"Primary",
"Admin"
]
]
},
reference: {}
}
The ID is required to add the note later
How do I store the ID to use in the Action later?
How do I chain the events together so that the Action is called after the ID is captured?
I have gone through the Zapier documentation and cannot find example code which does this.
The trigger that exposes the ID in the API response (in this case, the Brightpearl search result) can be mapped to a subsequent action. You don't store data in Zapier - you just pass it between actions.
Zapier's multi-step interface lets you append actions which can accept any data returned from the previous step.

RESTful URL design for Widgets Check

I am building a RESTful API for a web site that allows users to create widgets and tabs containing widgets (think igoogle.com/ netvibes.com) and I want to share my URL design for your insights.
Here are the simple rules:
There is a static list of widgetTypes available for a user to pick.
A user can create one or more widgetInstances of each widgetType.
A user can create one or more tabs/ dashboards containing widgetInstances
This API needs to only serve JSON that will be consumed by JavaScript. We can also assume that all authentication will be taken care of through cookies.
The API needs to serve:
CRUD of user's Tabs
CRUD of specific user widgetInstances
Retrieval of all tabs for a user
Retrieval of all widgetInstances for a given tab.
Retrieval of all available widgetTypes for a user to add widgets from.
Design:
Tab controller:
widgetAPI.com/tabs -> Returns meta data (id, title) of all tabs available to a user.
widgetAPI.com/tabs/1 -> Returns meta data (title) of tab id 1. If sent with POST, updates tab id 1.
widgetAPI.com/tabs/1/widgets > Returns all widgetInstances of tab id 1.
Question 1: Ideally I'd like to follow the design of widgetAPI.com/tabs/1 also returning all the widgetInstances of the given tab but with that design, widgetAPI.com/tabs may return far too much data as I would have to return all the widgets for all the tabs. Hence I need to create a separate "widgetAPI.com/tabs/1/widgets" URL but that also has to return the tab meta data as I don't want to make two HTTP calls to get meta data & widgets. Please advise as I am not sure of the best approach here.
widgetAPI.com/tabs/create -> Create a new tab
widgetAPI.com/tabs/delete/123 -> Delete tabid 123
Widget Controller:
widgetAPI.com/widgets/123 -> Return data for widgetInstanceId 123. Updates 123 if sent through POST.
widgetAPI.com/widgets/Create?typeID = 2 -> Creates a new widgetInstance of typeid = 2. This will only be a POST request so typeId could be a post parameter.
widgetAPI.com/widgets/delete/123 -> Delete widgetInstance 123
Question 2 So there is one rule I havent been able to fulfill yet. I need to return all the widgetTypes available and I am not sure how to fit this request into the previous two controllers. I am currently leaning towards just serving this separately. So something like widgetAPI.com/getWidgetTypes. Thoughts?
Thanks guys. If you could critique on the overall design, just address the questions or mention anything I should watch out for, that would be great as this is my first time designing a RESTful app. Thanks again.
widgetAPI.com/tabs/1 -> Returns meta data (title) of tab id 1. If sent
with POST, updates tab id 1.
A POST to the above URL should not update tab 1. A PUT to that URL should update tab 1.
widgetAPI.com/tabs/create -> Create a new tab
To create a new tab, you should POST to widgetAPI.com/tabs
widgetAPI.com/tabs/delete/123 -> Delete tabid 123
To delete tab 123, send a DELETE to widgetAPI.com/tabs/123
widgetAPI.com/widgets/123 -> Return data for widgetInstanceId 123. Updates 123 if sent through POST
To update widget 123, send a PUT to widgetAPI.com/widgets/123
widgetAPI.com/widgets/Create?typeID = 2 -> Creates a new widgetInstance of typeid = 2. This will only be a POST request so typeId could be a post parameter.
To create a new widget, send a POST to widgetAPI.com/widgets. The typeId should be part of the POST request body.
widgetAPI.com/widgets/delete/123 -> Delete widgetInstance 123
To delete widget 123, send a DELETE request to widgetAPI.com/widgets/123
Answer 1: I like the widgetAPI.com/tabs/1/widgets URL design. Also, I like the idea of making 2 separate calls for the metadata and the data.
Answer 2: I think you should do this with a separate controller. I don't like the URL though. Instead, I like HTTP GET widgetAPI.com/widget-types or just widgetAPI.com/widgettypes.
As a general rule, unless you want your clients to be able to create URL identifiers, follow this pattern:
URL: /whatever-resource
GET - returns all resources of this type
POST - create a new resource
URL: /whatever-resource/{id}
GET - return single resource with that id
PUT - update resource with that id
DELETE - delete resource with that id
You can also allow PUT requests to /whatever-resource/{id} to create a resource, but the client / user must specify the id (implicitly, the URL, since the URL contains the id). If you don't want users to provide this, but rather have the server generate it, then POST to /whatever-resource to create the resource.

Resources