Skip to content

medz/ht

Repository files navigation

ht

CI pub package Dart SDK License: MIT

ht stands for HTTP Types. It provides a fetch-first set of Dart HTTP abstractions.

This package focuses on the type and semantics layer only. It does not implement an HTTP client or server runtime.

Installation

dart pub add ht

Or add it manually to pubspec.yaml:

dependencies:
  ht: ^0.2.0

APIs

Category Types
Protocol HttpMethod, HttpStatus, HttpVersion, MimeType
Message Request, RequestInit, Response, ResponseInit, Body, BodyInit
Header/URL Headers, URLSearchParams
Binary/Form Blob, File, FormData

Quick Example

import 'package:ht/ht.dart';

Future<void> main() async {
  final request = Request(
    RequestInput.uri(Uri.parse('https://api.example.com/tasks')),
    RequestInit(
      method: HttpMethod.post,
      headers: Headers({'content-type': 'application/json; charset=utf-8'}),
      body: '{"title":"rewrite ht"}',
    ),
  );

  final response = Response.json(
    {'ok': true},
    ResponseInit(status: HttpStatus.created),
  );

  print(request.method); // POST
  print(request.headers.get('content-type')); // application/json; charset=utf-8
  print(await response.text());
}

Body Semantics

Request and Response use a single-consume body model:

  • After the first text() / bytes() / json() / blob() call (or stream read), bodyUsed == true
  • Reading the same instance again throws StateError
  • Use clone() when multiple reads are required

FormData Example

import 'package:ht/ht.dart';

Future<void> main() async {
  final form = FormData()
    ..append('name', Multipart.text('alice'))
    ..append(
      'avatar',
      Multipart.blob(
        Blob(<Object>['binary'], 'text/plain;charset=utf-8'),
        'avatar.txt',
      ),
    );

  final multipart = form.encodeMultipart();
  final bytes = await multipart.bytes();

  print(multipart.contentType);   // multipart/form-data; boundary=...
  print(multipart.contentLength); // body bytes length
  print(bytes.length);            // same as contentLength
}

Block Interop

Blob implements package:block Block, and BodyInit accepts Block values directly:

import 'package:block/block.dart' as block;
import 'package:ht/ht.dart';

Future<void> main() async {
  final body = block.Block(<Object>['hello'], type: 'text/plain');
  final request = Request(
    RequestInput.uri(Uri.parse('https://example.com')),
    RequestInit(method: HttpMethod.post, body: body),
  );

  print(await request.text());                  // hello
}

Blob Slice Semantics

Blob.slice(start, end) now follows Web Blob semantics. Negative indexes are interpreted from the end of the blob:

final blob = Blob(<Object>['hello world'], 'text/plain;charset=utf-8');
final tail = blob.slice(-5);
print(await tail.text()); // world

Development

dart pub get
dart format --output=none --set-exit-if-changed .
dart analyze
dart test
dart run example/main.dart

License

MIT

About

HTTP Types for Fetch-style APIs and protocol abstractions in Dart.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages