qs_dart는 인기 있는 JavaScript qs 라이브러리에서 영감을 얻어 쿼리 문자열의 인코딩과 디코딩을 위한 Dart 라이브러리입니다. URL 쿼리 매개변수의 강력한 파싱 및 문자열화를 제공하며, 중첩된 객체, 배열 및 사용자 정의 구분자를 지원합니다. 웹 및 모바일 애플리케이션에서 HTTP 요청 및 응답 데이터를 처리하는 데 이상적이며, 플랫폼 간 일관된 쿼리 문자열 형식을 보장합니다. 이 패키지는 가볍고 잘 테스트되었으며 모든 주요 Flutter 플랫폼과 호환됩니다.
사용 사례
URL 쿼리 매개변수 파싱
동적 API URL 만들기
HTTP 요청에서 폼 데이터 처리
중첩된 객체를 쿼리 문자열로 직렬화하기
REST API와의 상호 운용성
주요 기능
중첩된 개체 인코딩을 지원
쿼리에서 배열 구문 처리
사용자 정의 가능한 구분 기호 및 깊이 옵션
강력한 오류 처리
크로스 플랫폼 호환성
적합한 대상
웹 및 모바일 앱 개발자
API 통합
폼 데이터 처리
백엔드 호환 쿼리 문자열 처리
고려 사항
복잡한 중첩 구조를 위해 신중한 구성이 필요할 수 있습니다
전체 URL 조작을 위한 것이 아님
쿼리 문자열 작업만 가능
경계 사례에 대해 외부 JS 라이브러리의 동작에 의존합니다
원본 README
연결된 소스 저장소의 README 원문 스냅샷입니다. 최신 내용은 저장소에서 확인하세요.
qs_dart
A query string encoding and decoding library for Dart.
Multiple list formats: indices (a[0]=x), brackets (a[]=x), repeat (a=x&a=y), comma (a=x,y) with optional comma round‑trip.
Dot notation: parse/encode a.b=c as nested; options to encode or decode literal dots in keys (encodeDotInKeys / decodeDotInKeys).
Charset & sentinel: UTF‑8 (default) and Latin‑1; charsetSentinel (utf8=✓) to auto‑detect encoding.
Hooks & controls: custom encoder/decoder, encode keys‑only or values‑only, alternate delimiters (string or RegExp), ignore leading ?.
Duplicates & empties: strategies for duplicates (combine/first/last); allow empty list items (foo[]) with allowEmptyLists.
Null handling: strictNullHandling, skipNulls, and clear empty‑string behavior.
Safety limits: configurable depth, strictDepth, parameterLimit, listLimit, and parseLists toggle.
Dates & ordering: pluggable serializeDate, stable key ordering with sort, selective output via filter.
RFC modes: spaces as %20 (RFC 3986, default) or + (RFC 1738).
Dart‑friendly: Uri.queryParametersQs() and Uri.toStringQs() extensions for idiomatic usage in Dart/Flutter.
Installation
Add the package to your project:
For Dart projects:
dart pub add qs_dart
For Flutter projects:
flutter pub add qs_dart
Agent skill
This repo includes an optional agent skill at
skills/qs-dart/ for users who want Codex or another
compatible agent to help prepare qs_dart encoding and decoding snippets. The skill is user-facing: it focuses on Dart
and Flutter usage, option selection, query-string interoperability, and edge-case caveats.
[decode] allows you to create nested [Map]s within your query strings, by surrounding the name of sub-keys with
square brackets []. For example, the string 'foo[bar]=baz' converts to:
By default, nested [Map]s are decoded up to 5 levels deep. For example, decoding
a string like 'a[b][c][d][e][f][g][h][i]=j' yields the following [Map]:
The depth limit helps mitigate abuse when [decode] is used to parse user input, and it is recommended to keep it a
reasonably small number. [DecodeOptions.strictDepth] adds a layer of protection by throwing a [RangeError] when the
limit is exceeded, allowing you to catch and handle such cases.
For similar reasons, by default [decode] parses up to 1000 parameters. Override with
[DecodeOptions.parameterLimit]:
Decode percent-encoded dots in keys with [DecodeOptions.decodeDotInKeys].
Note: it implies [DecodeOptions.allowDots], so [decode] will error if you set [DecodeOptions.decodeDotInKeys]
to true, and DecodeOptions.allowDots to false.
Some services add an initial utf8=✓ value to forms so that old Internet Explorer versions are more likely to submit the
form as utf-8. Additionally, the server can check the value against wrong encodings of the checkmark character and detect
that a query string or application/x-www-form-urlencoded body was not sent as utf-8, eg. if the form had an
accept-charset parameter or the containing page had a different character set.
QS supports this mechanism via the [DecodeOptions.charsetSentinel] option.
If specified, the utf8 parameter will be omitted from the returned [Map].
It will be used to switch to [latin1] or [utf8] mode depending on how the checkmark is encoded.
Important: When you specify both the [DecodeOptions.charset] option and the [DecodeOptions.charsetSentinel] option,
the [DecodeOptions.charset] will be overridden when the request contains a utf8 parameter from which the actual charset
can be deduced. In that sense the [DecodeOptions.charset] will behave as the default charset rather than the authoritative
charset.
Note that the only difference between an index in a [List] and a key in a [Map] is that the value between the brackets
must be a number to create a [List]. When creating [List]s with specific indices, [decode] will compact a sparse
[List] to only the existing values preserving their order:
[decode] will also limit specifying indices in a [List] to a maximum index of 20.
Any [List] members with an index of greater than 20 will instead be converted to a [Map] with the index as the key.
This is needed to handle cases when someone sent, for example, a[999999999] and it will take significant time to iterate
over this huge [List].
[DecodeOptions.listLimit] is a maximum element count. With the default limit of
20, a[19]=b can still become a [List], while a[20]=b falls back to a [Map].
To disable List parsing entirely, set [DecodeOptions.parseLists] to false.
Note: when a value is a ByteBuffer, it is still decoded using the selected
charset even when encode is false, so the emitted value reflects the buffer
contents.
Encoding can be disabled for keys by setting the [EncodeOptions.encodeValuesOnly] option to true:
Examples beyond this point will be shown as though the output is not URI encoded for clarity.
Please note that the return values in these cases will be URI encoded during real usage.
When [List]s are encoded, they follow the [EncodeOptions.listFormat] option, which defaults to [ListFormat.indices]:
Note: When using [EncodeOptions.listFormat] set to [ListFormat.comma], you can also pass the [EncodeOptions.commaRoundTrip]
option set to true or false, to append [] on single-item [List]s, so that they can round trip through a parse.
Set [EncodeOptions.commaCompactNulls] to true with the same format when you'd like to drop null entries instead of keeping empty slots (for example, [true, false, null, true] becomes true,false,true).
When [Map]s are encoded, by default they use bracket notation:
Caveat: when both [EncodeOptions.encodeValuesOnly] and [EncodeOptions.encodeDotInKeys] are true, only dots in keys are encoded; values remain unchanged.
You may allow empty [List] values by setting the [EncodeOptions.allowEmptyLists] option to true:
If you only want to override the serialization of [DateTime] objects, you can provide a custom [DateSerializer] in the
[EncodeOptions.serializeDate] option:
Finally, you can use the [EncodeOptions.filter] option to restrict which keys will be included in the encoded output.
If you pass a [Function], it will be called for each key to obtain the replacement value.
Otherwise, if you pass a [List], it will be used to select properties and [List] indices to be encoded:
To distinguish between null values and empty [String]s use the [EncodeOptions.strictNullHandling] flag.
In the result string the null values have no = sign:
You can use the [EncodeOptions.charsetSentinel] option to announce the character by including an utf8=✓ parameter with
the proper encoding of the checkmark, similar to what Ruby on Rails and others do when submitting forms.
By default, the encoding and decoding of characters is done in [utf8], and [latin1] support is also built in via
the [EncodeOptions.charset] and [DecodeOptions.charset] parameter, respectively.
If you wish to encode query strings to a different character set (i.e.
Shift JIS) you can use the euc package
expect(
QS.encode(
{
'a': 'こんにちは!',
},
EncodeOptions(
encoder: (str, {Encoding? charset, Format? format}) {
if ((str asString?)?.isNotEmpty ?? false) {
finalUint8List buf = Uint8List.fromList(
ShiftJIS().encode(str!),
);
finalList<String> result = [
for (int i = 0; i < buf.length; ++i) buf[i].toRadixString(16)
];
return'%${result.join('%')}';
}
return'';
},
),
),
equals('%61=%82%b1%82%f1%82%c9%82%bf%82%cd%81%49'),
);
The default [EncodeOptions.format] is [Format.rfc3986] which encodes ' ' to %20 which is backward compatible.
You can also set the [EncodeOptions.format] to [Format.rfc1738] which encodes ' ' to +.