What is the unique ID for API Products in the Apigee Edge server API? - apigee

I am using the REST API for the Apigee Edge server, and am getting the details of the API products for my organization:
https://api.enterprise.apigee.com/v1/organizations/chrisnovak/apiproducts/PremiumWeatherAPI
Here is the response:
{
"apiResources" : [ ],
"approvalType" : "auto",
"attributes" : [ {
"name" : "description",
"value" : "Premium API Product to expose the weather API to developers"
}, {
"name" : "access",
"value" : "public"
}, {
"name" : "developer.quota.limit",
"value" : "10000"
}, {
"name" : "developer.quota.interval",
"value" : "1"
}, {
"name" : "developer.quota.timeunit",
"value" : "month"
} ],
"createdAt" : 1351796304109,
"createdBy" : "noreply_admin#apigee.com",
"description" : "",
"displayName" : "Weather API",
"environments" : [ "test", "prod" ],
"lastModifiedAt" : 1386812022110,
"lastModifiedBy" : "cnovak#apigee.com",
"name" : "PremiumWeatherAPI",
"proxies" : [ "weather" ],
"quota" : "10000",
"quotaInterval" : "1",
"quotaTimeUnit" : "month",
"scopes" : [ "READ" ]
}
However, I do not see a unique key in the response, and do not see any Apigee API reference documentation for API products around what the unique key is.
My questions are:
What is the unique ID for the API products in the system?
If there is not a unique ID, what happens if the API product is renamed? I need to be able to associate API products with documentation in an external system, and if the name changes, I will no longer be able to associate that documentation with that API product.

Chris,
The unique ID is the name field. It is generated from the display name the first time you save the product. That never changes. Any later changes to the name change the displayName field but not the name.

The 'Name' field is the unique field here. if you change the display name it will not affect the name field, so you can go ahead and use the name field in your documentation.

Name field is unique here.
You can test it by changing the name field and doing a POST for apiproducts.
It will create an apiproduct with the same display name but different name field.
Then if you are using the same name field and editing just display name and trying to POST for apiproducts it will give error as below:
-bash-4.1$ POST /o/weatherapi/apiproducts -H "Accept: text/xml" -H "Content-Type: text/xml" -d #st.xml
Test
keymanagement.service.apiproduct_already_exists
ApiProduct with name yahoo1 already exists
-bash-4.1$

Related

Artifactory aql: find builds of job with given property

I am trying to query which build number(s) produced artifacts from build foo with artifact property vcs.Revision=aabbccddee123456.
In Artifactory 5.1.3.
I was trying like this so far:
curl -u user:apikey -i -X POST https://artifactory.foobar.com/artifactory/api/search/aql -H "content-type:text/plain" -T query.json
query.json:
builds.find(
{
"module.artifact.item.repo":"snapshot-local",
"name":"foo",
"module.artifact.item.#vcs.Revision":"aabbccddee123456"
}
)
However, none of these 3 lines seem individually correct:
builds.find({"module.artifact.item.repo":"snapshot-local"})
returns nothing,
builds.find({"name":"foo"})
returns the same empty response,
builds.find({"module.artifact.item.#vcs.Revision":"aabbccddee123456"}) also returns this:
{
"results" : [ ],
"range" : {
"start_pos" : 0,
"end_pos" : 0,
"total" : 0
}
}
What am I doing wrong here? I do see in the webapp the builds I published with this name, and with the correct artifact properties.
Here's a working solution that will give build numbers (since giving admin rights to query builds is not a solution for us):
query.json:
items.find(
{
"repo":"snapshot-local",
"artifact.module.build.name":"foo",
"artifact.item.#vcs.Revision":"aabbccddee123456"
}
).include("artifact.module.build.number")
This returns a list of all the artifacts that were built with the relevant properties, with the build number attached, e.g:
{
"results" : [ {
"repo" : "snapshot-local",
"path" : "foo/42",
"name" : "a.out",
"type" : "file",
"size" : 123456789,
"created" : "2018-07-05T12:34:56.789+09:00",
"created_by" : "jenkins",
"modified" : "2018-07-05T12:34:56.789+09:00",
"modified_by" : "jenkins",
"updated" : "2018-07-05T12:34:56.789+09:00",
"artifacts" : [ {
"modules" : [ {
"builds" : [ {
"build.number" : "42"
} ]
} ]
} ]
},
[SNIP]
}
],
"range" : {
"start_pos" : 0,
"end_pos" : 30,
"total" : 30
}
}
I can then parse this to extract build.number.
Certain AQL queries requires a user with admin permissions.
To ensure that non-privileged users do not gain access to information without the right permissions, users without admin privileges have the following restrictions:
The primary domain in the query may only be item.
The following three fields must be included in the include directive: name, repo, and path.
In your case, you are using the build domain in the query which requires admin permissions

