Code Monkey home page Code Monkey logo

ts.data.json's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

ts.data.json's Issues

How to decode discriminated union types with nested json?

Hi there,

I am new to front-end development and to json decoders. In my front-end TypeScript code I have the following discriminated union (DU) type:

type FooA = {
    duKind: "FooA",
    myPropA: string
}

type FooB = {
    duKind: "FooB",
    myPropB: number
}

type Foo = FooA | FooB

My back-end REST API returns either

{
    "foo" : {
        "fooA": {
            "myPropA": "Hello World"
        }
    }
}

or

{
    "foo" : {
        "fooB": {
            "myPropB": 42
        }
    }
}

depending on the DU case.

How can I map this to my DU types using decoders?

const fooADecoder: JsonDecoder.Decoder<FooA> = ???;
const fooBDecoder: JsonDecoder.Decoder<FooB> = ???;
const fooDecoder: JsonDecoder.Decoder<Foo> = JsonDecoder.oneOf<Foo>([
    fooADecoder,
    fooBDecoder
], "Foo");

I guess for the duKind I can use JsonDecoder.constant, but the main problem is that I have to reduce the "object nesting" from "foo": { "fooA": { "myPropA": ...}} in JSON to {myPropA: ...} in TypeScript.

This problem probably is not limited to DUs, but a general question of how to reduce/compress/squeeze JSON object nesting levels within a decoder.

Any help would be much appreciated, since this is a show stopper for me right now.

Improve the case where the input to a decoder is not an object

I just spent a fair bit of time trying to debug why an object decoder was failing, only to eventually consult the code and realize it's because the input I was passing was a JSON string rather than an actual object.

I think there are a couple of possible ways this could be better:

  1. The error given could clearly state the input is not an object rather than just saying it's not a valid decoderName.
  2. Strings could be automatically parsed to json.
  3. The input to the decoder could be set to a more specific type than Any so the compiler could catch this.

Let me know what your thoughts are. If you'd like I can send a PR to do some or all of these, but I want to hear what you think first.

How to use JsonDecoder.dictionary for decoding a Map instance?

Hi there,

my ASP.NET back end returns this json

{
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "status": 400,
    "title": "One or more validation errors occurred.",
    "errors": {
        "foo": [
            "The foo field is required."
        ],
        "bar": [
            "Input string '1625F' is not a valid double for bar."
        ]
    },
    "traceId": "00-a531fd30a1f7824aa76c520f60201977-073a8f282c1beb47-00"
}

for validation errors.

I modelled this in Typescript as follows:

export type ValidationProblem = Readonly<{
    type: string
    status: number
    title: string
    errors: Readonly<Map<string, readonly string[]>>
    traceId: string
}>

My decoder looks like this:

const validationProblemDecoder: JsonDecoder.Decoder<ValidationProblem> =
    JsonDecoder.objectStrict({
        type: JsonDecoder.string,
        status: JsonDecoder.number,
        title: JsonDecoder.string,
        errors: JsonDecoder.dictionary(JsonDecoder.array(JsonDecoder.string, "ErrorEntries"), "Errors"),
        traceId: JsonDecoder.string
        }, "ValidationProblem")

but I get a type error message:

Type 'Decoder<{ type: string; status: number; title: string; errors: { [name: string]: string[]; }; traceId: string; }>' is not assignable to type 'Decoder<Readonly<{ type: string; status: number; title: string; errors: Readonly<Map<string, readonly string[]>>; traceId: string; }>>'.
  Type '{ type: string; status: number; title: string; errors: { [name: string]: string[]; }; traceId: string; }' is not assignable to type 'Readonly<{ type: string; status: number; title: string; errors: Readonly<Map<string, readonly string[]>>; traceId: string; }>'.
    Types of property 'errors' are incompatible.
      Type '{ [name: string]: string[]; }' is missing the following properties from type 'Readonly<Map<string, readonly string[]>>': clear, delete, forEach, get, and 6 more.

How can I turn the dictionary into a Map instance? I am not familiar with the index signature notation.

Question?

I just found this, and it looks very interesting. Do you have have an example of how the "hasLength" decoder would work. I can't seem to figure it out on my own.

Public functions in the class are identifie as a property.

Hi Everyone

First at all, thank you for putting this code together. I have a class with properties and gets/sets but also with extra function for specific behavior. The problem is that I get a error "...is missing the following properties from type 'DecoderObject': addOption, setOptions". Do you have any idea how to fix this?

Example
`export class Study {
private _name: string;
private _description: string;
private _goal: Goal[];

private _organizationName: string;

public readonly studyID: string;
public readonly organizationId: string;
public readonly owner: string;
public readonly ownerEmailAddress: string;
public static toApiDto(pItem: Study): ApiStudyDTO {
(...)
}

public static fromApiDTO(pItem: ApiStudyDTO): Study {
(โ€ฆ.)
}
public get name(): string { return this._name; }
public set name(pValue: string) { this._name = pValue; }

public get description(): string { return this._description; }
public set description(pValue: string) { this._description = pValue; }

public get organizationName(): string { return this._organizationName; }
public set organizationName(pValue: string) { this._organizationName = pValue; }

public set goal(pValue: Goal[]) { this._goal = pValue; }
public get goal(): Goal[] { return this._goal; }

public addOption(pStudyOption: StudyOption) {
this.options.splice(0, 0, pStudyOption);
}

public setOptions(pStudyOptions: Array) {
this.options = pStudyOptions;
}
}`

and my JsonDecoder.Object definition is
JsonDecoder.object<Study>({ name: JsonDecoder.string, description: JsonDecoder.string, goal: JsonDecoder.array<Goal>(GoalDecoders.Goal, 'Goal[]'), organizationName: JsonDecoder.string, studyID: JsonDecoder.string, organizationId: JsonDecoder.string, owner: JsonDecoder.string, ownerEmailAddress: JsonDecoder.string, ownerName: JsonDecoder.string, studyDate: Decoders.isDate(), options: JsonDecoder.array<StudyOption>(StudyOptionDecoders.StudyOption, 'StudyOption[]') }, 'Study');
best
Hmendezm

Wish List

Hey! Just adopted this library for a big project at work. Thanks for putting it together (or at least, thanks for sprucing up the thing you forked it from).

There are a few things that I think would make this a lot more usable. If you're interested, I'd be happy to submit some PRs:

  • Implementing the Fantasy Land Spec (mainly just .ap() and .map()) on Ok and Err
  • Using property accessors to auto-bind .decode() and .decodeThen() to make them easier to use in point-free compositions
  • Exposing additional metadata in Err to allow more flexible handling, i.e. building validation, etc.

Let me know what you think! Thanks again.

How would you decode an empty object

I use ts.data.json to decode incoming api req.body. I have one endpoint that I expect that no parameters should be passed in. the express body parser returns an empty object. I would ideally like to verify its an empty object.

When I try.

JsonDecoder.isExactly({})

I get an error {} is not {}

which makes sense because they are different objects.

so I tried.

JsonDecoder.objectStrict<{}>({}, 'GET /');

which lets everything pass.

Just curious what you would suggest.

Thanks!

FR: Easier to navigate (and complete) API reference

This library would be easier to use if you had an autogenerated API reference that makes it easy to see all the functions available.

For example, I just discovered that both Err and Ok have an isOk method by reading the code. These methods are useful and it'd be nice if they were easier to find. That said, the code is very readable from what little I've seen.

FR: Decode to class instance

I could use something like JsonDecoder.object, but which returns a class instance rather than a plain object. You can work around this by having an interface FooData and a class Foo that implements FooData and takes FooData as the argument to the constructor, but I'd rather eliminate all that boilerplate.

I'm fairly certain it's possible to do this, but I'm not sure if it's possible to do this without type assertions.

Not working with Artifactory because of unfortunate name

Hello,
this is a great library and I want to use it in a major organization - however all our npm install's are proxied through a corporate Artifactory instance.
This library has an unconventional for an npm packgae name with dots and not dashes (ts-data-json ๐Ÿค” ) which prevents Artifactory from letting me install it, as it thinks I'm trying to install a *.json file.

any chance this can be renamed to a more conventional dash-separated notation?

Just wanted to say thanks

I really appreciate this project. We have used it on a number of our projects now. The typescript generics are awesome to make sure that you are matching well.

Thanks

Optionally fail object decoder when encountering unknown keys

My use case: I have 1600 JSON files with complex structure that I want to type. The way I want to approach this is by iteratively running the decoder, inspecting the first error message and extending the decoder. I don't know in advance which fields those JSON files have, I want the decoder to help me in finding this out. I thus want the decoder to fail whenever it encounters an unknown object key.

Similar option exists in tcomb-validation is called strict.

Typescript helper function to extract decoder type

The current example looks like this.

type User = {
  firstname: string;
  lastname: string;
};

const userDecoder = JsonDecoder.object<User>(
  {
    firstname: JsonDecoder.string,
    lastname: JsonDecoder.string
  },
  'User'
);

But shouldnt it possbile to write something like this?:

const userDecoder = JsonDecoder.object(
  {
    firstname: JsonDecoder.string,
    lastname: JsonDecoder.string
  },
  'User'
);
type User = ExtractDecoderType<typeof userDecoder>;

This way I dont not have to repeat myself.

ts.data.json 2.0?

So I really like ts.data.json, and a while back I decided to open an issue in the Deno Standard Library suggesting that they include a decoder module in deno standard. Eventually, I ended up trying my hand at a PR. While the PR hasn't gotten much traction (I think one of the reasons for this is that Deno just isn't far enough along for the maintainers to focus on the standard library much), it did allow me to think critically about ts.data.json, and learn about some other, similar libraries.

For example, some of the issues I've had with ts.data.json:

  • The requirement that you provide a name argument to many decoders.
  • The formatting of the error messages -- I don't find the built-in format particularly useful, and often found myself re-writing the error messages.
  • Difficulty customizing error messages.
  • Inability for a decode function to return a promise (yes, you can pass a promise to a decoder as input, but the decode function itself can't be asynchronous).
  • Inability to return all errors (if appropriate) rather than the first.

I also learned that the decoder pattern is pretty popular (I imagine you already know this), and there are a number of typescript specific libraries to choose from. For example, io-ts for functional programming, or decoders which implements a pattern similar to this library. Some of the issues I've had with ts.data.json are addressed by these other libraries, but not all of them are. Also, the library with the best support for custom error messages I found, io-ts, is written in a functional style which doesn't appeal to me.

I decided to build out a new API to address these issues, and the repo can be seen here: https://gitlab.com/john.carroll.p/ts-decoders.

For me, the ts-decoders repo has become my ts.data.json 2.0. It provides a more extensible API with explicit support for customizing the error messages of decoders, is tree shakable, and has full async support. If you like the API / library, I'm open to upstreaming my work. This being said, I'm not sure updating this repo with that code makes the most sense (from a user's perspective), for a few reasons:

  1. The new repo is a complete rewrite of the API (though obviously it shares many concepts). Transitioning to the new API would be no different from transitioning to a different decoder library (e.g. decoders).
  2. This repo is still a fork of aische/JsonDecoder, and the ts-decoders library is not a fork of aische/JsonDecoder.
  3. The new API is not designed to specifically be a json decoders library. For example, you could create an AsyncDecoder to handle decoding io from a file. This makes the ts.data.json name a bit of a misnomer.

Instead, what I was thinking (if you are open to it) is inviting you to be a maintainer of the new library with me (if you're not interested in Gitlab, where it is currently located, I'm happy to move it to Github). FYI though, while I maintain a few open source typescript libraries (rSchedule, Angular IsLoading, Angular SizeObserver), I don't have any experience working with a co-maintainer, so I imagine there will be some growing pains. Personally, that's not something I'm not worried about, but I figured I should mention it.

Anyway, if you're not interested in the new API, or if you like the current ts.data.json API, I'm happy to go my own way with ts-decoders. Regardless, thanks again for all your work maintaining this library!

PS: If you have any questions about the new API, why decisions were made, etc, I'm happy to answer them. The repo is fully tested, and there's a good start on documentation in the readme, but all the code isn't fully commented.

Add better string validation

Cases with JsonDecoder.string make the key required to be a string, but sometimes the string can be an empty one e.g. "". Another case, would be when the value can be any string other than certain values e.g. would fail on "STOP".

In my case I need to ensure empty strings for required keys fail. Is there a way to do that?

In my eyes I see 2 ways to solve this 1) an opt-in feature to fail on an empty string value in case of a required key, 2) add an optional exclude value array for strings e.g. { exclude: ["value1", "value2"] }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.