I see Response.json() method being used a lot, and I'm using it myself, but either I'm missing something or the documentation for the Response class is incorrect.
Example:
getCurrentTime() {
return this._http.get('http://date.jsontest.com/')
.map((res:Response) => res.json())
}
On the Angular site at https://angular.io/docs/ts/latest/api/http/index/Response-class.html, I don't see the method as a member of the Response class.
If .json is not a member of the Response class, can someone point me in the direction of understanding how this works.
Or if the documentation is wrong, someone please say so.
Thanks in advance.
If you look at the API Reference for Response, you'll see that Response extends Body. If you try to search for Body, you won't find it, which probably means it isn't public. If you look at the source code for Body, you'll see the code for json
/**
* Attempts to return body as parsed `JSON` object, or raises an exception.
*/
json(): any {
if (typeof this._body === 'string') {
return JSON.parse(<string>this._body);
}
if (this._body instanceof ArrayBuffer) {
return JSON.parse(this.text());
}
return this._body;
}
Let me know if you need explanation of the source. It looks pretty self-explanitory to me though.
Actually, the HTTP Client documentation (Process the response object)
says:
Parse to JSON
This is not Angular's own design. The Angular HTTP client follows the Fetch specification for the response object returned by the Fetch function. That spec defines a json() method that parses the response body into a JavaScript object.
So Angular2 implements the Fetch Specification, which includes the specification for the mentioned Body mixin, Angular2's Response class is extending, including the .json() method.
The json() method, when invoked, must return the result of running consume body with JSON.
As you can see in peeskillet's link, Angular2 is implementing all specified methods of the Body mixin, except of formData().
I had the same problem and this is how the error go away:
In the new version of Angular 4+, you need to imports rxjs from:
import { map } from 'rxjs/operators';
instead of from importing from:
import 'rxjs/add/operator/map';
Next, change the .get() to .get() and also you have to use pipe for angular 4+ as below:
getCurrentTime() {
return this._http.get<any>('http://date.jsontest.com/')
.pipe(map((res:Response) => res.json()));
}
Hope that Helps...!
Related
I'm following an rxjs that shows how to use rxjs with http calls in angular. But when i'm,trying to use response.json in the mapping function, i've an error in the console saying that: ERROR TypeError: response.json is not a function. this is the code of my service:
mappingFn() {
return this.http
.get('https://opentdb.com/api.php?amount=10')
.pipe(map((response: Response) => response.json()))};
this is the code of the components:
this.svc.mappingFn().subscribe({
next: (res) => {
console.log('mapping:', res);
},
});
I looked on different blogs, but i couldn't find something usefull. Please help me. Thank you
This can be influenced by your response. Some of them does not work directly. Go to the network tab and watch your data model. On the other side, make sure that you actually have a response, and response isn't undefined.
You don't have map the result to json, that was happen automatically by HttpClient.get(). Remove the map and write mappingFn as.
mappingFn() {
return this.http
.get('https://opentdb.com/api.php?amount=10')};
I am using a Service in angular to retrieve JSON responses from a path as given below.
const request = this.http.get<ShoppingCartItem>('assets/json/shopping-cart-test.json');
The above JSON file in the assets folder has an array of JSON objects. I want to convert the response to an array of ShoppingCartItem objects. Following given is the ShoppingCartItem class that I want to map. How to achieve this?
export class ShoppingCartItem {
$key: string;
title: string;
imageUrl: string;
price: number;
quantity: number;
constructor(init?: Partial<ShoppingCartItem>) {
Object.assign(this, init);
}
get totalPrice() { return this.price * this.quantity; }
}
I am not familiar with handling the HTTP response with methods like subscribe, pipe and map. A detailed explanation would be more helpful.
You already had the fundamentals right.
Inside an Angular.component ts file,
We first create a request with final type you expect from the request i.e - ShoppingCartItem similar to what you have done in your code
const shoppingCartItem$: Observable<ShoppingCartItem> = http.get<ShoppingCartItem>('/assets/db.json');
Notice the $sign on shoppingCartItem$, usually used with an Observable, the return type when you make HTTP Requests in Angular.
The subscribing part is done after declaring our Observable in this case. Subscribe method is used to make HTTP Requests, without it no requests are made to the server.
Pipe and map are RXJS operators that allows us to make changes to response. It basically gives you access to data in your observable so you can make changes. They are usually used in conjunction.
In your case, it could be used like
this.shoppingCartItem$:.pipe(
map((items: shoppingCartItem[]) => items.map(items=> items.key))
)
Working Stackblitz is below.
Local JSON subscription example
I have a NestJS route which sends back in response, a JSON not well formatted (like minified),
I want to make this JSON easier to read, like a JSON prettier or JSON formatted,
Do someone knows how to do it in NestJS ? I accept answers for other NodeJS frameworks like Express, maybe it will work in NestJS too...
Prettifying the JSON response should be the responsibility of the client, not the server. Otherwise you could be sending a lot of white space which will bloat the response size and could lead to a crash due to having a response too large. If you are using something like Postman, it should be easy to prettify it, I think Postman might do it by default. If you are looking at the response in some web browser, you could use JSON.parse() on the response and it should make the response an actual JSON which console.log() would then print in a pretty way.
You should try https://www.postman.com or https://insomnia.rest/. It can save you a lot of time when it comes to testing an API.
While you shouldn't do it in prod as mentioned above, there's number of cases where it makes a lot of sense (e.g. in dev env). You can achieve this in a bit hacky way:
Access express instance inside nest through breaking abstraction. It's not exposed on INest interface, so you'll need to cast it to any type to bypass Typescript check
Set undocumented express property "json spaces", which will set formatting for all JSON responses over the app
const app = await NestFactory.create(AppModule);
if (process.env.NODE_ENV === 'development') {
(app as any).httpAdapter.instance.set('json spaces', 2);
}
await app.listen(3000);
It works for me:
// src/main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
if (process.env.NODE_ENV !== 'production') {
app.getHttpAdapter().getInstance().set('json spaces', 2);
}
await app.listen(process.env.PORT);
}
Define return type string on your controller
Set the Content-Type: application/json response header
Use JSON.stringify to format your object with whitespace
Example controller code:
import { Controller, Get, Header } from '#nestjs/common';
#Controller('diagnostics')
export class DiagnosticsController {
#Get()
#Header('Content-Type', 'application/json')
findAll(): string {
const statusCode = 200;
const statusText = 'OK';
const info = {
self: 'NestJS Diagnostics Report',
status: {
statusCode,
statusText,
},
};
return JSON.stringify(info, null, 2);
}
}
I am fairly new to (flutter) development and I have a question:
There is this website, and I would like to display the content in an app. As far as I understood the website, it is an server-site html render. Since there are no API's (atleast I didn't find them) which I can use to read the data, I wanted to get the whole html document and parse all of the "interesting" data out.
Do you have any idea how I get the html document so that I can start parsing?
Or is there a more elegant solution to my problem?
Info: I don't want to make a html render, I have build my own UI and just want to insert specific data
Thanks a lot in advance!
I've just tested an http.get request on Flutter to the url you specified and works well. I used this package to make the get request, I defined an async funcion to make the request and in the main function of a Flutter app I call that function:
//This import the package
import 'package:http/http.dart' as http;
//...
//Here comes code of Flutter
//...
//Now I define the async function to make the request
void makeRequest() async{
var response = await http.get('https://speiseplan.app.itelligence.org/');
//If the http request is successful the statusCode will be 200
if(response.statusCode == 200){
String htmlToParse = response.body;
print(htmlToParse);
}
}
//...
//Here comes more Flutter code
//...
main(){
makeRequest();
}
This will print the html you want, as String and now you can parse it as you want.
In a Grails 2.5.0 controller action method, it seems like the properties in the HTTP JSON body will not be used for command object binding if request.JSON has been accessed in a filter.
Why is that? It doesn't make any sense to me.
Is there any way to allow request.JSON to be used in a filter, and also for command object binding?
Yes, this is the default behavior of Grails while it comes to data binding with request body. When you read the request body via request.JSON in your filter then the corresponding input stream will be closed or gets empty. So, now Grails can't further access that request body to bind to the command object.
So, you can either access the request body on your own in the filter or can use it with the command object but can't both.
From Binding The Request Body To Command Objects heading http://grails.github.io/grails-doc/2.5.0/guide/theWebLayer.html#dataBinding:
Note that the body of the request is being parsed to make that work.
Any attempt to read the body of the request after that will fail since
the corresponding input stream will be empty. The controller action
can either use a command object or it can parse the body of the
request on its own (either directly, or by referring to something like
request.JSON), but cannot do both.
So, what are you trying to achieve is not possible directly. But, you can do something different. In your filter, read the incoming request body and store into the params or session (if filter passes the request to controller) and then manually bind the parameter in action:
MyFilters.groovy
class MyFilters {
def filters = {
foo(/* your filter */) {
before = {
// Your checks
Map requestData = request.JSON as Map
session.requestData = requestData
return true
}
}
}
}
Now, in your controller action, instead of doing:
class MyController {
def fooAction(MyCommandObject object) {
}
}
Do something like this:
class MyController {
def fooAction() {
MyCommandObject object = new MyCommandObject(session.requestData)
// Clear from session to clear up the memory
session.requestData = null
}
}
Update: The above solution, I've provided will work well but is not clean. #JoshuaMoore provided a link with a cleaner solution Http Servlet request lose params from POST body after read it once.