Artifactory API AQL "Displaying Specific Fields"

According to below link, Artifactory AQL allows "Displaying of specific fields" via REST API by returning only fields of interest.
https://www.jfrog.com/confluence/display/RTF/Artifactory+Query+Language#ArtifactoryQueryLanguage-DisplayingSpecificFields
It doesn't work if I provide a list of fields, see below
Not Work - Bad request (400)
items.find(...).include("name", "repo")
Works
items.find(...).include("*")
Can anyone advise
Thanks, Jag
I suspect that the problem is related to encoding during the REST call, therefore I suggest to upload the query as a file Here is a working example:
Save the following query to file, lets call it aql.query
items.find
(
{
"repo": {"$match":"*"}
}
)
.include("name","repo")
Run the following curl command from the same directory that contains the aql.query file and don't forget to replace the templates in the command with your user name, password, host and port.
curl -X POST -uuser:password 'http://host:port/artifactory/api/search/aql' -Taql.query
In the result you will get:
{
"results" :
[
{
"repo" : "ext-snapshot-local",
"name" : "maven-metadata.xml"
},{
"repo" : "ext-snapshot-local",
"name" : "multi-3.0.0-20150705.195404-1.pom"
},{
.
.
.
}
],
"range" :
{
"start_pos" : 0,
"end_pos" : 46,
"total" : 46
}
}
As you can see that the result contains only the "item repo" and the "item name" fields.
Had the same issue. Spent quite a bit of time trying to figure this out. Couldn't find an answer online.
With a bad request(400), I printed the response text: "For permissions reasons AQL demands the following fields: repo, path and name."
This solution worked for me -
at a minimum: have repo, path, name.
ie... items.find(...).include("name", "repo", "path", "created_by")

Proper way to apply custom analyzers to fields with elastic search, apply multiple analyzers to one field or multiple fields with single analyzers?

