How to access Dart shelf post body parameters? - json

I am using Dart Shelf framework for building an API. Get works fine but I am having issues with post. I couldn't access any of the body parameters of the post request in my server. Here is what I have tried.
// shelf-router
router.post('/login', (Request req) async {
final body = await req.readAsString();
// to check
print(body); // outputs null
return
Response.ok('OK');
});
How am I testing this?
Using postman with the endpoint and body type raw (JSON).
payload as
{
"user":"testUser",
"password":"p455w0rd"
}
I even tried setting contenttype header to application/JSON but no luck there too.

Try this inside your request handler function..
final String query = await request.readAsString();
Map queryParams = Uri(query: query).queryParameters;
print(queryParams);

final String query = await request.readAsString();
// Map<String, String> queryParams = Uri(query: query).queryParameters;
Map queryParams = jsonDecode(query);
print(queryParams['user']);

I can receive the parameter from the postman with form-data.
I am using shelf_route in the server.
If this is similar to you, you can follow this:
https://stackoverflow.com/a/74255231/17798537

Related

POST json to external API in .NET Core - Unsupported Media Type

I'm trying to code a middleman API that logs calls and other details from internal users to an external API.
When I try to POST to the external API from my Controller, I get 415 unsupported media type.
I set up my client in the controller constructor like this:
client.BaseAddress = new Uri("https://restapi.***.com/customers/");
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("X-AppSecretToken", Auth.APPSECRETTOKEN);
client.DefaultRequestHeaders.Add("X-AgreementGrantToken", Auth.AGREEMENTGRANTTOKEN);
My POST method looks like this:
var json = JsonConvert.SerializeObject(customer, Formatting.Indented);
using (var stringContent = new StringContent(json))
{
stringContent.Headers.ContentType.CharSet = "";
HttpResponseMessage response = await client.PostAsync(client.BaseAddress, stringContent);
if (!response.IsSuccessStatusCode)
{
return StatusCode((int)response.StatusCode);
}
}
return CreatedAtAction("GetCustomer", new { id = customer.ID }, customer);
I've been looking around and found a lot of comments telling me to use Stringcontent, but I also found a couple of responses saying ByteArrayContent - none of them work.
Can anyone help me?
EDIT: When I run the code with breakpoints it seems like some of the properties in the incoming customer object are set even though I didn't set them in my Postman call.
Example; the external API returns a customernumber when I give it the 5 properties that are obligatory. But when I call my internal API from Postman, sending only those 5 obligatory properties, it autopopulates the customernumber with a 0.
Could this be the source of the error? and how do I tell .net core to not autopopulate the customernumber?
EDIT2: I changed my stringContent to include encoding and used a different overload, so the using line now says
using (var stringContent = new StringContent(json, Encoding.UTF8, "application/json"))
And I removed
stringContent.Headers.ContentType.Charset = "";
to reflect the fact that I tried setting the encoding.
The return code changed from 415 to 400 Bad Request when I changed that.
EDIT3:
Tried NOT serializing with Json.Net, and instead used JObjects and Jproperties;
public async Task<ActionResult<Customer>> PostCustomer([FromBody]Customer customer)
{
JObject payload = new JObject(
new JProperty("currency", customer.Currency),
new JProperty("name", customer.Name),
new JProperty("customergroup",
new JObject(new JProperty("customergroupNumber",
customer.CustomerGroup.CustomerGroupNumber)
)),
new JProperty("paymentTerms",
new JObject(new JProperty("paymentTermsNumber",
customer.PaymentTerms.PaymentTermsNumber)
)),
new JProperty("vatZone",
new JObject(new JProperty("vatZoneNumber",
customer.VatZone.VatZoneNumber)
))
);
using (var stringContent = new StringContent(payload.ToString(), Encoding.UTF8, "application/json"))
{
HttpResponseMessage response = await client.PostAsync(client.BaseAddress, stringContent);
if (!response.IsSuccessStatusCode)
{
return StatusCode((int)response.StatusCode);
}
}
return CreatedAtAction("GetCustomer", new { id = customer.CustomerNumber }, customer);
}
Still 400 Bad Request
This is a case of capitalizing - simple really.
My POST request JSON had an object named customergroup - changed it to customerGroup, and it worked.

Dart - Http Get request with body

I want to send an HTTP GET request with json body using dart. I know this is possible, because I've done it in the past but can't find the files/recode it. Packages like dart:http doesn't allow to send a body along with an GET request.
thanks for help
I am not really sure where the problem should be but I have made this example for Dart VM which I guess does what you want:
import 'dart:convert';
import 'dart:io';
Future<void> main(List arguments) async {
final response =
await getCallWithBody('http://localhost:8080', {"Key": "Value"});
response.forEach(print);
}
Future<List<String>> getCallWithBody(String address, Object object) async {
final client = HttpClient();
final request = await client.getUrl(Uri.parse(address));
request.contentLength = -1;
request.add(utf8.encode(json.encode(object)));
await request.flush();
return (await request.close())
.transform(utf8.decoder)
.transform(const LineSplitter())
.toList();
}

