I am currently writing an API wrapper for wit.ai. I'd like to add tests to this wrapper but I am unsure how I'd do that given that I'm using the http library to send HTTP requests.
The code would look something like this:
Future message(String q) {
Map<String, String> headers = {
'Accept': 'application/vnd.wit.${apiVersion}+json',
'Authorization': 'Bearer ${token}'
};
return http
.get('https://api.wit.ai/message?q=${q}', headers: headers)
.then((response) {
return JSON.decode(response.body);
}).catchError((e, stackTrace) {
return JSON.decode(e);
});
}
Given this code, how would I write a test that does not actually send a HTTP request?
This is traditionally solved by dependency injection. Your API wrapper class could have a constructor like:
class MyWrapper {
final http.BaseClient _httpClient;
MyWrapper({BaseClient httpClient: new http.Client()})
: _httpClient = httpClient;
// ...
}
Using a named argument with a default value means normal users won't need to worry about creating the Client.
In your method, you use the Client instead of using the static methods of the http library:
Future message(String q) {
Map<String, String> headers = {
'Accept': 'application/vnd.wit.${apiVersion}+json',
'Authorization': 'Bearer ${token}'
};
return _httpClient
.get('https://api.wit.ai/message?q=${q}', headers: headers)
.then((response) {
return JSON.decode(response.body);
}).catchError((e, stackTrace) {
return JSON.decode(e);
});
}
Keep in mind, though, that clients need to be closed. If you don't have a close method on your API wrapper, you may want to a) add it, or b) put the dependency injection on the message() method instead of on the constructor.
When testing, set up a MockClient. Pass it like so:
var wrapper = new MyWrapper(httpClient: myMockClient);
No need for running a local server, and way faster.
Related
I am using the Reactor Netty HTTP client here as a stand alone dependency, ie not via spring-webflux because I do not want to drag in Spring related dependencies
As can be seen from the documentation it is possible to make a request that returns HttpClientResponse
import reactor.netty.http.client.HttpClient;
import reactor.netty.http.client.HttpClientResponse;
public class Application {
public static void main(String[] args) {
HttpClientResponse response =
HttpClient.create()
.get()
.uri("http://example.com/")
.response()
.block();
}
}
Thing is HttpClientResponse only contains the headers and the staus. As can be seen from its Java Docs here
Also from the example to consume data one can do
import reactor.netty.http.client.HttpClient;
public class Application {
public static void main(String[] args) {
String response =
HttpClient.create()
.get()
.uri("http://example.com/")
.responseContent()
.aggregate()
.asString()
.block();
}
}
But this only returns the http entity data as string. No information about the headers nor status code.
The problem I have now is I need to make a request and get a response that gives me both the headers, status etc alongside with the http response body.
I cannot seem to find how. Any ideas?qw
Take a look at the following methods:
Flux<V> response(BiFunction<HttpClientResponse,ByteBufFlux,Publisher<V>> receiver)
Mono<V> responseSingle(BiFunction<HttpClientResponse, ByteBufMono, Mono<V>> receiver)
They allow you to access response body, status, and http headers simultaneously.
For example using the responseSingle method you can do the following:
private Mono<Foo> getFoo() {
return httpClient.get()
.uri("foos/1")
.responseSingle(
(response, bytes) ->
bytes.asString()
.map(it -> new Foo(response.status().code(), it))
);
}
The code above translates the response into some domain object Foo defined as follows:
public static class Foo {
int status;
String response;
public Foo(int status, String response) {
this.status = status;
this.response = response;
}
}
The Foo object is null when the http response does not have a body. For example, if HttpStatus 403 is returned, the Foo object is null. I was able to check response code and return just status.
(resp, bytes)-> {
if (resp.status().code()=HttpResponseStatus.OK.code) {
return bytes.asString().map(it->new Foo(resp.status(),it);
} else {
return Mono.just(new Foo(resp.status());
}
}
Using Audit.Net is it possible to create an audit scope for httpClient requests, in a similar way to the MVC.Core or WebAPI.Core Middleware?
I've tried something like this but not having much success, generally it'll timeout the app.
AuditScope scope = null;
try {
using(HttpClient client = new HttpClient) {
scope = await AuditScope.CreateAsync("",() => client)
// code to initialise the Httpclient
}
}
finally {
await scope.DisposeAsync();
}
I think the only option to hook into the HttpClient is to use a custom HttpClientHandler so you can intercept the rest calls.
Just as an example:
public class AuditClientHandler : HttpClientHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var options = new AuditScopeOptions()
{
EventType = $"{request.Method.Method} {request.RequestUri.AbsoluteUri}",
CreationPolicy = EventCreationPolicy.InsertOnStartReplaceOnEnd,
ExtraFields = new
{
request = GetRequestAudit(request)
}
};
using (var scope = AuditScope.Create(options))
{
var response = await base.SendAsync(request, cancellationToken);
scope.SetCustomField("response", GetResponseAudit(response));
return response;
}
}
}
I've used the InsertOnStartReplaceOnEnd creation policy, so the request is saved before it's sent to the server, and the response is added to the event and saved afterwards.
The implementation of GetRequestAudit / GetResponseAudit is up to you, just return an object (that can be serialized) with the information you want to log.
So each time you need to audit an HttpClient instance, you need to pass the handler to its constructor:
var cli = new HttpClient(new AuditClientHandler());
var response = await cli.GetAsync("http://google.com");
Anyway I will evaluate providing a new library (Audit.HttpClient?) with a configurable Handler so the implementation could be cleaner.
Update
You can now use the Audit.HttpClient extension for a cleaner implementation. Take a look at the documentation here
Is there a way to implement GraphQL in flutter?
I was trying making the API call with the query and variables objects in a JSON object.
type '_InternalLinkedHashMap' is not a subtype of type 'String' in type cast
I have been using graphql_flutter package for a few weeks now and it seems to work well enough. Here is an example:
import 'package:graphql_flutter/graphql_flutter.dart' show Client, InMemoryCache;
...
Future<dynamic> post(
String body, {
Map<String, dynamic> variables,
}) async {
final Client client = Client(
endPoint: endpoint,
cache: new InMemoryCache(),
);
final Future<Map<String, dynamic>> result =
client.query(query: body, variables: variables);
return result;
}
To use just give it the graphql and any variables. i.e. a delete mutation may look like
String deleteMutation =
'''mutation deleteItem(\$itemId: ID!) {
deleteItem(input: { itemId: \$itemId}) {
itemId
}
}'''.replaceAll('\n', ' ');
await post(deleteMutation , variables: <String, dynamic>{'itemId': itemId});
This is updated and working solution of #aqwert
import 'package:graphql_flutter/graphql_flutter.dart';
...
HttpLink link = HttpLink(uri: /*your url here*/); // you can also use headers for authorization etc.
GraphQLClient client = GraphQLClient(link: link as Link, cache: InMemoryCache());
QueryOptions query = QueryOptions(
document:
r'''
mutation deleteItem($id: String!) {
deleteItem(callId: $id)
}
''',
variables: {'id' : id}
);
var result = await client.query(query);
I'm calling web API controller from Aurelia JS but i'm not getting any response from web API controller.
here is my code :
httpClient.fetch('/api/controllername', {
method: "POST",
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(passvaluetocontroller)
})
.then(response => response.json())
.then(data => {
alert(data);
alert("success");
});
here is my controller code :
public HttpResponseMessage Post(passvaluetocontroller s)
{
return new HttpResponseMessage(System.Net.HttpStatusCode.Accepted);
}
so I am not getting any response and also it is showing error in console:
Uncaught (in promise)
SyntaxError:
Unexpected end of JSON input.
How can I do work when the request is successful?
The cause is very simple. You are not actually sending anything from your controller method:
public HttpResponseMessage Post(passvaluetocontroller s)
{
return new HttpResponseMessage(System.Net.HttpStatusCode.Accepted);
}
By passing the HttpResponseMessage method a System.Net.HttpStatusCode.Accepted, you are creating a response whose header contains the Accepted status code, but its body is empty. Therefore, there is nothing to deserialize. The response.json() will fail if the response is empty, that's why you are getting the error.
There are 2 possible solutions:
If you do not even intend to send any actual content back from the server, then simply don't call response.json() since there is nothing that you need in it. In that case, in your .then(...) method, simply check for response.ok. Doing this will tell you whether the response represents a successful operation - that is, the response status code is 2xx.
If you actually want to deserialize something, then simply send something from the server to deserialize. You can do that like this:
public object Post(passvaluetocontroller s)
{
return new { Test = "Test" };
}
Obviously, you can change the object return type to whatever you want and so can you return an object of your liking from within the action method.
I'm trying to write some tests for my Dart server application, and I've been using the HttpClient class (along with the related HttpClientRequest and HttpClientResponse classes to make test requests to the server (note that I'm using these classes because I need the dart:io package for running the server, so I can't also import dart:html). This has been going fairly well so far, and I've been able to write tests to check that the server is returning responses with the correct HTTP Status code. The base of the code I've been using to make these test calls is as follows:
Future<HttpClientResponse> makeServerRequest(String method, Uri uri, [String jsonData]) async {
HttpClient client = new HttpClient();
HttpClientRequest request = await client.openUrl(method, uri);
request.write(jsonData);
return request.close();
}
Now I need to write a test that makes sure that the body of the response, not just the status code, is correct. The problem is that I can't seem to find anything that allows me to actually access the response body in the HttpClient* classes. The closest I've been able to find so far is the HttpClientResponse.contentLength property, but that only tells me how big the response body is, and isn't the actual content.
How do I retrieve the response body from these requests? Or, if you aren't able to, is there some other way I can make the requests on a server side application so I can read the responses?
The HttpClientResponse object is a Stream, so you can just read it with the listen() method:
response.listen((List<int> data) {
//data as bytes
});
You can also use the codecs from dart:convert to parse the data. The following example reads the response contents to a String:
import 'dart:io';
import 'dart:convert';
import 'dart:async';
Future<String> readResponse(HttpClientResponse response) {
final completer = Completer<String>();
final contents = StringBuffer();
response.transform(utf8.decoder).listen((data) {
contents.write(data);
}, onDone: () => completer.complete(contents.toString()));
return completer.future;
}
Low level
Here is the await for version of collecting the response stream. It's a little more compact than using a completer.
Future<String> readResponse(HttpClientResponse response) async {
final contents = StringBuffer();
await for (var data in response.transform(utf8.decoder)) {
contents.write(data);
}
return contents.toString();
}
You should wrap it in a try catch block to handle errors.
High level
Most of the time from the client side you would use the http library instead:
// import 'package:http/http.dart';
Response response = await get(url);
String content = response.body;
See this article for more details.
A short way of getting the body from an HttpClientResponse is:
Future<String> readResponse(HttpClientResponse response) async {
return response.transform(utf8.decoder).join();
}