EDIT: Added my current query to the end
I have a large database of human names and am using elastic search (via symfony2's FOSElasticaBundle and Elastica) to do smarter searching of the names.
I have a full name field, and I want to index the people's names with standard, ngram, and phonetic analyzers.
I've got the analyzers set up in elastic search, and I can begin dumping data into the index. I'm wondering if the way I'm doing it here is the best way, or if I can apply the analyzers to a single field...the reason I ask is because when I do a get /website/person/:id, I see all three fields in plain text...I was expecting to see the analyzed data here, although I guess it must only exist in an inverted index rather than on the document. Examples I've seen use multiple fields, but is it possible to add multiple analyzers to a single field?
My config.yml:
fos_elastica:
clients:
default: { host: %elastica_host%, port: %elastica_port% }
indexes:
website:
settings:
index:
analysis:
analyzer:
phonetic_analyzer:
type: "custom"
tokenizer: "lowercase"
filter: ["name_metaphone", "lowercase", "standard"]
ngram_analyzer:
type: "custom"
tokenizer: "lowercase"
filter : [ "name_ngram" ]
filter:
name_metaphone:
encoder: "metaphone"
replace: false
type: "phonetic"
name_ngram:
type: "nGram"
min_gram: 2
max_gram: 4
client: default
finder: ~
types:
person:
mappings:
name: ~
nameNGram:
analyzer: ngram_analyzer
namePhonetic:
analyzer: phonetic_analyzer
When I check the mapping it looks good:
{
"website" : {
"mappings" : {
"person" : {
"_meta" : {
"model" : "acme\\websiteBundle\\Entity\\Person"
},
"properties" : {
"name" : {
"type" : "string",
"store" : true
},
"nameNGram" : {
"type" : "string",
"store" : true,
"analyzer" : "ngram_analyzer"
},
"namePhonetic" : {
"type" : "string",
"store" : true,
"analyzer" : "phonetic_analyzer"
}
}
}
}
}
}
When I GET the document, I see that all three fields are stored in plain text... maybe i need to set STORE: FALSE for these extra fields, or, is it not being analyzed properly?
{
"_index" : "website",
"_type" : "person",
"_id" : "1",
"_version" : 1,
"found" : true,
"_source":{
"name":"John Doe",
"namePhonetic":"John Doe",
"nameNGram":"John Doe"
}
}
EDIT: The solution I'm currently using, which still requires some refinement but tests well for most names
//Create the query object
$boolQuery = new \Elastica\Query\Bool();
//Boost exact name matches
$exactMatchQuery = new \Elastica\Query\Match();
$exactMatchQuery->setFieldParam('name', 'query', $name);
$exactMatchQuery->setFieldParam('name', 'boost', 10);
$boolQuery->addShould($exactMatchQuery);
//Create a basic Levenshtein distance query
$levenshteinMatchQuery = new \Elastica\Query\Match();
$levenshteinMatchQuery->setFieldParam('name', 'query', $name);
$levenshteinMatchQuery->setFieldParam('name', 'fuzziness', 1);
$boolQuery->addShould($levenshteinMatchQuery);
//Create a phonetic query, seeing if the name SOUNDS LIKE the name that was searched
$phoneticMatchQuery = new \Elastica\Query\Match();
$phoneticMatchQuery->setFieldParam('namePhonetic', 'query', $name);
$boolQuery->addShould($phoneticMatchQuery);
//Create an NGRAM query
$nGramMatchQuery = new \Elastica\Query\Match();
$nGramMatchQuery->setFieldParam('nameNGram', 'query', $name);
$nGramMatchQuery->setFieldParam('nameNGram', 'boost', 2);
$boolQuery->addMust($nGramMatchQuery);
return $boolQuery;
No, you can't have multiple analyzers on a single field. The way you are doing is correct way of applying multiple analyzers by having different field names for same field.
The reason you are getting namePhonetic and nameNGram also in _source field is use of
"store" : true
It tells the ElasticSearch that you need those extra fields also in response. Use
"store" : false
that will solve your problem.
If you want to see the analyzed data on a field you can use _analyze api of elasticsearch.
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-analyze.html
Yes, these fields are stored in inverted index after analysis.
I hope I have answered all your doubts. Please let me know if you need more help on this.
Thanks

How do you get a list of all developers and apps for an API in Apigee?

Say you have exposed an API Product in Apigee. You would like to get a list of all the developers and their apps that have registered for the API Product.
There is a call to return those, documented here:
http://apigee.com/docs/api/get-list-keys-apps-developers-or-companies-api-product
But the IDs it returns appear to be useless. If you try developers, for instance:
https://api.enterprise.apigee.com/v1/organizations/YOUR-ORG/apiproducts/YOUR-PRODUCT?query=list&entity=developers
you get back a list of IDs. But to find which developer a given ID relates to is impossible, as the call to get a developer:
http://apigee.com/docs/api/get-developer
only accepts an email address.
How can I get a list of all the developers and their apps registered for a given API product?
The Apps a developer has is nested in each developer:
https://api.enterprise.apigee.com/v1/o/{your org}/developers
will return a list of developers like this:
["email#domain.com", "email2#domain2.com"]
Then you have to loop through each developer to get a list of their apps:
https://api.enterprise.apigee.com/v1/o/{your org}/developers/tesla#weathersample.com
Which gives you a bunch of meta data including apps:
{
"apps" : [ "weather" ],
"companies" : [ ],
"email" : "tesla#weathersample.com",
"developerId" : "Hk5mmLw9kKIM95qF",
"firstName" : "Nikolai",
"lastName" : "Tesla",
"userName" : "Nikolai",
"organizationName" : "jokeindex",
"status" : "active",
"attributes" : [ ],
"createdAt" : 1357858239543,
"createdBy" : "noreply_admin#apigee.com",
"lastModifiedAt" : 1357858239543,
"lastModifiedBy" : "noreply_admin#apigee.com"
}
Finally, if you look at each app you can see the products associated with that developer app:
https://api.enterprise.apigee.com/v1/o/{your org}/developers/tesla#weathersample.com/apps/weather
Gets you this detail:
{
"accessType" : "read",
"appFamily" : "default",
"appId" : "030fdcea-cf97-40b1-96df-12084aea513c",
"attributes" : [ {
"name" : "Developer",
"value" : "tesla#weathersample.com"
}, {
"name" : "DisplayName",
"value" : "Weather"
}, {
"name" : "Notes",
"value" : "not yet"
}, {
"name" : "lastModifier",
"value" : ""
} ],
"callbackUrl" : "http://example.com/callback",
"createdAt" : 1363578857830,
"createdBy" : "adminui#apigee.com",
"credentials" : [ {
"apiProducts" : [ {
"apiproduct" : "weather",
"status" : "approved"
} ],
"attributes" : [ ],
"consumerKey" : "{key}",
"consumerSecret" : "{key}",
"expiresAt" : -1,
"scopes" : [ ],
"status" : "approved"
} ],
"developerId" : "Hk5mmLw9kKIM95qF",
"lastModifiedAt" : 1386042817268,
"lastModifiedBy" : "michael.bissell#apigee.com",
"name" : "weather",
"scopes" : [ ],
"status" : "approved"
}
Take a look at the Org Snapshot Tool on git if you want to interrogate the entire org with one script:
https://github.com/apigee/api-platform-samples/tree/master/tools
This will interrogate every developer and every app and put it into a nice tree structure in your file system for future reference.

Drupal 7 Rules - on cron, check date field and if past set field [Status] from “active” to “ended”

OK... let me start by saying I know there is a similar post here (How to create a Drupal rule to check (on cron) a date field and if passed set field "status" to "ended"?) but the answer on that post does not work. Step 4 (In the component add the condition 'Data comparison' and select node:type) does not work or even exists as an option.
What I need to do is this:
On Cron > If content type is event and the end date has passed the current date then change the status field from Active to Ended. (select list)
I was able to do this by using the Event: Content is viewed but I really need to to work when cron is ran.
Side note: with the current version I have (Content is viewed) it does change Active to Ended but it also for some reason deletes the title of the node which is strange becuase the title filed is required by Drupal... any idea wht that is happening?
Not sure if it helps but here is an export of what I have done myself:
{ "rules_event_status" : {
"LABEL" : "Event Status",
"PLUGIN" : "reaction rule",
"ACTIVE" : false,
"REQUIRES" : [ "rules", "php" ],
"ON" : [ "node_view" ],
"IF" : [
{ "node_is_of_type" : { "node" : [ "node" ], "type" : { "value" : { "event" : "event" } } } },
{ "AND" : [] },
{ "php_eval" : { "code" : "\/\/dpm(strtotime($node-\u003Efield_event_date_time[LANGUAGE_NONE][0][\u0027value2\u0027]));\r\nif (time() \u003E strtotime($node-\u003Efield_event_date_time[LANGUAGE_NONE][0][\u0027value2\u0027]))\r\n{\r\n return true;\r\n}" } }
],
"DO" : [
{ "data_set" : { "data" : [ "node:field-event-status" ], "value" : "Ended" } }
]
}
}
Any help is very much appreciated.
Thanks
C
to use any custom fields or fields created by other modules than node, you have to add condition "entity has field" to your rules which will make that field "visible" and accesible for later work
side note: I think you can do the date comparison without php_eval, just add another entity has field condition and create "data comparison" condition. There should be tokens available to your needs
Not sure I fully understand the question: rules can be triggered by cron.
You should be able to get it to run when cron executes by picking the "React on event" attribute of the rule to "System > Cron maintenance tasks are executed".
Am I missing something?

Resources