Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typescript generator #68

Merged
merged 95 commits into from
Jul 14, 2022
Merged

Typescript generator #68

merged 95 commits into from
Jul 14, 2022

Conversation

pmcelhaney
Copy link
Owner

Code to read an openAPI spec and generate TypeScript that Counterfact uses to implement a fake server. The files that export types are meant to stay in sync with the OpenAPI spec. The other files are meant to be used as a starting point for approximating the business logic of the real app.

Here's an example of the code generated for the pet store as of this writing.

/* paths/pets.types.ts */
import type { Pets } from "./../components/Pets.js";
import type { Error } from "./../components/Error.js";
export type HTTP_GET = ({ tools: any }) =>
  | {
      status: 200;
      contentType: "application/json";
      body: Pets;
    }
  | {
      status: number | undefined;
      contentType: "application/json";
      body: Error;
    }
  | { status: 415; contentType: "text/plain"; body: string };
export type HTTP_POST = ({ tools: any }) =>
  | {
      status: 201;
      contentType: "contentType";
      body: null;
    }
  | {
      status: number | undefined;
      contentType: "application/json";
      body: Error;
    }
  | { status: 415; contentType: "text/plain"; body: string };





/* paths/pets/{petId}.ts */
import type { HTTP_GET } from "./{petId}.types.js";
import { PetSchema } from "./../../components/Pet.js";
import { ErrorSchema } from "./../../components/Error.js";
export const GET: HTTP_GET = ({ tools }) => {
  const statusCode = tools.oneOf(["200", "default"]);

  if (statusCode === "200") {
    if (tools.accepts("application/json")) {
      const example = tools.oneOf([]);

      return {
        status: 200,
        contentType: "application/json",
        body: tools.randomFromSchema(PetSchema),
      };
    }
  }
  if (tools.accepts("application/json")) {
    const example = tools.oneOf([]);

    return {
      contentType: "application/json",
      body: tools.randomFromSchema(ErrorSchema),
    };
  }

  return {
    status: 415,
    contentType: "text/plain",
    body: "HTTP 415: Unsupported Media Type",
  };
};





/* components/Error.ts */
export type Error = { code: number; message: string };
export const ErrorSchema = {
  type: "object",
  required: ["code", "message"],
  properties: {
    code: { type: "integer", format: "int32" },
    message: { type: "string" },
  },
};





/* paths/pets/{petId}.types.ts */
import type { Pet } from "./../../components/Pet.js";
import type { Error } from "./../../components/Error.js";
export type HTTP_GET = ({ tools: any }) =>
  | {
      status: 200;
      contentType: "application/json";
      body: Pet;
    }
  | {
      status: number | undefined;
      contentType: "application/json";
      body: Error;
    }
  | { status: 415; contentType: "text/plain"; body: string };





/* components/Pets.ts */
import type { Pet } from "./Pet.js";
import { PetSchema } from "./Pet.js";
export type Pets = Array<Pet>;
export const PetsSchema = {
  type: "array",
  items: PetSchema,
};





/* components/Pet.ts */
export type Pet = { id: number; name: string; tag: string };
export const PetSchema = {
  type: "object",
  required: ["id", "name"],
  properties: {
    id: { type: "integer", format: "int64" },
    name: { type: "string" },
    tag: { type: "string" },
  },
};





/* paths/pets.ts */
import type { HTTP_GET } from "./pets.types.js";
import type { HTTP_POST } from "./pets.types.js";
import { PetsSchema } from "./../components/Pets.js";
import { ErrorSchema } from "./../components/Error.js";
export const GET: HTTP_GET = ({ tools }) => {
  const statusCode = tools.oneOf(["200", "default"]);

  if (statusCode === "200") {
    if (tools.accepts("application/json")) {
      const example = tools.oneOf([]);

      return {
        status: 200,
        contentType: "application/json",
        body: tools.randomFromSchema(PetsSchema),
      };
    }
  }
  if (tools.accepts("application/json")) {
    const example = tools.oneOf([]);

    return {
      contentType: "application/json",
      body: tools.randomFromSchema(ErrorSchema),
    };
  }

  return {
    status: 415,
    contentType: "text/plain",
    body: "HTTP 415: Unsupported Media Type",
  };
};
export const POST: HTTP_POST = ({ tools }) => {
  const statusCode = tools.oneOf(["201", "default"]);

  if (statusCode === "201") {
  }
  if (tools.accepts("application/json")) {
    const example = tools.oneOf([]);

    return {
      contentType: "application/json",
      body: tools.randomFromSchema(ErrorSchema),
    };
  }

  return {
    status: 415,
    contentType: "text/plain",
    body: "HTTP 415: Unsupported Media Type",
  };
};

This branch is way too big. I'm not sure if I'm going to merge it or consider it "one to throw away" and rebuild everything in smaller steps with good testing discipline.

For now, my focus is on getting to a state where I can do a demo in order to (a) prove to myself that this is actually going to work and (b) articulate the vision.

…e process but finally ready to merge this monstrosity.
@pmcelhaney pmcelhaney merged commit 07a4e9a into main Jul 14, 2022
@pmcelhaney pmcelhaney deleted the typescript-generator branch July 14, 2022 21:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant