#restful #fields #parser #filter #api #zalando #guideline

z157

Parser for fields filtering according to Zalando's RESTful API guideline #157

12 releases (1 stable)

1.0.0 Jan 6, 2025
0.6.0 Jan 6, 2025
0.5.0 Jan 6, 2025
0.4.0 Dec 28, 2024
0.0.3 Dec 19, 2024

#166 in HTTP server

Download history 710/week @ 2024-12-17 293/week @ 2024-12-24 154/week @ 2024-12-31 180/week @ 2025-01-07

1,337 downloads per month

MIT/Apache

26KB
446 lines

z157

Crates.io docs.rs (with version)

Parser for the field filter defined in Zalando's RESTful API and Event guideline #157.

When would I need this?

If your HTTP service accepts a query parameter that lets the caller specify which fields they would like, this crate helps you parse such a string.

GET http://localhost/users/0001?fields=(age,address(street,city))

The value of the fields query parameter is parsed into a tree of field names.

Example

An example program is found in the examples/ directory. You can run it like this:

cargo run --example example -- '-(name,bio(height_cm),last_seen)'

A more simple example is shown below:

use z157::Tree;

fn main() {
    // Select fields to include
    let tree = Tree::parse("(name,bio(height(meters,centimeters),age))").unwrap();

    assert!(!tree.negation());
    let height = tree.index(&["bio", "height"]).unwrap();
    assert!(height.children().any(|field| field.name() == "meters"));
    assert!(height.children().any(|field| field.name() == "centimeters"));

    for field in tree.walk() {
        // z157::Field::path returns a vector of ancestors from the top-level
        // field name until and including itself.
        println!("{}", field.path().join("."));
        // This would print out:
        // name
        // bio
        // bio.height
        // bio.height.meters
        // bio.height.centimeters
        // bio.age
    }

    // Select fields to exclude
    let tree = Tree::parse("!(bio)").unwrap();

    assert!(tree.negation());
}

The field filter specification

<fields>            ::= [ <negation> ] <fields_struct>
<fields_struct>     ::= "(" <field_items> ")"
<field_items>       ::= <field> [ "," <field_items> ]
<field>             ::= <field_name> | <fields_substruct>
<fields_substruct>  ::= <field_name> <fields_struct>
<field_name>        ::= <dash_letter_digit> [ <field_name> ]
<dash_letter_digit> ::= <dash> | <letter> | <digit>
<dash>              ::= "-" | "_"
<letter>            ::= "A" | ... | "Z" | "a" | ... | "z"
<digit>             ::= "0" | ... | "9"
<negation>          ::= "!"

Dependencies

~1MB
~17K SLoC