I'm attempting to use Eve to provide an RESTful API for a simple list of items.
I'd like to use 1) one HTTP request to create a list (possibly with initial items), 2) one HTTP request to add an item(s) (a common operation), 3) one HTTP request to get the list (including all child items). In other words:
1) POST /lists with body
{
"title": "My List",
"items": [{
"name": "Alice"
},
{
"name": "Bob"
}]
}
2) POST /lists/555555555555555555555555/items with body
{
"name": "Carol"
}
3) GET /lists/555555555555555555555555
{
"_id": "555555555555555555555555",
"title": "My List",
"items": [{
"_id": "aaaaaaaaaaaaaaaaaaaaaaaa",
"name": "Alice"
},
{
"_id": "bbbbbbbbbbbbbbbbbbbbbbbb",
"name": "Bob"
},
{
"_id": "cccccccccccccccccccccccc",
"name": "Carol"
}]
}
I haven't figured out how to do this with Eve. I can do (1) using an embedded list of dicts, but then I can't do (2)—I'd have to POST an item and then PATCH the list (?). I can do (2) using sub-resources, but then I can't do (1) ("value '{'name': 'Alice'}' cannot be converted to a ObjectId"). Or am I missing something?
If all three can't be done, could at least both (2) and (3)?
I figured out how to implement (2) and (3), using database event hooks to inject the embedded child documents into the parent list before it's returned to the client (and also delete the children when the parent is deleted). This works and supports the expected REST usage on individual list items. It results in two DB queries, however.
I suspect (1) could also be implemented using an event hook, but this will suffice for now.
Any further improvements/suggestions are welcome. It would be nice if there were an easier way to accomplish this (keywords: One-to-Many Relationships with Embedded Documents).
settings.py:
RESOURCE_METHODS = ['GET', 'POST', 'DELETE']
ITEM_METHODS = ['GET', 'PUT', 'PATCH', 'DELETE']
lists = {
'schema': {
'title': {
'type': 'string'
}
}
}
items = {
'url': 'lists/<regex("[a-f0-9]{24}"):list_id>/items',
'schema': {
'name': {'type': 'string',
'required': True
},
'list_id': {
'type': 'objectid',
'required': True,
'data_relation': {
'resource': 'lists',
'field': '_id'
}
}
}
}
DOMAIN = {
'lists': lists,
'items': items
}
main.py:
from bson.objectid import ObjectId
def before_returning_lists(response):
list_id = response['_id']
response['items'] = list(db.items.find({'list_id': ObjectId(list_id)}))
def after_deleting_lists(item):
list_id = item['_id']
db.items.delete_many({'list_id': ObjectId(list_id)})
app.on_fetched_item_lists += after_fetching_lists
app.on_deleted_item_lists += after_deleting_lists
Usage
curl -X POST http://127.0.0.1:5000/lists -d title="My List"
# (2)
curl -X POST http://127.0.0.1:5000/lists/5895fdb5a663e2dcad9e7647/items -d 'name=Alice'
curl -X POST http://127.0.0.1:5000/lists/5895fdb5a663e2dcad9e7647/items -d 'name=Bob'
curl -X POST http://127.0.0.1:5000/lists/5895fdb5a663e2dcad9e7647/items -d 'name=Carol'
# (3)
curl -X GET http://127.0.0.1:5000/lists/5895fdb5a663e2dcad9e7647
Related
How can I insert multiply records to a form using postman?
my data is in JSON file
and I use POST request:
"https://jrpostest.domjr.local/odata/Priority/tabula.ini/jrdf/SUPPLIERS"
getting the error below
You can use batch request in order to insert multiple records into a parent form with
one server call.
POST
https://jrpostest.domjr.local/odata/Priority/tabula.ini/jrdf/$batch
{
"requests": [
{
"method": "POST",
"url": "SUPPLIERS",
"body": {
"SUPNAME": "33445566",
"SUPDES": "33445566"
}
},
{
"method": "POST",
"url": "SUPPLIERS",
"body": {
"SUPNAME": "33445577",
"SUPDES": "33445577"
}
}
]
}
Please note that batch requests are available from Priority version 19.1.
In previous versions you will need to send two POST requests to the SUPPLIERS endpoint.
We're automating our TFS Team/Board creation and found that there is an API to create a Team and an API to create an Area Path, but not one to link the two. Basically we're looking for something that acts as the ‘Create an area path with the name of the team.’ check box in the attached picture.Screenshot Here's the code for our Team post:
$azdoURI = https://prd-ourCompanyName/tfs/ourOrg/_apis/projects/ourProject/teams?api-version=5.0"
$requestBody = #{ name = "$boardName" }
$jsonRequestBody = $requestBody | ConvertTo-Json -Compress
$response = (Invoke-WebRequest -Method Post -Uri $azdoURI -Body $jsonRequestBody -Content 'application/json' -Credential $credential -UseBasicParsing)
Adding an iteration to a team is done through the /_apis/work/teamsettings/iterations API.
Request:
POST https://dev.azure.com/fabrikam/Fabrikam-Fiber/_apis/work/teamsettings/iterations?api-version=5.1
"{\"id\":\"a589a806-bf11-4d4f-a031-c19813331553\"}"
Response:
{
"id": "a589a806-bf11-4d4f-a031-c19813331553",
"name": "Sprint 2",
"path": "Fabrikam-Fiber\\Release 1\\Sprint 2",
"attributes": {
"startDate": null,
"finishDate": null
}
}
To set area paths use the /_apis/work/teamsettings/teamfieldvalues:
Request:
PATCH https://dev.azure.com/fabrikam/Fabrikam-Fiber/_apis/work/teamsettings/teamfieldvalues?api-version=5.1
{
"defaultValue": "Fabrikam-Fiber\\Auto",
"values": [
{
"value": "Fabrikam-Fiber\\Auto",
"includeChildren": true
},
{
"value": "Fabrikam-Fiber\\Fiber",
"includeChildren": false
},
{
"value": "Fabrikam-Fiber\\Optics",
"includeChildren": false
}
]
}
Response:
{
"field": {
"referenceName": "System.AreaPath",
"url": "https://dev.azure.com/fabrikam/_apis/wit/fields/System.AreaPath"
},
"defaultValue": "Fabrikam-Fiber\\Auto",
"values": [
{
"value": "Fabrikam-Fiber\\Auto",
"includeChildren": true
},
{
"value": "Fabrikam-Fiber\\Fiber",
"includeChildren": false
},
{
"value": "Fabrikam-Fiber\\Optics",
"includeChildren": false
}
]
}
See also:
TeamFieldvales
Iterations
Basically we're looking for something that acts as the ‘Create an area
path with the name of the team.’ check box in the attached picture.
If I understand you well, you're trying to create a new Team Project in which there's one default Area path. (Of course you also want their names should be the same)
For TFS2018U2, try:
POST https://{instance}/{collection}/_apis/projects?api-version=4.1
For Azure Devops Server 2019, try:
POST https://{instance}/{collection}/_apis/projects?api-version=5.0
You can find more details from my another post here. After my check, this api will automatically define the default area path with same name like Team project's:
So here's where I ended up:
5 Steps:
Create team: POST https://dev-tfs.../{organization}/_apis/projects/{project}/teams?api-version=5.1
Body: {"name":"BoardByPostmanTest_3"}
Create Area Path to match team: POST https://dev-tfs.../{organization}/{project}/_apis/wit/classificationnodes/Areas?api-version=5.1
Body: {"name":"BoardByPostmanTest_3"}
Update Team with Area path: PATCH https://dev-tfs.z../{organization}/{project}/BoardByPostmanTest_3/_apis/work/teamsettings/teamfieldvalues?api-version=5.1
Body:
{
"defaultValue": "Agile\BoardByPostmanTest_3",
"values": [
{
"value": "Agile\BoardByPostmanTest_3",
"includeChildren": true
}
]
}
Find Iteration for project: GET https://dev-tfs.../{organization}/{project}/_apis/wit/classificationnodes/Iterations?api-version=5.1
Add that Iteration to Team: PATCH https://dev-tfs.../{organization}/{project}/BoardByPostmanTest_3/_apis/work/teamsettings?api-version=5.1
Body:
{
"backlogIteration": "whatever that Iteration number is from GET in step 4"
}
Thank you to jessehouwing for step 3 that I was missing.
I'm trying to set a custom_fields of type enum_value in a task that I'm creating with a POST HTTP request.
I managed to set a custom_field of type number but I'm having issue with the custom_fields of type enum_value
Questions:
Here's what I did so far:
1- I created the custom_fields that I want to populate on asana, I can set custom_fields of type number but not the ones of type enum_value( see picture attached)
Here's my code (I tried different implementations to set the custom_fields that were incorrect) :
var task = {
data: {
assignee: "me",
workspace: "1234567",
projects: "9876543",
parent: null,
custom_fields: {
"1234567898": 333, // this works
"98765": "Public" // this custom field holds an enum_values, this implementation doesn't work
},
notes: "Test notes"
}
}
It looks like you put the name of the enum_value instead of the id. Here is an example of a PUT/POST request and response:
# Request
curl --request PUT -H "Authorization: Bearer <personal_access_token>" \
https://app.asana.com/api/1.0/tasks/1001 \
-d
'{
"data": {
"custom_fields":{
"124578":"439"
}
}
}'
# Response
{
"data": {
"id": 1001,
"name": "Hello, world!",
"completed": false,
"...": "...",
"custom_fields": [
{
"id": 124578,
"name": "Priority",
"type": "enum",
"enum_value": {
"id": 439,
"name": "High",
"enabled": true,
"color": "red"
}
},
"~..."
]
}
}
It's admittedly a bit buried, but if you look in the Custom Fields section of the getting started documentation, there is an example of creating custom fields under "Accessing Custom Field values on Tasks".
We have an index of domain names in elasticsearch (we are using the tire gem with ruby to connect and maintain this) however we are having trouble with exact searches.
If I search for the term google.com in domains, it brings back google.com however it also brings back any domain with a dash (-) in such as in-google.com, research leads me to believe that - is a wildcard in ES and all I need to do is put not_analyzed but that doesn't work.
:domain => { :type => 'string' , :analyzer => 'whitespace' },
:domain_2 => { :type => 'string' , :analyzer => 'pattern' },
:domain_3 => { :type => 'string', :index => 'not_analyzed' },
:domain_4 => { :type => 'string', :analyzer => 'snowball' }
I've tried different analysers as you can see above, but they all have the same issue when searched using the 'head' plugin'.
https://gist.github.com/anonymous/8080839 is the code I'm using to generate the dataset to test with, what I'm looking for is the ability to search for JUST google and if I want *google I can implement my own wildcard?
I'm resigned to the fact that I'm going to have to delete and regenerate my index but no matter what analyser I choose or type, I still cannot get an exact match
You're not showing the sample queries you are using. Are you sure your queries and indexing uses the same text processing?
Also, you may want to check out the multi_field-approach to analyzing things multiple ways.
I've made a runnable example with a bunch of different queries that illustrate this. Note that the domain has been indexed in two ways, and note which field the queries are hitting: https://www.found.no/play/gist/ecc52fad687e83ddcf73
#!/bin/bash
export ELASTICSEARCH_ENDPOINT="http://localhost:9200"
# Create indexes
curl -XPUT "$ELASTICSEARCH_ENDPOINT/play" -d '{
"mappings": {
"type": {
"properties": {
"domain": {
"type": "multi_field",
"fields": {
"domain": {
"type": "string",
"analyzer": "standard"
},
"whitespace": {
"type": "string",
"analyzer": "whitespace"
}
}
}
}
}
}
}'
# Index documents
curl -XPOST "$ELASTICSEARCH_ENDPOINT/_bulk?refresh=true" -d '
{"index":{"_index":"play","_type":"type"}}
{"domain":"google.com"}
{"index":{"_index":"play","_type":"type"}}
{"domain":"in-google.com"}
'
# Do searches
# Matches both
curl -XPOST "$ELASTICSEARCH_ENDPOINT/_search?pretty" -d '
{
"query": {
"match": {
"_all": "google.com"
}
}
}
'
# Also matches "google.com". in-google.com gets tokenized to ["in", "google.com"]
# and the default match operator is `or`.
curl -XPOST "$ELASTICSEARCH_ENDPOINT/_search?pretty" -d '
{
"query": {
"match": {
"domain": {
"query": "in-google.com"
}
}
}
}
'
# What terms are generated? (Answer: `google.com` and `in`)
curl -XPOST "$ELASTICSEARCH_ENDPOINT/_search?pretty" -d '
{
"size": 0,
"facets": {
"domain": {
"terms": {
"field": "domain"
}
}
}
}
'
# This should just match the second document.
curl -XPOST "$ELASTICSEARCH_ENDPOINT/_search?pretty" -d '
{
"query": {
"match": {
"domain.whitespace": {
"query": "in-google.com"
}
}
}
}
'
Short
I can't get neo to update existing node properties in a batched rest op.
Long
I want to create a batch operation that inserts/updates a node inside an index. It should handle three use-cases:
if the node does not exist, insert it with the given properties set
if the node exists, update it's properties set with the new values, if any.
I'm using the batch operation api, I wrote a test where I'm issuing two requests:
Short
1. first one inserts the node and indexes it's properties
2. second one simply updates some properties of the node
Here's the first request:
[
{
"method": "POST",
"to": "/index/node/events?uniqueness=get_or_create",
"id": 1,
"body": {
"key": "id",
"value": "222222222",
"properties": {
"id": "222222222",
"type": "event-type"
}
}
},
{
"method": "POST",
"to": "/index/node/events",
"body": {
"uri": "{1}",
"key": "id",
"value": "222222222"
}
},
{
"method": "POST",
"to": "/index/node/events",
"body": {
"uri": "{1}",
"key": "type",
"value": "event-type"
}
} ]
And now the second one.
[
{
method: 'POST',
to: '/index/node/events?uniqueness=get_or_create',
id: 1,
body: {
key: 'id',
value: '222222222',
properties: {id: '222222222', type: 'event-type', title: 'SUPEREVENT'}
}
},
{
method: 'POST',
to: '/index/node/events',
body: {
uri: '{1}',
key: 'id',
value: '222222222'
}
},
{
method: 'POST',
to: '/index/node/events',
body: {
uri: '{1}',
key: 'type',
value: 'event-type'
}
},
{
method: 'POST',
to: '/index/node/events',
body: {
uri: '{
1
}',
key: 'title',
value: 'SUPEREVENT'
}
}
]
NOTE! that on the second request i'm adding and event title property with value SUPEREVENT. This does not get persisted nor indexed. Why? and how can I fix it?
Thank you,
Alex
From the doc:
URL Parameter uniqueness=get_or_create: Create a new node/relationship
and index it if no existing one can be found. If an existing
node/relationship is found, discard the sent data and return the
existing node/relationship.
So your second request's data will be discarded. You need to split each of your requests in two requests each, and do two batches. Each of the two batches has two instructions: first one creates the node if not present, and the second one updates the properties.