I'm using Outlook Contacts REST API in order to get all phone numbers saved for a given contact.
I have to call both versions of the API (v2.0 & beta) so I can get almost all values.
ie. v2.0 send me this:
HomePhones: [ '0333333333', '0444444444' ],
MobilePhone1: '0611111111',
BusinessPhones: [ '0155555555', '0166666666' ],
and beta send me this:
Phones: [
{ Type: 'Home', Number: '0333333333' },
{ Type: 'Business', Number: '0155555555' },
{ Type: 'Mobile', Number: '0611111111' },
{ Type: 'Other', Number: '0677777777' }
],
However, my contact looks like this:
As you can see, both API send me different results, and none of them is complete.
Moreover, the contact I saved in my account has one more phone number, Mobile2, and none of the APIs send it to me.
Is there a way to get it?
Thank you,
bjorge
The API doesn't expose this directly. However, you can always request it as an extended property using the correct MAPI property tag details.
I examined a contact with MFCMapi and I see that the Mobile2 number is stored in PR_CAR_TELEPHONE_NUMBER, which is a string property with the property ID of 0x3A1E. So, since you're using the Outlook REST endpoint, your request would look something like this:
GET /me/contacts?$expand=SingleValueExtendedProperties(
$filter=PropertyId eq 'String 0x3A1E')
If you were using Graph, the request would look a little different:
GET /me/contacts?$expand=singleValueExtendedProperties(
$filter=id eq 'String 0x3A1E')
Finally, I'd recommend voting up this UserVoice request: https://officespdev.uservoice.com/forums/224641-feature-requests-and-feedback/suggestions/19861435-beef-up-contact-resource-contents-in-rest-api
Related
Given the following GraphQL mutations:
type Mutation {
updateUser(id: ID!, newEmail: String!): User
updatePost(id: ID!, newTitle: String!): Post
}
The Apollo docs state that it's totally possible to perform multiple mutations in one request, say
mutation($userId: ID!, $newEmail: String!, $postId: ID!, $newTitle: String!) {
updateUser(id: $userId, newEmail: $newEmail) {
id
email
}
updatePost(id: $postId, newTitle: $newTitle) {
id
title
}
}
1. Does anyone actually do this? And if you don't do this explicitly, will batching cause this kind of mutation merging?
2. If you perform run multiple things within on mutation, how would you handle errors properly?
I've seen a bunch of people recommending to throw errors on the server so that the server would respond with something that looks like this:
{
errors: [
{
statusCode: 422,
error: 'Unprocessable Entity'
path: [
'updateUser'
],
message: {
message: 'Validation failed',
fields: {
newEmail: 'The new email is not a valid email address.'
}
},
},
{
statusCode: 422,
error: 'Unprocessable Entity'
path: [
'updatePost'
],
message: {
message: 'Validation failed',
fields: {
newTitle: 'The given title is too short.'
}
},
}
],
data: {
updateUser: null,
updatePost: null,
}
}
But how do I know which error belongs to which mutation? We can't assume, that the first error in the errors array belongs to the first mutation, because if updateUser succeeds, the array would simple contain one entry. Would I then have to iterate over all errors and check if the path matches my mutation name? :D
Another approach is to include the error in a dedicated response type, say UpdateUserResponse and UpdatePostResponse. This approach enables me to correctly address errors.
type UpdateUserResponse {
error: Error
user: User
}
type UpdatePostResponse {
error: Error
post: Post
}
But I have a feeling that this will bloat my schema quite a lot.
In short, yes, if you include multiple top-level mutation fields, utilize the path property on the errors to determine which mutation failed. Just be aware that if an error occurs deeper in your graph (on some child field instead of the root-level field), the path will reflect that field. That is, an execution error that occurs while resolving the title field would result in a path of updatePost.title.
Returning errors as part of the data is an equally valid option. There's other benefits to this approach to:
Errors sent like this can include additional meta data (a "code" property, information about specific input fields that may have generated the error, etc.). While this same information can be sent through the errors array, making it part of your schema means that clients will be aware of the structure of these error objects. This is particularly important for clients written in typed languages where client code is often generated from the schema.
Returning client errors this way lets you draw a clear distinction between user errors that should be made visible to the user (wrong credentials, user already exists, etc.) and something actually going wrong with either the client or server code (in which case, at best, we show some generic messaging).
Creating a "payload" object like this lets you append additional fields in the future without breaking your schema.
A third alternative is to utilize unions in a similar fashion:
type Mutation {
updateUser(id: ID!, newEmail: String!): UpdateUserPayload!
}
union UpdateUserPayload = User | Error
This enables clients to use fragments and the __typename field to distinguish between successful and failed mutations:
mutation($userId: ID!, $newEmail: String!) {
updateUser(id: $userId, newEmail: $newEmail) {
__typename
... on User {
id
email
}
... on Error {
message
code
}
}
}
You can get even create specific types for each kind of error, allowing you to omit any sort of "code" field:
union UpdateUserPayload = User | EmailExistsError | EmailInvalidError
There's no right or wrong answer here. While there are advantages to each approach, which one you take comes ultimately comes down to preference.
I've been trying to send fax using RingCentral API but there is no way to specify the From fax phone number to send the fax. It is only sending the fax using company fax number. I am not able to find the option to use fax from number. I am using the following end point for sending fax:
https://platform.ringcentral.com/restapi/v1.0/account/:accountId/extension/:extensionId/fax
In the RingCentral system, the From (or sending) fax number is the fax caller ID value. You can update this for your extension to use with your faxes, but the value is not available in the send fax API itself. To change this on a per send basis, you can update the caller ID value before each fax request.
You can update the Fax Caller ID using two approaches:
via API or
using the Online Account Portal (https://service.ringcentral.com), both of which are described below.
Both are described below. Let me know if this works for you.
1) Updating the Fax Caller ID
To update the fax caller ID, call the PUT extension/caller-id endpoint and update the callerId for the FaxNumber feature using the phone number ID of the number you are interested in using. You can get a list of this by calling the extension/phone-number shown in the next section.
PUT /restapi/v1.0/account/{accountId}/extension/{extensionId}/caller-id
Authorization: Bearer {accessToken}
Content-Type: application/json
{
"byFeature": [
{
"feature": "FaxNumber",
"callerId": {
"phoneInfo": {
"id": 33333333
}
}
}
]
}
See the API Reference for more: https://developer.ringcentral.com/api-docs/latest/index.html#!#RefUpdateCallerId
1.1) Listing Your Available Caller ID Numbers
To get a list a list of numbers you can use, call the GET extension/phone-number endpoint:
GET /restapi/v1.0/account/{accountId}/extension/{extensionId}/phone-number
Authorization: Bearer {accessToken}
In your JSON response, you will have a list of phone numbers in the records property. Numbers that you can use will have the following property values:
features property will have the CallerId value
type property will be set to VoiceFax or FaxOnly
The following is the excerpt of a JSON response showing one number. You should have more numbers and a paging object.
{
"uri":"https://platform.devtest.ringcentral.com/restapi/v1.0/account/11111111/extension/22222222/phone-number?page=1&perPage=100",
"records":[
{
"id":33333333,
"phoneNumber":"+16505550100",
"paymentType":"Local",
"location":"Belmont, CA",
"type":"VoiceFax",
"usageType":"DirectNumber",
"status":"Normal",
"country":{
"uri":"https://platform.devtest.ringcentral.com/restapi/v1.0/dictionary/country/1",
"id":"1",
"name":"United States"
},
"features":[
"SmsSender",
"CallerId",
"MmsSender"
]
}
]
}
See the API Reference for more: https://developer.ringcentral.com/api-docs/latest/index.html#!#RefUserPhoneNumbers.html
1.2) Reading The Fax Caller ID Value
RingCentral supports multiple caller ID values. To read the value for your extension make the following API call to the extension/caller-id endpoint:
GET /restapi/v1.0/account/{accountId}/extension/{extensionId}/caller-id
Authorization: Bearer {accessToken}
You will receive a response like the following with an array of caller ID values in the byFeature property. Look for the feature with the feature property set to FaxNumber. I only show the FaxNumber feature caller ID below, but the array includes the following features: CallFlip, FaxNumber, RingMe, RingOut, MobileApp, Alternate.
{
"uri":"https://platform.devtest.ringcentral.com/restapi/v1.0/account/11111111/extension/22222222/caller-id",
"byFeature":[
{
"feature":"FaxNumber",
"callerId":{
"type":"PhoneNumber",
"phoneInfo":{
"uri":"https://platform.devtest.ringcentral.com/restapi/v1.0/account/11111111/phone-number/33333333",
"id":"33333333",
"phoneNumber":"+16505550100"
}
}
}
]
}
See the API Reference for more: https://developer.ringcentral.com/api-docs/latest/index.html#!#RefGetCallerId
2) Using the Online Account Portal
You can also change the Caller ID value in the Online Account Portal under:
Settings > Outbound Calls > Caller ID > By Feature > Fax Number
More is available in this Knowledgebase Article:
https://success.ringcentral.com/articles/RC_Knowledge_Article/3614
This worked for me when working with the RingCentral Java SDK.
To get the sender/caller numbers list that I can use for my Fax/call
RestClient rc = new RestClient(RINGCENTRAL_CLIENTID, RINGCENTRAL_CLIENTSECRET, RINGCENTRAL_SERVER);
rc.authorize(RINGCENTRAL_USERNAME, RINGCENTRAL_EXTENSION, RINGCENTRAL_PASSWORD);
GetExtensionPhoneNumbersResponse numbers = rc.restapi().account().extension().phonenumber().get();
To update the sender/caller number
RestClient rc = new RestClient(RINGCENTRAL_CLIENTID, RINGCENTRAL_CLIENTSECRET, RINGCENTRAL_SERVER);
rc.authorize(RINGCENTRAL_USERNAME, RINGCENTRAL_EXTENSION, RINGCENTRAL_PASSWORD);
ExtensionCallerIdInfo resp = rc.restapi().account().extension().callerid().get();
for (CallerIdByFeature e : resp.byFeature) {
if (e.callerId.phoneInfo != null) {
e.callerId.phoneInfo.phoneNumber("**********");
}
}
resp = rc.restapi().account().extension().callerid().put(resp);
In a mobility context of use of the API, an advanced research proposes several dynamic filters that must be returned by the server. (We don't want to make too many exchange with server to initialize our filters)
In a REST api, how to expose a enum of possible values for filter search?
Thank you for your suggestions/ideas?
My initial thought would be to treat the search like a normal resource. In an object oriented perspective, a search can have a collection of fields which can be used to filter by. These fields can be numeric, boolean, string based, or whatever.
So, if I understand your question correctly, then I would propose doing this:
GET /search_fields
If your API have multiple type searches that can be performed, then they can be identified by an id or maybe their name, as long as it is unique, like so:
GET /searches/{search_id}/fields
which would return a collection of search fields like so:
[{
name: 'Field1',
type: 'boolean'
},
{
name: 'Field2',
type: 'number'
},
{
name: 'Field3',
type: 'string'
}]
or if your fields are really just simple enums then:
[{
name: 'Field1',
id: 1
},
{
name: 'Field2',
id: 2
},
{
name: 'Field3',
id: 3
}]
That's my suggestion. Remember, there's no one right way to expose an API.
I am trying to do a domain availability search using an API from free domain API.
After i create an account, it shows:
**Make a REST request using this URL:**
http://freedomainapi.com/?key=11223344&domain=freedomainapi.com
And looking in the documentation page, it has only:
Request http://freedomainapi.com?key=YOUR_API_KEY&domain=DOMAIN_NAME
Result:
{
"status": "success",
"domain": "freedomainapi.com",
"available": false
}
I am very new to APIs...
What I need is to show a domain search box, and when the user enters, it should return with result.
It claims to show domain suggestions as well. I hope it will also work.
Using jquery and a jsonp proxy
http://jsfiddle.net/mp8pukbm/1/
$.ajax({
type: 'GET',
url: "https://jsonp.nodejitsu.com/?callback=?",
data: {url: 'http://freedomainapi.com?key=14ejhzc5h9&domain=freedomainapi.com'},
dataType: "jsonp",
success: myfn
});
function myfn(data) {
console.log(data);
}
you have to use the proxy because cross domain json is not permitted
EDIT:
i made an update to show the result in a div (stringified)
http://jsfiddle.net/mp8pukbm/2/
EDIT #2: i created a test key on that site, you have to use your own
EDIT #3: and there's your combo: http://jsfiddle.net/mp8pukbm/4/
Assuming that you will use java script for showing the search box, you can use AJAX feature of java script (or jQuery or Dojo) ... All you need to do is a "GET" request that like you can pasted and you will get the result back on the response object. To try out the API you can use "Postman" application in Chrome. https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en
In the response object of the AJAX call you will get a JSON object which you can parse and display the result.
Normally when we use REST we need to differentiate one REST call from another.
Assuming this url
http://freedomainapi.com/checkAvailability?key=YOUR_API_KEY&domain=DOMAIN_NAME
In Application layer we need to write an interface
#GET
#Path("/checkAvailability")
#Produces({MediaType.APPLICATION_JSON})
public ReturnObject getDomainAvailability(#QueryParam("key") String key,
#QueryParam("domain") String doaminName );
Once interface is done you need to write your implementation class.
This class will intract with business layer and perform search task and based on
result collected will create ReturnObject.
ReturnObject => will contain status, domain and availability
On screen
$.ajax({
type: "GET",
url: 'root/checkAvailability',
success: function(jsonData)
{
// read json and perform operation
}
,
error: function (error)
{
// handle error
}
});
If you are using JAVA as backend then you can use gson to parse the result, which is a json. After parsing you can read the values from result and display accordingly :)
Any API is a way to extend a given software. (Might be a website or an application)
In both ways there is a certain way to communicate with the software. In your example freedomainapi.com allows you to fetch if given domain is avaiable. There is no such thing as a suggestion tho, atleast i cannot find any suggestions at all.
Given output is a message format know as JSON. It can be easily interpreted by many major Languages such as Java, Javascript and PHP.
Given String might be easily interpreted as a Map consisting of a status (String), a domain (string) and avaiable (boolean)
A domain availability search could not be easier, assuming K is your key, D is your search input (Domain):
Download http://freedomainapi.com/checkAvailability?key=K&domain=D as input
Parse JSON from input as json
return json["status"] == "success" and json["avaiable"]
Depending on your language you might need to use methods to access properties of json, but that does not influence the basic usage of this api.
on user enters, it calls click_button function and I am assuming your result displaying div id is "main_container" you can give domain suggestions by passing related DOMAIN_NAME s as arguments to click_button function
function click_button(DOMAIN_NAME){
$.ajax({
url : 'http://freedomainapi.com?key=YOUR_API_KEY&domain=DOMAIN_NAME',
type: 'GET',
crossDomain: true,
contentType: "application/json; charset=utf-8",
success: function(data) {
data=JSON.parse(data);
if(data['available']){
$('#main_container').html($('#main_container').html()+'<br>'+DOMAIN_NAME+': Available');
else{
$('#main_container').html($('#main_container').html($('#main_container').html()+'<br>'+DOMAIN_NAME+': Not Available');
}//success
});//ajax
}
hope it helpful !
JavaScript
For example, I have the following JavaScript code (Dojo 1.6 is already loaded):
dojo.require("dojo.io.script")
// PART I
var jsonpArgs = {
url: "http://myapp.appspot.com/query",
content: {
id: "1234",
name: "Juan",
start_date: "2000-01-01",
callback: "recover"
}
};
// PART II
dojo.io.script.get(jsonpArgs).then(function(data) {
console.log(data);
});
// PART III
function recover(data) {
console.log(data);
}
Direct query from browser
I understand that my server will receive the query as though I typed the following into the address bar:
http://myapp.appspot.com/query?id=1234&name=Juan&start_date=2000-01-01&callback=recover
Expected response
If I directly queried my server using the browser address bar, I'll receive, in MIME type application/json and plaintext rendered in browser, something like this:
recover(
{
id: 1234,
name: Juan,
data: [
["2000-01-01", 1234],
["2000-01-02", 5678]
]
}
);
Problem
Now, looking back at Part II of the JavaScript, I'd execute the JSONP request with dojo.io.script.get(jsonpArgs). This returns a Deferred object, which I can take advantage of by chaining .then after it. Note that I defined the handler for the .then event to output that captured data to the console.
However, all I get in the console is an Event. I tried to search its data tree, but I could not find the data I expected.
Question
Where is the response for a JSONP request stored? How do I find it?
My server (which I control) only outputs a plaintext rendering of the data requested, wrapped in the callback function (here specified as recover), and specifies a application/json MIME type. Is there anything else I need to set up on my server, so that the response data is captured by the Deferred object?
Attempted solution
I can actually recover the response by defining the callback function (in this case recover in Part III of the JavaScript). However, in the Dojo tutorials, they just recovered the data using the Deferred (and .then) framework. How do I do it using Dojo Deferreds?
Update (using the Twitter example from Dojo tutorial)
Take for example this script from the Dojo tutorial, Getting Jiggy With JSONP. I edited it to log data to the console.
dojo.require("dojo.io.script");
dojo.io.script.get({
url: "http://search.twitter.com/search.json",
callbackParamName: "callback",
content: {q: "#dojo"}
}).then(function(data){
//we're only interested in data.results, so strip it off and return it
console.log(data); // I get an Object, not an Event, but no Twitter data when browsing the results property
console.log(data.results) // I get an array of Objects
return data.results;
});
For console.log(data), I get an Object, not an Event as illustrated by my case. Since the example implies that the data resides in data.results, I also try to browse this tree, but I don't see my expected data from Twitter. I'm at a loss.
For console.log(data.results), I get an array of Objects. If I query Twitter directly, this is what I'd get in plaintext. Each Object contains the usual tweet meta-data like username, time, user portrait, and the tweet itself. Easy enough.
This one hits me right on the head. The handler for the .then chain, an anonymous function, receives only one argument data. But why is it that the results property in console.log(data) and the returned object I get from console.log(data.results) are different?
I got it.
Manual callback implementation
function recover(data) {
console.log(data);
}
var jsonpArgs = {
url: "http://myapp.appspot.com/query",
content: {
id: "1234",
name: "Juan",
start_date: "2000-01-01",
callback: "recover"
};
dojo.io.script.get(jsonpArgs);
This is the request that my server will receive:
http://myapp.appspot.com/query?id=1234&name=Juan&start_date=2000-01-01&callback=recover
In this case, I'll expect the following output from my server:
recover({
id: 1234,
name: Juan,
data: [
["2000-01-01", 1234],
["2000-01-02", 5678]
]
});
Three things to note:
Server will expect callback in the query URL string. callback is implemented as a property of jsonpArgs.
Because I specified callback=recover, my server will attach recover( + the_data_I_need + ), returns the whole string to the browser, and browser will execute recover(the_data_I_need). This means...
That I'll have to define, for example, function recover(one_argument_only) {doAnythingYouWantWith(one_argument_only)}
The problem with this approach is that I cannot take advantage of Deferred chaining using .then. For example:
dojo.io.script.get(jsonpArgs).then(function(response_from_server) {
console.log(response_from_server);
})
This will give me an Event, with no trace of the expected response at all.
Taking advantage of Dojo's implementation of JSONP requests
var jsonpArgs = {
url: "http://myapp.appspot.com/query",
callbackParamName: "callback",
content: {
id: "1234",
name: "Juan",
start_date: "2000-01-01"
};
dojo.io.script.get(jsonpArgs);
This is the request that my server will receive:
http://myapp.appspot.com/query?id=1234&name=Juan&start_date=2000-01-01&callback=some_function_name_generated_by_dojo
In this case, I'll expect the following output from my server:
some_function_name_generated_by_dojo({
id: 1234,
name: Juan,
data: [
["2000-01-01", 1234],
["2000-01-02", 5678]
]
});
Things to note:
Note the property of jsonpArgs, callbackParamName. The value of this property must be the name of the variable (in the query URL string) expected by the server. If my server expects callbackfoo, then callbackParamName: "callbackfoo". In my case, my server expects the name callback, therefore callbackParamName: "callback".
In the previous example, I specified in the query URL callback=recover and proceeded to implement function recover(...) {...}. This time, I do not need to worry about it. Dojo will insert its own preferred function callback=some_function_name_generated_by_dojo.
I imagine some_function_name_generated_by_dojo to be defined as:
Definition:
function some_function_name_generated_by_dojo(response_from_server) {
return response_from_server;
}
Of course the definition is not that simple, but the advantage of this approach is that I can take advantage of Dojo's Deferred framework. See the code below, which is identical to the previous example:
dojo.io.script.get(jsonpArgs).then(function(response_from_server) {
console.log(response_from_server);
})
This will give me the exact data I need:
{
id: 1234,
name: Juan,
data: [
["2000-01-01", 1234],
["2000-01-02", 5678]
]
}