icarus-consulting / yaapii.http Goto Github PK
View Code? Open in Web Editor NEWC# Library for Http Request
License: MIT License
C# Library for Http Request
License: MIT License
We have a URL interface which will assist in creating url`s
there is no such interface
interface IUrl {
IUrl Schema();
IUrl Host();
IUrl Port();
IUrl With();
}
var body = "";
if(new Body.Exists(response).Value())
{
body = new Body.Of(response).AsString();
}
can be replaced with the less verbose
var body = new Body.FallbackOf(response).AsString();
No *.FallbackOf classes exist.
We use the current version of Yaapii.Atoms.
No Atoms classes are copied into this project.
We use Yaapii.Atoms 0.29.0.
For compatibility reasons, some classes from Atoms have been copied into this project.
Yaapii.HTTP uses Atoms 0.21.0
It uses Atoms 0.20.0
We can write new TextBody.Of(response)
instead of new TextOf(new Body.Of(response))
to get a body as IText
. Similar things exist for IJSON
, IXML
and IBytes
.
We had similar classes before, but they accidentally got lost in refactoring.
Now Body.Of is the only thing that can retrieve the body of a request/response.
Body.Of implements IInput
, which can be converted into the other data types, but that makes things more verbose than they need to be.
To ensure consistent decoding, these classes should use Body.Of internally.
The badges at the top of the readme.md include the one provided by https://www.elegantobjects.org to inform potential contributors, that we follow those principles.
readme.md has no reference to elegant objects.
A timeout given to the ctor of AspNetCoreWire is always used for requests sent over that Wire.
A singleton HttpClient is used. The timeout of a HttpClient can only be set before the first request is sent. This means only the first timeout value passed to AspNetCoreWire will be used.
The problem is in AspNetCoreClient, it ignores the given timeout when the HttpClient has already been initialized.
The singleton HttpClient is necessary, see https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/.
We may have to store several of them, one for each timeout value used. That should still be much better that creating a new HttpClient for each request.
var wire1 =
new AspNetCoreWire(
new TimeSpan(0, 1, 0) // should time out after one minute
);
wire1.Response(new Get("insert some url")); // first request will initialize the HttpClient
var wire2 =
new AspNetCoreWire(
new TimeSpan(0, 0, 1) // should time out after one second (but won't)
);
wire2.Response(new Get("insert a url that can't be reached")); // will time out after one minute
We can set the security protocol, when initializing a client.
By default, this should be:
ServicePointManager.SecurityProtocol =SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
It can happen, that a server does not understand the security protocol, which the client (that sends the http request) is using.
When something goes wrong, a meaningful exception is thrown.
Due to the wires creating responses in separate tasks, if something goes wrong while getting a response, an AggregateException
is thrown where the task's result is being accessed, to signal that something went wrong in that task. This is usually not very helpful in finding out what exactly went wrong.
An AggregateException
can hold any number of inner exceptions, but in this case, it can be expected that there is only ever exactly one inner exception, the one that caused the task to fail.
If there is exactly one inner exception, throw that.
Otherwise, rethrow the AggregateException
.
Our build scripts (appveyor.yml
and build.cake
) publishes NuGet packages to our AppVeyor NuGet feed only when a tag was set.
Setting the artifacts in the appveyor.yml
causes in publishing the NuGet packages from the AppVeyor artifacts cloud to the NuGet Feed. This is an internal automated mechanism in the AppVeyor environment.
When the master builds on the AppVeyor the version number of the head of build.cake
is taken to publish a NuGet package all the time. This may result in overwriting an already published NuGet package in our NuGet feed with wrong content.
Our library ports the design of verano-http, which is better than the current.
There is a HTTP server mock, which we can use to fire HTTP Requests at.
No such thing
The QueryParams object can work with empty querys
if query is empty, a single, empty entry is returned which leads to an error
The fix with special char encoding exists in version 3...
The NuGet package is only deployed on the NuGet feed.
The NuGet package is deployed on the internal feed and NuGet.
Remove NuGet deployment from the AppVeyor.yml and control the NuGet release in the cake.build script.
No dictionary is enumerated
Some dictionaries are filtered and mapped
This results in all values being built
If a key or value stored in the body as form params contains special characters, they are escaped, encoded or something else to make that data compatible with content type application/x-www-form-urlencoded.
Characters like '&', '+', or '=' may cause unexpected behavior or errors.
The problem is in AspNetCoreWire
:
body =
new BytesOf(
new Yaapii.Atoms.Text.Joined("&",
new MappedDictionary<string>((key, value) =>
$"{key}={value()}",
formParams
)
)
);
There has to be a better way of doing this.
Using System.Net.Http.FormUrlEncodedContent
instead of System.Net.Http.ByteArrayContent
may solve this.
Giving the request a timeout works.
Does not work.
AtomsTemp have only Map and Many classes and no interfaces
We have classes for standard content results, which accepts a content and a contenttype. They return a ContentResult.
You have to build your content result every time complete by yourself
The QueryParams object uses the MapOf from Yaapii.Atoms. Remove the temporary class after new release from Yaapii.Atoms (>2.3.1)
Temporary MapOf is used due to missing Atoms release
To secure, that our apps can talk with each other, the security protocol is set in AspNetCoreClients to
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Depending on the Framework on which apps run, it can happen, that communication does not work because of differently used security protocols
AspNetCore is tolerant with unsupported headers
When there is a "authorization" header in the request it fails when trying to add it to the content headers
When extracting a part from a request or response using *.Of, and the part doesn't exist, an appropriate Exception is thrown.
Example: Using Body.Of on a response that doesn't contain a body should throw an InvalidOperationException with a message like "Body not found"
a generic KeyNotFoundException is thrown
all *.Of classes are probably affected by this
We can use C# async command when sending a request.
IWire is a synced interface. Therefore the library is not useable in Blazor projects as they require async/await operators.
Library uses Atoms 0.27.0
Yaapii.Http uses Atoms 0.22.0
It uses Atoms 0.21.0
RequestBody.With accepts bytes.
It accepts IText.
HttpMock is not responsible for routing requests to different FkWires depending on the path.
Instead, HttpMock always takes one IWire, which can be a FkWire if you want the same response regardless of path, or a MatchingWire to return different responses for different requests.
MatchingWire compares incoming requests to request templates (which can contain any request part, not just a path, but also query params etc.) and chooses a FkWire associated with a template, that matches the request.
If no matching template is found, the response has status 404.
HttpMock does too many things.
ctor parameter names in FkWire are not ambiguous.
The names are ambiguous which results in more code to distinguish the on which should be used, like here:
new IsResponding(
new FkConfig(
"ssl", bool.TrueString,
"port", "1337"
),
new FkAuthorization(),
new FkWire(response: req => throw new TimeoutException()), //ambiguity
new FkIdentity()
).Invoke()
)
Timeout works fine when specifying it like new Timespan(0,0,1,0);
TimeSpan is misinterpreted: In the following line, it must be TotalMilliSeconds instead of MilliSeconds:
There is fake implementations of all interfaces, for use in unit testing.
There is no fake implementation of IAspHttpClients
and IVerification
.
We can specify the Hostname when we create a new MockServer, like
var server = new HttpMock("localhost", 80);
Only the port is configurable.
TextBody.Of automatically selects the encoding specified in the content type header.
TextBody.Of internally uses Atoms.Text.TextOf(IInput), which uses utf-8 encoding by default.
var expected = "this is a test @ ³ € 𤽜 𝄞";
Assert.Equal(
expected,
new TextBody.Of(
new Request(
new Body(
new InputOf(
expected,
Encoding.Unicode
)
),
new ContentType("text/plain; charset=utf-16")
)
).AsString()
);
Symbols nuget package is deployed to nuget.org
No symbols deployed
The wire does not send a body when using the verbs GET and DELETE. A body is not valid when using these verbs and ASPNet throws an Exception.
@koeeenig and me agreed to ignore the body if present, to establish a safe workflow for Yaapii.Http, even if someone tries to send a body illegally.
new Response.Of(
new Status(200),
new Reason("OK"),
new JsonBody(json)
)
can be replaced with new JsonResponse.Of(json)
for less verbose unit testing.
Similarly, XmlResponse.Of and BytesResponse.Of are a thing.
new JsonResponse(...)
(without .Of) could be a less verbose variant of
new JsonBody.Of(
new Response(
...
)
)
Same for XmlResponse and BytesResponse.
No specialized response classes exist.
No unnecessary duplicate header values.
When using FormParams, duplicate values may be sent for the content type header. This can cause problems with some servers (Status 400 / Bad Request).
AspNetCoreWire
uses FormUrlEncodedContent
which will automatically add a content type header. Since we can't expect this behavior from all IWire
implementations, it should be ok to also manually add a content type header to a request dictionary, or have FormParams
and similar classes add one, before passing that dictionary to a wire.
For that reason, AspNetCoreWire
should tolerate duplicate header values in a request dictionary. When adding headers from a request dictionary to an HttpContent
instance, AspNetCoreWire
should first check if the same value already exists for the same header type and only add the value if it isn't a duplicate.
Adding a request header for example Content-Type: application/json
works.
A Exception is thrown by the Library. The header is added to the wrong request object.
If you are sure that a header has exactly one value, or you just need the first of several values, it can be accessed with
new Header.FirstOf(response, "header key").AsString()
Similar *.FirstOf classes exist for specialized headers, e.g. BearerTokenAuth.FirstOf etc.
new FirstOf<string>(
new Header.Of(response, "header key")
).Value()
Body class use Base64 encoding for strings.
The Wire decodes the Body with Base64
Files have MIT license headers.
No headers.
JToken.Parse is used to allow parsing JObject or JArray.
JObject.Parse is used. Trying to parse JArray results in an exception.
The function that creates an Exception is only called, when an Exception is needed.
The function that creates an Exception to throw, if the status doesn't match, is always called, even when the status matches.
Yaapii.Atoms.FailWhen takes an exception, so the Func is being executed to build FailWhen from the result.
Use an if statement instead of FailWhen and only execute the Func when needed.
Test will be executed.
No tests are executed.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.