AngularJS POST json to SilverStripe API - json

I wrote a pretty basic API using a SilverStripe module (here) and while building it I was testing using Postman and Advanced REST Client chrome extension so I know the endpoints work.
Now when trying to reach the endpoints (POST json) the API is telling me that required values aren't set. I'm did a little bit of digging and compared the request headers from Postman to the ones from Angular using Firebug. The only noticeable discrepancy is that in Postman the header for Content-Type is:
"application/json"
and for Angular it's:
"application/json; charset=UTF-8"
Here's the code for the Angular POST (pretty basic):
notebookFactory.addNotebook = function(title) {
var notebook = "Testing Title 23!";
var message = {
Title: notebook
};
return $http({
url: 'api/notebook',
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: message
});
};
The API error says: "The JSON property Title is required"
Is this something that could make a difference? I've tried adding charset=UTF-8 to the end of the Content-Type in Postman and receive the same error. Is there any way to remove the charset from the Angular POST header?
Let me know if you need any more info and thanks in advance!

This was a small issue with the code for handling json in the RESTful API module.
The developer has made the fix already and can be referenced here: https://github.com/pstaender/silverstripe-restful-api/issues/1

Related

How to allow Cors Headers in Google AppScript for making an XMLHttpRequest?

I have created a doGet and doPost endpoints in my appscript. When I hit the endpoint to make a post request from Python, it does work perfectly and as expected.
But when I try to hit the same url with my Flutter based mobile App, it throws me an XML error. (Which I suspect is related to CORSING).
When I hit the url with get request, I get the right response, but post request is failing. To ensure that my Post request is properly configured, I have made a post request to public API and it worked like charm.
Is it possible to add headers, where I could enable cors like this:
allowHeaders = {
"Access-Control-Allow-Origin": "*", // Required for CORS support to work
"Access-Control-Allow-Credentials": true, // Required for cookies, authorization headers with HTTPS
"Access-Control-Allow-Headers": "Origin,Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,locale",
"Access-Control-Allow-Methods": "POST, OPTIONS"
}
Here is what my doPost request returns:
ContentService.createTextOutput(JSON.stringify(
{
data: isAuthenticated.data,
error: true,
//request: request,
msg: query.apiKey,
//paramters:request.parameters
})).setMimeType(ContentService.MimeType.JSON)
Here is my python script to get the post response:
requests.post("https://script.google.com/macros/s/AKfycbz7kTROol8u509M_p9pMZ9XRnL-myVjcRQKeb9Etp_OIMPnH640vHf_0Jp2dvvrbto7kOg/exec",
json = requestObject)
And here is my Flutter function:
Future<http.Response> createAlbum() async{
print("Trying to make a post request");
var result = await http.post(Uri.parse('https://script.google.com/macros/s/AKfycbz7kTROol8u509M_p9pMZ9XRnL-myVjcRQKeb9Etp_OIMPnH640vHf_0Jp2dvRIco7kOg/exec'),
headers: {"Content-Type": "application/json"},
body: jsonEncode(<String, dynamic>{
"apiKey":apiKey,
"operationType":"register_user",
"operationData": {
"email": "shivam#yoptima.com",
"otp": 318728
}
}),
);
print("Here is the result: " + result.body);
}
Just to clarify things:
Get Request works for both the platforms.
Post Request works with python for AppScript.
Post Request works for any other public API from flutter.
Post Request doesn't work for Flutter when Hitting AppScript API.
I suspect it to be something to do with CORS. (But not very sure).
Flutter http library makes request via XMLHttpRequest.

Scraping - catch json response with python

I need to scrape a website with a "load more" button.
I need to catch the json response (which is invisible in the html code) and parse it to build URLs
This is the JSON post request response
I'm using Selenium, python.
how do I ?
tHX
You can bypass actually clicking on the "load more" button by reading the API call that the website is sending when you click the button and then sending it via Selenium. If you send it through Selenium, you can capture the response. Here's what I've been using an Angular website. You'll have to modify it to work with the website you're using, but this should get you started.
call = """
$http = angular.element(document.body).injector().get('$http');
var done = arguments[0];
$http({
method: 'POST',
headers: {
"Content-Type": "application/json"
},
data: {
foo: "bar"
},
url: "https://request.url/"
}).then(data => done(data));
"""
json_response = driver.execute_async_script(call)
The execute_async_script method will make the call and wait for a JSON response.
You can also right-click on the xhr in Chrome DevTools and copy the API call, which should make it easier to recreate it with selenium.
Let me know if you have follow-up questions.

StackExchange API authentication in Google Apps Script

I'm trying to use the V2.2 of StackExchange API in Google Apps Script.
The problem comes in the last step of the explicit OAuth 2.0 flow, when I try to send the POST request to obtain the access token. I receive a 404 error, but making the same request manually (using postman extension) everything is ok.
To simplify the problem, if I send this POST request with no payload I receive the same 404
var response = UrlFetchApp.fetch("https://stackexchange.com/oauth/access_token", {
method: 'post',
muteHttpExceptions: true
});
Logger.log(response);
while in postman I receive this 400:
{
"error": {
"type": "invalid_request",
"message": "client_id not provided"
}
}
I guess this will be a problem with UrlFetchApp, but does anyone know how to solve it? Thanks!
The problem is related with the Origin header.
You cannot remove from the header directly but you can perform the call via a proxy :)
You need to provide the data for the post by adding an 'option' object to the call.
For example:
var options = { "method" : "post", "payload" : payload };
UrlFetchApp.fetch("https://stackexchange.com/oauth/access_token", options);
Btw, have you tried you use the OAuth that UrlFetch got: https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app#addOAuthService(String) - It might be better way.

How can i pass an object and a string to webservice using post request using angularjs