Angular HttpClient returns string data instead of parsed JSON

I've been in the process of migrating a code base from Angular 4.x to 5.x, and I'm running into a strange issue. I have a service function, that is intended to return a list of objects to the front end, which I then massage into a specific data format. I know I'll need to keep the mapping, but I'm a little miffed that it's returning just plain string data.
The original function is this: (using Http from #angular/http just renamed to HttpClient)
public GetVendors(showAll = true, screenArea: number = 0): Observable<Array<SelectModel>> {
let link = AppSettings.API_COMMON_VENDORS;
let params: URLSearchParams = new URLSearchParams();
params.set('showAll', showAll.toString());
params.set('screenArea', screenArea.toString());
let requestOptions = new RequestOptions();
requestOptions.search = params;
return this.httpClient.get(link, requestOptions).map(response => {
let result = JSON.parse(response.json());
let list = new Array<SelectModel>();
let vendors: Array<any> = result;
vendors.forEach(vendor => {
list.push(this.CreateSelectModel(vendor));
});
return list;
});
}
and after ripping out ALL of the Http code, here's the function again using HttpClient from #angular/common/http
public GetVendors(showAll = true, screenArea: number = 0): Observable<Array<SelectModel>> {
let link = AppSettings.API_COMMON_VENDORS;
let params: HttpParams = new HttpParams()
.set('showAll', showAll.toString())
.set('screenArea', screenArea.toString());
return this.httpClient.get<Array<any>>(link, {params}).map(response => {
let list = new Array<SelectModel>();
response.forEach(vendor => {
list.push(this.CreateSelectModel(vendor));
});
return list;
});
}
The issue with this is it kind of defeats the purpose of the new client parsing json for me. The response object is a string representing the JSON of the data I requested, but it's still in a string form, and not the type defined in the get<>() call.
What am I doing wrong here? shouldn't it be parsed already?
Sample Response Data A'la Network Tools in Chrome Dev Tools:
Sample Response Body:
Dev Tools Screenshot with Value of response
The backend (C#) responds with this:
[HttpGet]
public JsonResult Vendors(bool showAll = false, int screenArea = 0)
{
var vendors = _commonBL.GetVendorsSlimForUser(UserModel, UserModel.CustomerId, showAll, screenArea);
return GetJson(vendors);
}
this is how it worked before the Http => HttpClient migration, and it worked with ONE JSON.parse() The data in the return line is simply a standard List<T>
This is what the raw response for your data should look like:
[{"Id":1234,"Name":"Chris Rutherford"}]
But this is what it actually looks like:
"[{\"Id\":1234,\"Name\":\"Chris Rutherford\"}]"
So somewhere in your server code, you have applied JSON encoding twice. Once you correct that, HttpClient will do the right thing.
I'd quote an answer from this thread. Hope it will shed some light on how things work, read it thoroughly it enlightened me tough its not easy to find.
TypeScript only verifies the object interface at compile time. Any object that the code fetches at runtime cannot be verified by
TypeScript.
If this is the case, then things like HttpClient.Get should not
return Observable of type T. It should return Observable of type Object because
that's what is actually returned. Trying to state that it returns T
when it returns Object is misleading.
In the documentation the client's return section says this:
#return an Observable of the body as
type T.
In reality, the documentation should say:
#return an Observable of the body which
might be T. You do not get T back. If you got T back, it would
actually be T, but it's not.

Get json Data from Rapid API in Flutter (Dart)

I managed to load the data from a Json File which is local on my Flutter Project. I also was able to fetch Data from the Internet, if the API Url was like:
https://[API-Server][parameter1:xy][parameter2:abc][API-KEY:lasgoewrijeowfjsdfdfiia]
I archieved that with this code sample:
Future<String> _loadStringFixtures() async {
return await rootBundle.loadString('assets/fixtures.json');
}
Future loadFixtures() async {
String jsonString = await _loadStringFixtures();
final jsonResponse = json.decode(jsonString);
FixturesAPI value = new FixturesAPI.fromJson(jsonResponse);
return value;
}
So far so good...
But now I am facing a problem with the API Provider RapidAPI
You can find the documentation etc. here:
https://rapidapi.com/api-sports/api/api-football/endpoints
As you can see they give some code snippets to connect to their API.
There are some for C, C#, Java, Python etc. You can look into all of them with the link above.
Sadly there is no example for Flutter.
And I do not see a way to adapt these examples.
Normally you can paste your API Key directly into the URL, but this seems not possible here? Or maybe it is?
Does Flutter also have other possibilities to receive data from an API besides the one I did?
Thank you so much in advance for your help!
It's possible to with http package and very easy. You can see in this example below...
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
class APIService {
// API key
static const _api_key = <YOU-API-KEY-HERE>;
// Base API url
static const String _baseUrl = "api-football-beta.p.rapidapi.com";
// Base headers for Response url
static const Map<String, String> _headers = {
"content-type": "application/json",
"x-rapidapi-host": "api-football-beta.p.rapidapi.com",
"x-rapidapi-key": _api_key,
};
// Base API request to get response
Future<dynamic> get({
#required String endpoint,
#required Map<String, String> query,
}) async {
Uri uri = Uri.https(_baseUrl, endpoint, query);
final response = await http.get(uri, headers: _headers);
if (response.statusCode == 200) {
// If server returns an OK response, parse the JSON.
return json.decode(response.body);
} else {
// If that response was not OK, throw an error.
throw Exception('Failed to load json data');
}
}
}
Then get you request:
//....
APIService apiService = APIService();
// You future
Future future;
//in the initState() or use it how you want...
future = apiService.get(endpoint:'/fixtures', query:{"live": "all"});
//....
Yes it possible in flutter. Use the Dio Package in flutter which is a powerful Http client. Using dio you can set interceptors to add api key to url so you don't have to append it in every request. Setting interceptors will help you.

Seeing the Http Response content in ServiceStack

I am using ServiceStack to create a C# client to a JSON RESTful service. I have this code that returns my DTO:
Search result = restClient.Get (search);
This works fine, but in order to effectively debug the search results coming back I need to output the text content from the underlying HTTP Response object. (I don't know all the elements in the response yet in order to add them to the DTO).
Is there any way I can get hold of the underlying HTTP response, and thus the full text content, from my result object?
Thanks in advance.
#adamfowleruk
When inheriting from ServiceStack's built-in Service you can access the underlying Request and Response directly from the Response class with:
public class MyService : Service
{
public object Get(Request request)
{
base.Request ...
base.Response ...
}
}
You won't see the response output in your service or filters since it writes directly to the response stream and is the last thing that ServiceStack does after executing your service and all response filters.
For diagnosing HTTP I recommend using Fiddler or WebInspector also ServiceStack's built-in Request Logger might help as well.
Consuming a ServiceStack service
If you're using the C# Service Clients you can simply ask for what you want, e.g. you can access the returned response as a raw string:
string responseJson = client.Get<string>("/poco/World");
Or as raw bytes:
byte[] responseBytes = client.Get<byte[]>("/poco/World");
Or as a Stream:
using (Stream responseStream = client.Get<Stream>("/poco/World")) {
var dto = responseStream.ReadFully().FromUtf8Bytes().FromJson<PocoResponse>();
}
Or even access the populated HttpWebResponse object:
HttpWebResponse webResponse = client.Get<HttpWebResponse>("/poco/World");
webResponse.Headers["X-Response"] //World
using (webResponse)
using (var stream = webResponse.GetResponseStream())
using (var sr = new StreamReader(stream)) {
string response = sr.ReadToEnd();
}
You can also introspect the HttpWebResponse by using Global and Local Response filters, e.g:
JsonServiceClient.HttpWebResponseFilter = httpRes => { .. };
Or using a Local filter:
var client = new JsonServiceClient(baseUrl) {
ResponseFilter = httpRes => { .. }
};
Consuming a 3rd Party Service
If you're consuming a 3rd Party REST/HTTP API you can use a responseFilter: in ServiceStack's HTTP Util extensions:
List<GithubRepo> repos = "https://api.github.com/users/{0}/repos".Fmt(user)
.GetJsonFromUrl(responseFilter: httpRes => {
var remaining = httpRes.Headers["X-Api-Remaining"];
})
.FromJson<List<GithubRepo>>();
I use Fiddler to debug my services. It gives you all sorts of cool HTTP debugging facilities.
http://www.fiddler2.com/fiddler2/
I like to use RestConsole. It is a Chrome Extension and you can easily submit POST requests and see the response. It is also handy to create sample data and then step into the ServiceStack code and see what's happening. The ServiceStack PluralSight course has a nice demo of how to use them together.
Thanks to the above help I found the right answer. Documenting here for others:-
SearchResponse result = null; // my ServiceStack DTO
HttpWebResponse webResponse = restClient.Get<HttpWebResponse>(
completePath("/v1/search",qp)); // builds the URL with parameters
using (var stream = webResponse.GetResponseStream())
using (var sr = new StreamReader(stream)) {
var text = sr.ReadToEnd();
log.log ("response text: " + text); // *** PRINTING STRING VALUE HERE FOR DEBUG
result = text.FromJson<SearchResponse>();
}
// Now do something useful with the result DTO object
log.log ("RESULT: " + result.ToString ());
for (int i = 0; i < result.Results.Length; i++) {
log.log ("Result " + i + ": " + result.Results[i].ToString());
}