Hacker News new | comments | show | ask | jobs | submit login
RESTyped: End-To-end Typing for REST APIs with TypeScript (falcross.com)
91 points by rawrmaan 10 months ago | hide | past | web | favorite | 29 comments



Can't you already do this using Swagger Codegen?

I use swashbuckle to automatically generate swagger https://www.nuget.org/packages/Swashbuckle/

Then paste swagger definition into the online editor to generate TypeScript client: https://swagger.io/swagger-editor/

(You can also generate offline).

How is RESTyped better than Swagger Codgen?


This is pretty cool, I hadn't seen it before!

RESTyped has a couple of advantages over this:

- RESTyped definitions are extremely lightweight and don't require shipping an API wrapper with a bunch of generated code

- No build/manual copy step required. Easy to distribute typings on NPM.


I don't understand the advantages, could you clarify?

- In what way are RESTyped definitions lighter? A Swagger definition is just a JSON or YAML file and can be used without shipping any additional code (e.g. by https://github.com/swagger-api/swagger-js).

- Swagger only requires a build step when the definition is used to generate code. Definitions can be distributed via NPM (e.g. https://www.npmjs.com/package/appveyor-swagger).

Edit: I realized you were talking about RESTyped being lighter/nobuild compared to Swagger Codegen specifically for TypeScript because it is written in TypeScript. Seems reasonable.


Swagger is a de facto standard for automatically generating JSON descriptions of REST API and for generating UI for invoking/experimenting with REST APIs. Swagger codegen is good but not terrific. Alternatives would be welcome. I recommend layering your code gen over swagger.


Swagger is the basis and a great implementation of OpenAPI which is a standard.

https://www.openapis.org


Allow me to be a bit autistic here: these APIs are barely REST-ful. They are effectively RPC, which is appropriate, because REST doesn't easily apply to a non-hypertext data format, which disallows HATEOAS.

I wish XML-RPC hadn't ruined things so utterly, so we could properly refer to these APIs as JSON-RPC and leave REST for hypertext-based architectures (e.g. intercooler.js + html)


I am a Python (Django) and CoffeeScript (with Ember) fan who really wants to learn TypeScript. I already use VSCode.

This project looks very promising for building full-stack apps spanning Node and the browser. One thing I would love to see eventually is a reduction in the need for manually pulling attributes from the request body and parsing query params. Does this provide a foundation for building a frictionless end-to-end experience via data adapters (which have served me well in Django/Ember projects, despite some mismatches)?


We have been using GraphQL for almost a year now and I'm really pleased with it. In my mind it both solves the type issue, while also providing great flexibility in what data to fetch. I guess this could be used to improve an existing REST API without the big cost of moving to GraphQL (which might even be impossible sometimes).

Maybe there are also some situations where GraphQL fails, I would definitely be interested to hear about that.


One of my complaints with GraphQL (as an observer; I've not yet directly worked with GraphQL) is that while it has a bunch of type information, most of that is fairly opaque to Typescript itself: queries themselves are mostly opaque strings, and most examples I've seen of query usage (and this may be mostly just a problem with wild examples as opposed to real usage) most of them just use the result of a query call as any-typed, manual type assertion, or manual generic argument to the query call.

It seems to me that all of GraphQL's type information should be easier to use in Typescript.

I have noticed there is a compiler of .graphql files to .d.ts files [1], and I could see using something like that the way that RESTyped is used in the article here (though it's "backwards" from the RESTyped model where the Typescript definitions are the source of truth [2]), but at least in examples I've seen to date of GraphQL in the wild it does seem like there is a similar need in the GraphQL world for something like RESTyped.

[1] https://www.npmjs.com/package/graphql-typescript-definitions

[2] Which leads me to wondering if it would be nice to have a Typescript Definition file to GraphQL compiler.


Yes, it's really important to have the frontend types generated directly from what the backend generated graphql schema specifies. We shouldn't have to type anything at all.

I wrote an article about using apollo-codegen to generate all the Typescript types:

https://medium.com/@crucialfelix/bridging-the-server-client-...

It's still a few steps too many, but it's getting there.

I'm about to write up the second article which deals with mutations. This lets me import only one type:

    import { SetAptListOnWebProps } from "../mutations";
and then this.props.mutate is fully typed:

    (property) mutate: (options: MutationOptions<{
        apt: string;
        listOnWeb: boolean;
    }, {
        setAptListOnWeb: {
            apt: {
                id: string;
                listOnWeb: boolean;
                __typename: "Apt";
            };
            __typename: "SetAptListOnWebPayload";
        };
    }>) => Promise<{
        data: {
            setAptListOnWeb: {
                apt: {
                    id: string;
                    listOnWeb: boolean;
                    __typename: "Apt";
                };
                __typename: "SetAptListOnWebPayload";
            };
        };
        errors?: GraphQLError[];
        loading: boolean;
        networkStatus: NetworkStatus;
        stale: boolean;
    }>
First type argument is the mutation input variables, the optional second is the shape of the optimistic response.


If you use Apollo as your GraphQL client, there's apollo-codegen [0], which supports generating both Flow and TypeScript type definitions.

Relay Modern's query compiler also generates Flow types AFAIK.

But that's only for the client side. I suppose if you'd like to use typed JavaScript on the server side, something like the library you've posted might be your best bet, since client side solutions like apollo-codegen generate types based on the exact set of queries in your client-side app, which might not be all that useful for implementing the GraphQL server itself (unless maybe your API is private and you can afford to implement some form of persisted queries?). Having access to all the individual base types specified in your schema would probably be more useful for that purpose.

[0] https://github.com/apollographql/apollo-codegen


Yes, that's the big thing I've been seeing: it's definitely the server-side story that seems somewhat deficient right now, in terms of end-to-end types. It does seem like a server built with Typescript should be able to save a lot of manual GraphQL writing work and reuse a bunch of Typescript type information, but I don't feel like I've seen a lot of examples and/or libraries of people doing that.


> Maybe there are also some situations where GraphQL fails, I would definitely be interested to hear about that.

I know one, but it will take you a while to realize it. Allowing a lot of flexibility in query types makes it harder to optimize later when you can't predict the code paths your clients will take. In the API world, I have learned the hard way that flexibility is a bad thing especially compared to specific ways to obtain data and very optimizable, well-known "hot" paths to data.


You can always use analytics on the calls made to find hot code paths.


This misses the point. I'm not talking about finding hot paths, I'm talking about limiting the total predictable path count so you can optimize better. Or, as I often saw, when you have so many paths to different data pieces, you don't test every permutation of every combination of paths, and a caller finds one that hurts for some reason (e.g. bad optimization choice by your RDBMS).


Yes, but with analytics in place you'll find that when it happens and be able to fix it?


I've been using something similar and it solves many problems elegantly. You use a build step to connect to the server and run an introspection query to get all server types ran generated dynamically as .ts files (or .js for flow). Then your code has access to your data model with very little to maintain: a dev can change the backend model in the server and you'll know right away. You almost don't need documentation, since the schema can also contain comments.

If anything, a GraphQL server can still be used in a RESTful manner (perform a pre-written query, get its results) so there's a lot of pros (with very, if any, cons) with using a GraphQL server.


We also support effortless end-to-end Typed API support in ServiceStack: http://docs.servicestack.net/typescript-add-servicestack-ref...

We're a strong believer in TypeScript which we've configured in all our .NET Core 2.0 / .NET Framework Single Page App project templates:

http://docs.servicestack.net/releases/v5.0.0#new-net-core-20...


I’ll have to give this a go.

I usually shared types from the backend to the front end in the same repo. Then change

    (data: any) 
To something like

    (data: User)
See this repo

https://github.com/styfle/react-server-example-tsx


I'm a developer at Habitat (the company mentioned in the article), and have been loving working with RESTyped so far. This has saved me so much time that I would usually spend debugging. It's really nice knowing what you should be passing to an endpoint as you type it. If every API I worked with was RESTyped, life would be a dream.


In a way it is ironic how with Swagger, RESTtyped we are getting back to IDLs and WSDL.

Maybe old dogs did understand a few things about doing distributed programming.


Yup. Someone on Reddit suggested making an OpenAPI/Swagger -> RESTyped adapter. If people are interested in this, I'm all for it.


> Someone on Reddit

Got a link to the thread?



It may be hoped that the next incarnation of this will deal with change better. It's really not enough to just deface every URL with a "/v2/" at the front. That way lies the madness that soured everyone on the great "web services" vision the first time around.


God I hate SOAP. Creating a client for WS-Deathstar was always an adventure.

The types are defined, so no need for documentation to explain the semantics. Oh, and if you don’t have the same tool stack, good luck getting the envelope header the way our server wants it.

Sometimes, there’s value in being able to add or omit attributes without some brittle (static) monstrosity messing itself.


Your link to the definition file, https://blog.falcross.com/introducing-restyped-end-to-end-ty..., is 404ing.


Fixed, thank you!


+1 for adding OpenAPI integration




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: