the github API sends the pagination data for the json results in the http link header:
Link: <https://api.github.com/repos?page=3&per_page=100>; rel="next",
<https://api.github.com/repos?page=50&per_page=100>; rel="last"
since the github API is not the only API using this method (i think) i wanted to ask if someone has a useful little snippet to parse the link header (and convert it to an array for example) so that i can use it for my js app.
i googled around but found nothing useful regarding how to parse pagination from json APIs
The parse-link-header NPM module exists for this purpose; its source can be found on github under a MIT license (free for commercial use).
Installation is as simple as:
npm install parse-link-header
Usage looks like the following:
var parse = require('parse-link-header');
var parsed = parse('<https://api.github.com/repos?page=3&per_page=100>; rel="next", <https://api.github.com/repos?page=50&per_page=100>; rel="last"')
...after which one has parsed.next, parsed.last, etc:
{ next:
{ page: '3',
per_page: '100',
rel: 'next',
url: 'https://api.github.com/repos?page=3&per_page=100' },
last:
{ page: '50',
per_page: '100',
rel: 'last',
url: ' https://api.github.com/repos?page=50&per_page=100' } }
There is a PageLinks class in the GitHub Java API that shows how to parse the Link header.
I found this Gist that:
Parse Github Links header in JavaScript
Tested it out on the Github API and it returns an object like:
var results = {
last: "https://api.github.com/repositories/123456/issues?access_token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&state=open&since=2013-07-24T02%3A12%3A30.309Z&direction=asc&page=4"
next: "https://api.github.com/repositories/123456/issues?access_token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&state=open&since=2013-07-24T02%3A12%3A30.309Z&direction=asc&page=2"
};
I found wombleton/link-headers on github. It appears to be made for the browser, as opposed to being an npm module, but it seems like it wouldn't be hard to modify it to work in a server-side environment. It uses pegjs to generate a real RFC 5988 parser rather than string splits, so it should work well for any link header, rather than just Github's.
I completely understand this is "technically" a JavaScript thread. But, if you're like me and arrived here by Google'ing "how to parse Link header" I thought I'd share my solution for my envinronment (C#).
public class LinkHeader
{
public string FirstLink { get; set; }
public string PrevLink { get; set; }
public string NextLink { get; set; }
public string LastLink { get; set;}
public static LinkHeader FromHeader(string linkHeader)
{
LinkHeader linkHeader = null;
if (!string.IsNullOrWhiteSpace(linkHeader))
{
string[] linkStrings = linkHeader.Split("\",");
if (linkStrings != null && linkStrings.Any())
{
linkHeader = new LinkHeader();
foreach (string linkString in linkStrings)
{
var relMatch = Regex.Match(linkString, "(?<=rel=\").+?(?=\")", RegexOptions.IgnoreCase);
var linkMatch = Regex.Match(linkString, "(?<=<).+?(?=>)", RegexOptions.IgnoreCase);
if (relMatch.Success && linkMatch.Success)
{
string rel = relMatch.Value.ToUpper();
string link = linkMatch.Value;
switch (rel)
{
case "FIRST":
linkHeader.FirstLink = link;
break;
case "PREV":
linkHeader.PrevLink = link;
break;
case "NEXT":
linkHeader.NextLink = link;
break;
case "LAST":
linkHeader.LastLink = link;
break;
}
}
}
}
}
return linkHeader;
}
}
Testing in a console app, using GitHub's example Link header:
void Main()
{
string link = "<https://api.github.com/user/repos?page=3&per_page=100>; rel=\"next\",< https://api.github.com/user/repos?page=50&per_page=100>; rel=\"last\"";
LinkHeader linkHeader = LinkHeader.FromHeader(link);
}
Here is a simple javascript function that extracts the useful info from the link in a nice object notation.
var linkParser = (linkHeader) => {
let re = /<([^\?]+\?[a-z]+=([\d]+))>;[\s]*rel="([a-z]+)"/g;
let arrRes = [];
let obj = {};
while ((arrRes = re.exec(linkHeader)) !== null) {
obj[arrRes[3]] = {
url: arrRes[1],
page: arrRes[2]
};
}
return obj;
}
It will output the result like this ==>
{
"next": {
"url": "https://api.github.com/user/9919/repos?page=2",
"page": "2"
},
"last": {
"url": "https://api.github.com/user/9919/repos?page=10",
"page": "10"
}
}
If you can use Python and don't want to implement full specification, but need to have something what work for Github API, then here we go:
import re
header_link = '<https://api.github.com/repos?page=3&per_page=100>; rel="next", <https://api.github.com/repos?page=50&per_page=100>; rel="last"'
if re.search(r'; rel="next"', header_link):
print re.sub(r'.*<(.*)>; rel="next".*', r'\1', header_link)
Here's a simple bash script with curl and sed to get all pages from a long query
url="https://api.github.com/repos/$GIT_USER/$GIT_REPO/issues"
while [ "$url" ]; do
echo "$url" >&2
curl -Ss -n "$url"
url="$(curl -Ss -I -n "$url" | sed -n -E 's/Link:.*<(.*?)>; rel="next".*/\1/p')"
done > issues.json
For someone who ended up here searching for Link Header Parser in Java, you can use javax.ws.rs.core.Link. Refer below for example:
import javax.ws.rs.core.Link
String linkHeaderValue = "<https://api.github.com/repos?page=3&per_page=100>; rel='next'";
Link link = Link.valueOf(linkHeaderValue);
Instead of using the original parse-link-header package, another option would be #web3-storage/parse-link-header. It's the forked version of the original NPM package. The API is the same but it comes with advantages like:
TypeScript support
Zero dependencies
No Node.js globals and ESM
Installation:
npm install #web3-storage/parse-link-header
Usage:
import { parseLinkHeader } from '#web3-storage/parse-link-header'
const linkHeader =
'<https://api.github.com/user/9287/repos?page=3&per_page=100>; rel="next", ' +
'<https://api.github.com/user/9287/repos?page=1&per_page=100>; rel="prev"; pet="cat", ' +
'<https://api.github.com/user/9287/repos?page=5&per_page=100>; rel="last"'
const parsed = parseLinkHeader(linkHeader)
console.log(parsed)
Output:
{
"next":{
"page":"3",
"per_page":"100",
"rel":"next",
"url":"https://api.github.com/user/9287/repos?page=3&per_page=100"
},
"prev":{
"page":"1",
"per_page":"100",
"rel":"prev",
"pet":"cat",
"url":"https://api.github.com/user/9287/repos?page=1&per_page=100"
},
"last":{
"page":"5",
"per_page":"100",
"rel":"last",
"url":"https://api.github.com/user/9287/repos?page=5&per_page=100"
}
}
Here is a Python solution to get contributors count for any github repo.
import requests
from urllib.parse import parse_qs
rsp = requests.head('https://api.github.com/repos/fabric8-analytics/fabric8-analytics-server/contributors?per_page=1')
contributors_count = parse_qs(rsp.links['last']['url'])['page'][0]
Here is a simple code to parse link header from GitHub in Java Script
var parse = require('parse-link-header');
var parsed = parse(res.headers.link);
no_of_pages = parsed.last.page;
This is a Java function which will serve the purpose, you can find a link for the provided parameter key and parameter value.
Please Note: This is something that I made for personal purpose, it might not be fool proof for your scenario, so review it and make changes accordingly
https://github.com/akshaysom/LinkExtract/blob/main/LinkExtract.java
public static String getLinkFromLinkHeaderByParamAndValue(String header, String param, String value) {
if (header != null && param != null && value != null && !"".equals(header.trim()) && !"".equals(param.trim())
&& !"".equals(value)) {
String[] links = header.split(",");
LINKS_LOOP: for (String link : links) {
String[] segments = link.split(";");
if (segments != null) {
String segmentLink = "";
SEGMENT_LOOP: for (String segment : segments) {
segment = segment.trim();
if (segment.startsWith("<") && segment.endsWith(">")) {
segmentLink = segment.substring(1, segment.length() - 1);
continue SEGMENT_LOOP;
} else {
if (segment.split("=").length > 1) {
String currentSegmentParam = segment.split("=")[0].trim();
String currentSegmentValue = segment.split("=")[1].trim();
if (param.equals(currentSegmentParam) && value.equals(currentSegmentValue)) {
return segmentLink;
}
}
}
}
}
}
}
return null;
}
Related
I have a python list called "devices" that looks something like this:
[{
'Version': 'V14E',
'DeviceID': 'e00fce68281671574f416a8c',
'TerminationDate': '2050-12-31',
'Latitude': 31.322139613573903,
'ActivationDate': '2021-01-04',
'Longitude': -101.93960164357534,
'DeviceName': 'Hans_Gruber-1'
}, {
'Version': 'V14E',
'DeviceID': 'e00fce68e1265e12e12fa02a',
'TerminationDate': '2050-12-31',
'Latitude': 31.32151602493975,
'ActivationDate': '2021-01-04',
'Longitude': -101.93948944894449,
'DeviceName': 'Hans_Gruber-2'
}]
In my flask app, I pass this list to my html file by the name "devices_test" using json.dumps() to correctly format the data to be used in java script.
return render_template("json_form.html",
devices = devices, components = components, operator = operator, name = site_name,
devices_test = json.dumps(devices))
Here is me trying to test out an answer I have seen on another post here via the "data" variable:
function update_device_form(strDevice) {
var data = {
{
devices_test | safe
}
};
var device_index = document.getElementById("devices").selectedIndex;
if (device_index == 0) { //IOW if no device is selected
document.getElementById("device_id").value = "";
} else {
document.getElementById("device_id").value = '';
}
But I get errors such as "Declaration or statement expected" and "Property assignment expected" and "',' expected". What am I doing wrong here?
You can use string to remove the error var data = "{{devices_test|safe}}"
Now data is not javascript object, it is a string, you need to use JSON.parse and also replaceAll.
var data = "{{devices_test|safe}}"
var data = data.replaceAll("'",'"') // replace single quote to double
var data = JSON.parse(data)
one line
var data = JSON.parse("{{devices_test|safe}}".replaceAll("'",'"'))
I'm trying to use the new Fetch API:
I am making a GET request like this:
var request = new Request({
url: 'http://myapi.com/orders',
method: 'GET'
});
fetch(request);
However, I'm unsure how to add a query string to the GET request. Ideally, I want to be able to make a GET request to a URL like:
'http://myapi.com/orders?order_id=1'
In jQuery I could do this by passing {order_id: 1} as the data parameter of $.ajax(). Is there an equivalent way to do that with the new Fetch API?
A concise, modern approach:
fetch('https://example.com?' + new URLSearchParams({
foo: 'value',
bar: 2,
}))
How it works: When a string (e.g. the URL) is being concatenated with an instance of URLSearchParams, its toString() method will automatically be called to convert the instance into a string representation, which happens to be a properly encoded query string. If the automatic invoking of toString() is too magical for your liking, you may prefer to explicitly call it like so: fetch('https://...' + new URLSearchParams(...).toString())
A complete example of a fetch request with query parameters:
// Real example you can copy-paste and play with.
// jsonplaceholder.typicode.com provides a dummy rest-api
// for this sort of purpose.
async function doAsyncTask() {
const url = (
'https://jsonplaceholder.typicode.com/comments?' +
new URLSearchParams({ postId: 1 }).toString()
);
const result = await fetch(url)
.then(response => response.json());
console.log('Fetched from: ' + url);
console.log(result);
}
doAsyncTask();
If you are using/supporting...
IE: Internet Explorer does not provide native support for URLSearchParams or fetch, but there are polyfills available.
Node: As of Node 18 there is native support for the fetch API (in version 17.5 it was behind the --experimental-fetch flag). In older versions, you can add the fetch API through a package like node-fetch. URLSearchParams comes with Node, and can be found as a global object since version 10. In older version you can find it at require('url').URLSearchParams.
Node + TypeScript: If you're using Node and TypeScript together you'll find that, due to some technical limitations, TypeScript does not offer type definitions for the global URLSearchParams. The simplest workaround is to just import it from the url module. See here for more info.
Update March 2017:
URL.searchParams support has officially landed in Chrome 51, but other browsers still require a polyfill.
The official way to work with query parameters is just to add them onto the URL. From the spec, this is an example:
var url = new URL("https://geo.example.org/api"),
params = {lat:35.696233, long:139.570431}
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]))
fetch(url).then(/* … */)
However, I'm not sure Chrome supports the searchParams property of a URL (at the time of writing) so you might want to either use a third party library or roll-your-own solution.
Update April 2018:
With the use of URLSearchParams constructor you could assign a 2D array or a object and just assign that to the url.search instead of looping over all keys and append them
var url = new URL('https://sl.se')
var params = {lat:35.696233, long:139.570431} // or:
var params = [['lat', '35.696233'], ['long', '139.570431']]
url.search = new URLSearchParams(params).toString();
fetch(url)
Sidenote: URLSearchParams is also available in NodeJS
const { URL, URLSearchParams } = require('url');
let params = {
"param1": "value1",
"param2": "value2"
};
let query = Object.keys(params)
.map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k]))
.join('&');
let url = 'https://example.com/search?' + query;
fetch(url)
.then(data => data.text())
.then((text) => {
console.log('request succeeded with JSON response', text)
}).catch(function (error) {
console.log('request failed', error)
});
As already answered, this is per spec not possible with the fetch-API, yet. But I have to note:
If you are on node, there's the querystring package. It can stringify/parse objects/querystrings:
var querystring = require('querystring')
var data = { key: 'value' }
querystring.stringify(data) // => 'key=value'
...then just append it to the url to request.
However, the problem with the above is, that you always have to prepend a question mark (?). So, another way is to use the parse method from nodes url package and do it as follows:
var url = require('url')
var data = { key: 'value' }
url.format({ query: data }) // => '?key=value'
See query at https://nodejs.org/api/url.html#url_url_format_urlobj
This is possible, as it does internally just this:
search = obj.search || (
obj.query && ('?' + (
typeof(obj.query) === 'object' ?
querystring.stringify(obj.query) :
String(obj.query)
))
) || ''
You can use stringify from query-string.
import { stringify } from 'query-string';
fetch(`https://example.org?${stringify(params)}`)
encodeQueryString — encode an object as querystring parameters
/**
* Encode an object as url query string parameters
* - includes the leading "?" prefix
* - example input — {key: "value", alpha: "beta"}
* - example output — output "?key=value&alpha=beta"
* - returns empty string when given an empty object
*/
function encodeQueryString(params) {
const keys = Object.keys(params)
return keys.length
? "?" + keys
.map(key => encodeURIComponent(key)
+ "=" + encodeURIComponent(params[key]))
.join("&")
: ""
}
encodeQueryString({key: "value", alpha: "beta"})
//> "?key=value&alpha=beta"
I know this is stating the absolute obvious, but I feel it's worth adding this as an answer as it's the simplest of all:
const orderId = 1;
fetch('http://myapi.com/orders?order_id=' + orderId);
Maybe this is better:
const withQuery = require('with-query');
fetch(withQuery('https://api.github.com/search/repositories', {
q: 'query',
sort: 'stars',
order: 'asc',
}))
.then(res => res.json())
.then((json) => {
console.info(json);
})
.catch((err) => {
console.error(err);
});
Solution without external packages
to perform a GET request using the fetch api I worked on this solution that doesn't require the installation of packages.
this is an example of a call to the google's map api
// encode to scape spaces
const esc = encodeURIComponent;
const url = 'https://maps.googleapis.com/maps/api/geocode/json?';
const params = {
key: "asdkfñlaskdGE",
address: "evergreen avenue",
city: "New York"
};
// this line takes the params object and builds the query string
const query = Object.keys(params).map(k => `${esc(k)}=${esc(params[k])}`).join('&')
const res = await fetch(url+query);
const googleResponse = await res.json()
feel free to copy this code and paste it on the console to see how it works!!
the generated url is something like:
https://maps.googleapis.com/maps/api/geocode/json?key=asdkf%C3%B1laskdGE&address=evergreen%20avenue&city=New%20York
this is what I was looking before I decided to write this, enjoy :D
Template literals are also a valid option here, and provide a few benefits.
You can include raw strings, numbers, boolean values, etc:
let request = new Request(`https://example.com/?name=${'Patrick'}&number=${1}`);
You can include variables:
let request = new Request(`https://example.com/?name=${nameParam}`);
You can include logic and functions:
let request = new Request(`https://example.com/?name=${nameParam !== undefined ? nameParam : getDefaultName() }`);
As far as structuring the data of a larger query string, I like using an array concatenated to a string. I find it easier to understand than some of the other methods:
let queryString = [
`param1=${getParam(1)}`,
`param2=${getParam(2)}`,
`param3=${getParam(3)}`,
].join('&');
let request = new Request(`https://example.com/?${queryString}`, {
method: 'GET'
});
Was just working with Nativescript's fetchModule and figured out my own solution using string manipulation.
Append the query string bit by bit to the url. Here is an example where query is passed as a json object (query = {order_id: 1}):
function performGetHttpRequest(fetchLink='http://myapi.com/orders', query=null) {
if(query) {
fetchLink += '?';
let count = 0;
const queryLength = Object.keys(query).length;
for(let key in query) {
fetchLink += key+'='+query[key];
fetchLink += (count < queryLength) ? '&' : '';
count++;
}
}
// link becomes: 'http://myapi.com/orders?order_id=1'
// Then, use fetch as in MDN and simply pass this fetchLink as the url.
}
I tested this over a multiple number of query parameters and it worked like a charm :)
Hope this helps someone.
var paramsdate=01+'%s'+12+'%s'+2012+'%s';
request.get("https://www.exampleurl.com?fromDate="+paramsDate;
I am having issues retrieving parameters from my URL that is an API. Any
help would be greatly appreciated.
Here is my c# code
[Route("api/[controller]")]
public class PasswordController : Controller
{
private readonly AppSettings _options;
public PasswordController(IOptions<AppSettings> optionsAccessor)
{
_options = optionsAccessor.Value;
}
[HttpGet]
//this isnt returning anything...
public IActionResult Get([FromQuery]string emp)
{
var x = HttpContext.Request.Query["emp"].ToString();
Response.Headers.Add("x-emp-name", x);
return Json(_options.ClientSettings);
}
Here is my angular code ts
private GetData(): void {
this.http.get('api/password').subscribe(values => {
this.ViewOptions = values.json();
this.titleService.setTitle(this.ViewOptions.changePasswordTitle + " -
" + this.ViewOptions.applicationTitle);
if (this.ViewOptions.recaptcha.isEnabled) {
this.FormGroup.addControl('reCaptcha', new FormControl('',
[Validators.required]));
const sp = document.createElement('script');
sp.type = 'text/javascript';
sp.async = true;
sp.defer = true;
sp.src =
'https://www.google.com/recaptcha/api.js?onload=vcRecaptchaApiLoaded&render=explicit&hl='
+ this.ViewOptions.recaptcha.languageCode;
}
});
}
Here is my browser console screenshot
You can pass a parameter into your method:
private GetData(queryParam): void {
this.http.get('api/password?emp=' + queryParam).subscribe(values => {
this.ViewOptions = values.json();
///code omitted
note: I don't know the exact syntax for TypeScript parameters so this probably isn't copy/paste-able.
So as I understand your question, you try to call the api/password endpoint with the get parameter ?emp=Test from within an angular web app.
As I see you don't call the endpoint with the parameter but call the whole angular app with the parameter. So my suggestion was to call
this.http.get('api/password?emp=Test').subscribe
from the typescript code.
There is a webpage I am trying to extract data from. By looking at the HTML in the page Source, I can find the data I am interested inside script tags.
It looks like the following:
<html>
<script type="text/javascript">
window.gon = {};
gon.default_profile_mode = false;
gon.user = null;
gon.product = "shoes";
gon.books_jsonarray = [
{
"title": "Little Sun",
"authors": [
"John Smith"
],
edition: 2,
year: 2009
},
{
"title": "Little Prairie",
"authors": [
"John Smith"
],
edition: 3,
year: 2009
},
{
"title": "Little World",
"authors": [
"John Smith",
"Mary Neil",
"Carla Brummer"
],
edition: 3,
year: 2014
}
];
</script>
</html>
What I would like to achieve is, call the webpage by using its url, then retrieving the 'gon' variable from JavaScript and store it in a C# variable. In other words, in C#, I would like to have a data structure (a dictionary for instance) that would hold the value of 'gon'.
I have tried researching how to get a variable defined in JavaScript via C# WebBrowser, and this is what I found:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Net;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using mshtml;
namespace Mynamespace
{
public partial class Form1 : Form
{
public WebBrowser WebBrowser1 = new WebBrowser();
private void Form1_Load(object sender, EventArgs e)
{
string myurl = "http://somewebsite.com"; //Using WebBrowser control to load web page
this.WebBrowser1.Navigate(myurl);
}
private void btnGetValueFromJs_Click(object sender, EventArgs e)
{
var mydoc = this.WebBrowser1.Document;
IHTMLDocument2 vDocument = mydoc.DomDocument as IHTMLDocument2;
IHTMLWindow2 vWindow = (IHTMLWindow2)vDocument.parentWindow;
Type vWindowType = vWindow.GetType();
object strfromJS = vWindowType.InvokeMember("mystr",
BindingFlags.GetProperty, null, vWindow, new object[] { });
//Here, I am able to see the string "Hello Sir"
object gonfromJS = vWindowType.InvokeMember("gon",
BindingFlags.GetProperty, null, vWindow, new object[] { });
//Here, I am able to see the object gonfromJS as a '{System.__ComObject}'
object gonbooksfromJS = vWindowType.InvokeMember("gon.books_jsonarray",
BindingFlags.GetProperty, null, vWindow, new object[] { });
//This error is thrown: 'An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in mscorlib.dll; (Exception from HRESULT: 0x80020006 (DISP_E_UNKNOWNNAME))'
}
}
}
I am able to retrieve values of string or number variables such as:
var mystr = "Hello Sir";
var mynbr = 8;
However, even though I am able to see that the 'gon' variable is being passed as a '{System.__ComObject}', I don't know how to parse it in order to see the values of its sub components. It would be nice if I could parse it, but if not, what I would like to have instead, is a C# Data Structure with keys/values that contains all the sub infos for the gon variable, and especially, be able to view the variable 'gon.books_jsonarray'.
Any help on how to achieve this would be very much appreciated. Note that I cannot change the source html/javascript in anyway, and so, what I need is a C# code that would allow to reach my goal.
You can cast the result of InvokeMember() to dynamic and use the property names directly in your C# code. Array indexing is tricky but can be done with another use of InvokeScript(), see my example:
private void btnGetValueFromJs_Click(object sender, EventArgs e)
{
var mydoc = this.WebBrowser1.Document;
IHTMLDocument2 vDocument = mydoc.DomDocument as IHTMLDocument2;
IHTMLWindow2 vWindow = (IHTMLWindow2)vDocument.parentWindow;
Type vWindowType = vWindow.GetType();
var gonfromJS = (dynamic)vWindowType.InvokeMember("gon",
BindingFlags.GetProperty, null, vWindow, new object[] { });
var length = gonfromJS.books_jsonarray.length;
for (var i = 0; i < length; ++i)
{
var book = (dynamic) mydoc.InvokeScript("eval", new object[] { "gon.books_jsonarray[" + i + "]" });
Console.WriteLine(book.title);
/* prints:
* Little Sun
* Little Prairie
* Little World
*/
}
}
You need to use JSON.stringify to convert your gon.books_jsonarray variable to JSON string
After you can retrive JSON using next C# code:
var gonFromJS = mydoc.InvokeScript("eval", new object[] { "JSON.stringify(gon.books_jsonarray)" }).ToString();
After you can deserialize JSON to object using Newtonsoft.Json
My full code is here:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
var webBrowser = new WebBrowser();
webBrowser.DocumentCompleted += (s, ea) =>
{
var mydoc = webBrowser.Document;
var gonFromJS = mydoc.InvokeScript("eval", new object[] { "JSON.stringify(gon.books_jsonarray)" }).ToString();
var gonObject = JsonConvert.DeserializeObject<List<Books>>(gonFromJS);
};
var myurl = "http://localhost/test.html";
webBrowser.Navigate(myurl);
}
private class Books
{
public string Title { get; set; }
public List<string> Authors { get; set; }
public int Edition { get; set; }
public int Year { get; set; }
}
}
}
Also you can see output on screenshot:
EDIT:
Also you can have a trouble with JSON.stringify method.
It can returns null.
In this case you can review SO topics: here and here.
If JSON.stringify method returns null then try to add next code to your HTML page:
<head>
<meta http-equiv='X-UA-Compatible' content='IE=edge' >
</head>
First off, I'll acknowledge there are lots of questions close to my one here, but having tried every solution I can find on SO I'm still stuck.
My Service method within my service.js is as follows, with comments;
postSimpleObject: function () {
// Have tried this first, and have passed
// as JSON.stringify(simpleObject)
var simpleObject = {
name: "J Doe",
colour: "Red"
};
// tried to pass this next
var simplerObject = '{ "Name": "J Done", "Colour":"Red"}';
// escaped the quotations and tried this next
var simplerObject2 = '{ \"Name\": \"J Done\", \"Colour\":\"Red\"}';
return $http.post(apiUrl + "PostSimpleObject?item=" + JSON.stringify(simpleObject), {
headers: {
'Content-Type': 'application/json'
}
});
}
Here is my API controller function on the API side;
public class CrudUserApiController : ApiController
{
[System.Web.Http.HttpPost]
public void PostSimpleObject(SimpleObject item)
{
var itemReceived = item;
}
}
my simple object class, on the api side;
public class SimpleObject
{
public string Name { get; set; }
public string Colour { get; set; }
}
Now, what happens is;
The API method is triggered, the routing can locate the controller and method
The model / object received is a new SimpleObject with null properties for both members
As per the comments in the service, I've tried passing a stringified object, a json string and an escaped json string.
Also on the API side I've tried using the [FromBody] attribute in front of the SimpleObject argument in the signature. The same thing happens.
I'm totally lost, some help would be much appreciated. Thanks.
It would be advisable to post the content on the body instead of on the the querystring for a number of reasons, such as querystring length limitations.
That said, if you insist on using the querystring, you need to tell WebAPI to look to the querystring for the data using the FromUri attribute, since the default is the body:
[System.Web.Http.HttpPost]
public void PostSimpleObject([FromUri]SimpleObject item)
{
var itemReceived = item;
}
Alternatively, you can post the content on the body directly as called out by ex0dm3nt:
$http.post(apiUrl + "PostSimpleObject", simpleObject);
You just need to pass your simpleObject as second parameter in the $post request like this:
postSimpleObject: function () {
var simpleObject = {
name: "J Doe",
colour: "Red"
};
return $http.post(apiUrl + "PostSimpleObject", simpleObject);
}