REST API: Should single API have multiple responsibilities? - api

We have classified goods website where we do not have login but users can view products listed by other users. To view details of other users, they have to provide their contact details. To verify if user has provided the correct mobile number, we send back OTP code to the number. The API flow looks like:
//API to be hit when user fills form to get seller details of particular stock (this expects "stockId" and "mobile" as input):
POST /api/lead/
{
"stockId": 123,
"mobile": 9890384328
}
Response of API if "mobile" is already verified (Response code: 200):
{
"sellerName": "xyz",
"sellerMobile": "+123232312",
"sellerAddress": "21, park street, new york"
}
Response if "mobile" is NOT already verified (Response code: 403):
{
"OTP verification required. OTP is sent to the mobile number."
}
User sends back request again with OTP received on mobile to the same lead API:
Request Payload:
{
"stockId": 123,
"mobile": 9890384328,
"otp": 1234
}
It sends back seller details in response if OTP is correct. If OTP
provided is not correct, the response is:
{
"Incorrect OTP."
}
I see few issues in this API design:
This API is doing lots of working i.e. returning back seller details, returning back OTP, verifying OTP etc. We can easily break OTP related functionality to some other API. For example one API to generate OTP i.e. GET /api/otp/, other API to verify OTP i.e. POST api/verifyotp/. This would increase number of API calls from client i.e first client will initiate POST lead API, if number is not verified, client will hit OTP API. To verify by OTP it will call verifyOTP api. If it gets verified, it will call leads API to fetch seller details. So, basically it makes 4 API calls vs 2 API calls in above approach.
This is non-complaint with HATEOS which suggests "A REST client enters a REST application through a simple fixed URL. All future actions the client may take are discovered within resource representations returned from the server."
Can someone suggest which approach is better?

Simple answer: no.
It is called single responsibility principle for a reason.
Allowing for more than one responsibility in the your public API means that the API "endpoint" has to understand the different responsibilities to "dispatch" to the "correct" implementation for each of these aspects. Or you allow your dual-responsibility API design to corrupt your implementation by having a single thing providing that implementation.
And beyond that: when you have different responsibilities, the range of OK/error return codes simply turns more complicated. That simply makes "everything" harder. For you to write tests - but also for the clients using your API.
In your case, the user does:
use /api/lead first
to be told about "not verified"
use OTP generation API to get the verification code
to then use a specific OTP API to submit verification code
to then use /api/lead again

Related

Is there a way to request Stripe for the cancellation reason of a subscription via API?

I am trying to query stripe for the cancellation reason of a subscription to feed this information into our CRM system.
The information I am looking for can be found in the dashboard here:
Stripe dashboard image
I found out that the browser sends a request to https://dashboard.stripe.com/v1/subscriptions/sub_xxx but with an API key that seems to belong to user request: uk_xxx. When I send a GET request to that endpoint with my API key sk_live_xxx I dont get the same data, i.e. the following information is missing:
{
"customer_portal_data": {
"cancellation_reason": "too_expensive",
"cancellation_reason_text": null
}
}
My question now: is there a way to query this information via the standard API from stripe?
This feature is only available in the Dashboard and Sigma right now and is not available via the API.

Generating Google Pay Token without UI