Am very new to angularjs and i need to post data to a web service, the service accepts two parameters, one is List of object and the other is securityToken,
Here is my code,
$scope.saveCompany=function(){
// alert("Save Company!!!");
var Companies={
Code: 'testMartin',
Name: 'company1',
CompanyType : 'Tenant',
email : 'test#yaoo.com',
Fax : 4235353,
ParentID : 1
};
$http({
url:'http://localhost/masters/smstools.svc/json/SaveComapnies',
dataType: 'json',
method: 'POST',
data: $.param(Companies),
headers: {
"Content-Type": "text/json",
}
}).success(function(response){
alert ("Success");
}).error(function(error){
alert ("Save company!");
});
how can i pass the security token with the companies object as a separate paramenter. my service accepts the parameters like this,
public List<CompanyProfile> Save(List<CompanyProfile> CompanyList,string securityToken)
Since this is a rest call you only have 3 places were you can pass parameters data:
With Post and it will be part of the body, it seems this is what is your first parameter is occupying now.
With Get and you add the parameter to the URL /json/SaveComapnies/mySecParam or by queryString like /json/SaveComapnies?sec=mySecParam but this is not secure nor recommended for security settings.
With header from angular Post:
**headers: {
"Content-Type": "text/json",
"mySecVar": "mySecParamValue"
}**
Server side version:
public List<CompanyProfile> Save(List<CompanyProfile> CompanyList){
WebOperationContext current = WebOperationContext.Current;
WebHeaderCollection headers = current.IncomingRequest.Headers;
if (headers["mySecVar"] != null){
// do something
}
}
You can read more about it here:
How to read HTTP request headers in a WCF web service?
Can you share more information in your Backend?
If it is actually a REST Backend I would rather use an angular $resource
https://docs.angularjs.org/api/ngResource
If you want to pass json object and string as post Parameter you should stick to the $http docs
https://docs.angularjs.org/api/ng/service/$http
In the post example you can pass both params in:
$http.post('/yourEndpoint', {jsonObj:yourCompaniesObj, secKey:yourSecretToken})....(sucess etc)
Typing from my cell - if you need more code examples just tell

how to return json format from ODATA?

I know ODATA can return json but not sure if I have to use an attribute or interface to do so.
I want it to do just like http://odata.netflix.com/Catalog/Titles?$format=JSON but my odata service doesn't return JSON. When I call it like www.foo.com/service?$format=json, it just returns XML.
What do I need to do to return json with ODATA?
Download and install Fiddler.
http://www.fiddler2.com/fiddler2/
Once installed, open it, click on the "Request Builder" tab located in the right side of Fiddler.
Insert this URL:
http://test.com/feed2/ODataService.svc/results
Note that you DO NOT NEED THE ?$format=JSON
In the "Request Headers" section, insert the following line:
accept: application/json
Hit the Big "Execute" button at the top right of Fiddler.
You'll see the results of the request added to the list on the left side of Fiddler.
Double click on the request. The right side of Fiddler will change to the "Inspectors" tab where you can see the results of your request.
Also, since you are working with Json, you probably want to download and install the Json viewer plugin for Fiddler:
http://jsonviewer.codeplex.com/
Newer versions of WCF Data Services support JSON by default and you must have
Accept: application/json;odata=verbose
in the request header.
Accept: application/json
is no longer sufficient. More info here.
No-one seems to be answering your question very cleanly here!
From an HTML page you can use the following Javascript / JQuery code to have a WCF Data Service return data in JSON format;
<script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script language="javascript" type="text/javascript">
var sURL = "http://YourService.svc/Books(10)";
function testJSONfetch() {
$.ajax({
type: "GET",
contentType: "application/json; charset=utf-8",
datatype: "json",
url: sURL,
error: bad,
success: good,
beforeSend: function (XMLHttpRequest) {
//Specifying this header ensures that the results will be returned as JSON.
XMLHttpRequest.setRequestHeader("Accept", "application/json");
}
});
}
function good(response)
{
}
function bad(response)
{
}
</script>
You need to add “Accept: application/json” into the request header section.
Check out this link
If you're using the ODATA provider from Data Services you can easily return ODATA as JSON by specifying it in the URL as in the sample you gave - http://odata.netflix.com/Catalog/Titles?$format=JSON
To do this use the JSONp and URL-controlled format support for ADO.NET Data Services download from MSDN http://code.msdn.microsoft.com/DataServicesJSONP and add the JSONPSupportBehavior decorator to your DataService class like below.
[JSONPSupportBehavior]
public class MyDataService : DataService<MyContextType>
{
...
"...but I get "The webpage cannot be found" using http://test.com/feed2/ODataService.svc/results?$format=JSON ..."
you dont need the $format=JSON in the Uri.
Just use "http://test.com/feed2/ODataService.svc/results"
(with Accept: application/json in the request header)
Late answer, but I've been spending the last hour trying to figure out how to curl OData APIs and return the result as json. The following code fetches the document in json and writes it to a file:
-o myfile.html -H "Accept: application/json" http://example.com/api/data?$filter=name eq 'whatever'
... just use lower case letters:
"format=json"
It's not pretty but this is how I forced JSON output without using $format in the request string:
Request r = new Request(Method.GET, "http://XXXXXXX.svc//Login"
+ "&UserId=" + "'" + "user" + "'"
+ "&Password=" + "'" + "password" + "'");
ClientInfo ci = r.getClientInfo();
ArrayList<Preference<MediaType>> accepted = new ArrayList<Preference<MediaType>>();
accepted.add(new Preference<MediaType>(MediaType.APPLICATION_JSON));
ci.setAcceptedMediaTypes(accepted);
Client client = new Client(Protocol.HTTP);
Response response = client.handle(r);
Representation output = response.getEntity();