HTTP client for NodeJS. Inspired in the Java JAX-RS spec, so you can expect excellence, versatility and extensibility.
I have Node.js applications that currently rely on the well-known "request" library. However, as we're all aware, this library has been discontinued since 2020. To compound the issue, they've opted not to accept any community merge requests for updates or security patches. It's frustrating, resembling an admonishing parent, they consistently point to the discontinuation post, even though the library continues to see around 19,000 weekly downloads even after two years of being abandoned. It's worth noting that we're discussing an HTTP client here; it's not a complex, cutting-edge codebase.
Given this situation, I'm actively seeking a suitable replacement. While I experimented with alternatives like "axios" and others, they all emphasize front-end and back-end compatibility (not to mention ESM module compatibility), which isn't my primary concern. I'm in search of a library that provides a straightforward and robust API, harnessing the latest features of Node.js, without being encumbered by compatibility intricacies.
- HTTP, HTTPs, HTTP2
- Filters / Observability
- Streaming
- Well-defined API
- 0 dependencies
const client = new ClientBuilder()
.withTimeout(30, TimeUnit.Seconds)
.withFilter(new LoggingFilter(console.log))
.build();
const target = client
.target("https://run.mocky.io");
const response = await target
.path("/v3/de314aa8-a521-47c4-8ff3-69b447dab89b")
.request()
.header(HttpHeaders.ACCEPT, MediaType.ANY_TEXT_TYPE.toString())
.get();
if(response.getStatusInfo().getFamily().isSuccessful()) {
const body = await response.readEntity(new StringEntity());
} else {
console.log("Response status code:", response.getStatus());
}
const client = new ClientBuilder()
.withTimeout(30, TimeUnit.Seconds)
.withFilter(new LoggingFilter(console.log))
.build();
const target = client
.target("https://run.mocky.io");
const response = await target
.path("/v3/de314aa8-a521-47c4-8ff3-69b447dab89b")
.request()
.header(HttpHeaders.ACCEPT, MediaType.ANY_TEXT_TYPE.toString())
.get();
response.readEntity(fs.createWriteStream('get_response.txt'));
const client = new ClientBuilder()
.withTimeout(30, TimeUnit.Seconds)
.withFilter(new LoggingFilter(console.log))
.build();
const target = client
.target("https://run.mocky.io");
const response = await target
.path("/v3/de314aa8-a521-47c4-8ff3-69b447dab89b")
.request()
.post(Entity.json({test: 1}));
const obj = await response.readEntity(new JsonEntity());
const client = new ClientBuilder()
.withTimeout(30, TimeUnit.Seconds)
.withFilter(new LoggingFilter(console.log))
.withHttp2()
.build();
class ToUppercaseFilter extends Transform implements Filter {
filter(requestContext: RequestContext, responseContext?: ResponseContext): void {
responseContext?.pipe(this);
}
order(): FilterOrder {
return FilterOrder.PostRequest;
}
_transform(chunk: any, encoding: BufferEncoding, callback: TransformCallback) {
callback(null, String(chunk).toUpperCase());
}
equals(other: any): boolean {
return other == this;
}
}
interface Request {
accept(mediaType: MediaType): RequestBuilder;
acceptLanguage(locale: string): RequestBuilder;
acceptEncoding(encoding: Encoding): RequestBuilder;
cacheControl(cacheControl: CacheControl): RequestBuilder;
cookie(cookie: Cookie): RequestBuilder;
header(key: string, value: string): RequestBuilder;
get(): Promise<Response>;
put<T>(entity: Entity<T>): Promise<Response>
post<T>(entity: Entity<T>): Promise<Response>
delete<T>(entity: Entity<T>): Promise<Response>
build<T>(method: Method, entity?: Entity<T>): Promise<Response>;
}
interface Response {
getHeaders(): MultiValueMapType;
getStatusInfo(): StatusType
getStatus(): number;
getMediaType(): MediaType | undefined;
getEtag(): EntityTag | undefined;
getDate(): Date | undefined;
getLastModified(): Date | undefined;
getHeaderString(key: string): string
getCookies(): MultiValueMap<Cookie>;
readEntity<T>(unmarshaller: Unmarshal<T>): Promise<T>
readEntity(writable: Writable): Writable
}