We have a use-case where we need to authorize a payment using a native payment on the web but use two different merchants. We want the user to press pay with Google and go through the ui but access google pay api with two different merchants. paymentsClient.loadPaymentData(paymentDataRequest).then(function(paymentData){ // if using gateway tokenization, pass this token without modification paymentToken = paymentData.paymentMethodData.tokenizationData.token; }).catch(function(err){ // show error in developer console for debugging console.error(err); });
is it possible to get the callback from this api request without a user interaction for the second request.

Identify unique user in Dialogflow V1

So I am testing out Dialogflow and one of the first questions I have is: how does my bot know who it is talking to? I need to identify a user and keep that information for as long as I can. The basic scenario being:
User starts his/her first conversation.
Chatbot send a fulfillment request to the server trying to match a user within its own database.
The user is found, the information (as a JWT or some other token) is sent back to Dialogflow and stored there for further communication. In reality, this part would involve asking for user email, sending a verification code to that email and then verifying the user with the code.
User then starts chatting with a bot and all fulfillment requests get the unique token stored for this very user, so that my REST API knows which user is being served with the response.
Couldn't find anything about it in the docs (maybe I am looking in the wrong places).
There will be several integrations, like Messenger, Viber, Telegram. I dunno, maybe those APIs add some unique information on the user?...
Thanks for the help!
Sorry, I know it's been a while, but maybe this will help someone else.
The right solution here is a user id, not a session id. A user id is provided by the chat platform (Facebook, Slack etc) and is consistent across sessions for the same user.
To get the user id, go to the Fulfillment tab, enable the editor and use a function like so:
let r = request.body.originalDetectIntentRequest
//this makes sure that you're on an integration
if (r["source"]){
return r.payload.data.sender.id;
}
To tie together ids from different platforms, you probably have to have some kind of log-in process every time you encounter a new id on a platform.
Pop,
Sessions are built in already into DialogFlow requests to your fulfilment service, if you check the payload you will find a sessionId, it remains the same for the same client until it expires.
However if you want to identify the user from any of the clients that you can connect to DialogFlow like Messenger then from the same request payload to you you will notice that there is an object named originalRequest that is only available when requests are coming from those clients.
You can personalize those users response eg using their FB firstname in a message to them.

Paypal Payments (Authorization & Capture) not returning Authorization ID

According to the documentation the paypal payment method should be able to do Authorization & Capture just fine. The following excerpt under the PayPal authorizations excerpt specifically states how to go about it:
First get payment approval and execute the payment as you normally would do for a PayPal payment. Once you successfully execute on the payment authorization, PayPal responds with a new set of HATEOAS links, including a capture link that you use to capture the payment.
So if im following correctly the flow for doing Authorize & Capture is as follows:
Create a Payment
Redirect User to HATEOAS link approval_url to get them to sign into paypal.
Be returned to success (or cancel, but not in this example) link.
Get the Payment to see what's changed, get the shipping address / etc....
Let the customer review the details
Execute The Payment to commit to the hold on funds.
At this point an AuthorizationID / HATEOAS Link should hold information about the authorization.
Some time later use the authorization ID to Capture, and voila, we're done.
Now this is all fine and dandy, but in my tests on the sandbox environment I'm having trouble retrieving the authorization ID anywhere.
Here's my HATEOAS Links I receive from my Execute Step:
As you can see, only the self reference is returned, according to the documentation there should be one capture link at the least that should have the authorizationID in it.
Also, nowhere in the response body is any authorization ID. However, If I look at the payment in my sandbox paypal dashboard:
And once I drill down into it:
Sure enough if I call the Authorization.Capture API call against 8B633793L37511009 it captures as you would expect. However I can't find a programmatic way to determine this number.
How am I supposed to store the authorization number so my tooling can capture later when our business conditions have been met?
In the beggining, when you create the payment with intent authorize you should be getting an authorization object within the response. This object has the id you need for the capture later.
Check this blog post to see if you're missing something fundamental in the picture.
I followed the tutorial and executed the sample requests via curl. As you can see, I got the authorization id under transactions->related resources->authorization->id
Then I used the id in the URL and successfully captured the payment.
Hope this helps, if it doesn't, please elaborate and maybe I will be able to help you further. Good luck!

Login and Verify with only phone number using Nexmo or Twilio

This is an authentication flow, which logs in the user with only the phone number provided (Whatsapp style). The Steps are:
User enters phone number and sent to server.
Server generated 4 digit random key, and save the pair (phone,key) in DB.
Server asks 3rd party SMS service to send key to phone.
SMS service sends message.
User enters the key from sms, and together with phone, sent to server.
Server checks the pair against the DB.
If pair exists, server sends back a token for further calls.
What I am trying to understand is where services like Twilio and Nexmo fit in (or replace parts of the flow).
From what I understand, looking at Nexmo for example,
I can replace steps 2 and 3 with an API call to:
https://api.nexmo.com/verify/
and save the request_id from the response in the DB as pair (phone,request_id).
And now, when the user enters a 4 digit code and sends it back,
I need to call:
https://api.nexmo.com/verify/check/json
providing it with request_id and code.
But where do I get the request_id?
Do the server needs to send it back to the client, the moment it gets it from Nexmo?
I can't see the benefits of using Nexmo here, what will it save me?
Answer to your first question: the request_id is part of the response to the first verify API call. See: https://docs.nexmo.com/index.php/verify/verify
As to what are the benefits of Nexmo here, I believe you have two options:
Generate your own code, use Nexmo to text it to your user, have the user submit the code back to your application, verify code against your own database.
Use Nexmo verify service to generate and send the code to the user, store the returned request_id in your db, have user submit code to your application, call Nexmo verify API to validate code.
In some ways the first option is easier as it is less API calls. However the benefit of the second option, using Nexmo Verify, is that they provide a whole lot more capabilities into the service to fall back to a voice call if SMS isn't working, filter out virtual phone numbers to prevent spam, you don't have to pay for failed SMS attempts, reporting/analytics, etc. etc.
Hopefully that helps a little.