Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ copier copy gh:quickplates/next .
- package management with [`npm`](https://www.npmjs.com)
- embracing [`TypeScript`](https://www.typescriptlang.org) to the fullest
- server-side configuration with [`zod-config`](https://github.com/alexmarqs/zod-config)
- code generation for APIs with [`Hey API`](https://heyapi.dev)
- backend for frontend pattern with [`oRPC`](https://orpc.unnoq.com)
- state management with [`Valtio`](https://valtio.dev)
- clean UI with [`Mantine`](https://mantine.dev)
Expand Down
2 changes: 2 additions & 0 deletions src/.dockerignore.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ next-env.d.ts
{%- if docs %}
/docs/
{%- endif %}
/openapi/
/.copier-answers.yaml
/.dockerignore
/.envrc
Expand All @@ -40,6 +41,7 @@ next-env.d.ts
/Dockerfile
/eslint.config.mjs
/LICENSE
/openapi-ts.config.mts
/README.md
/stylelint.config.mjs
/Taskfile.dist.yaml
2 changes: 1 addition & 1 deletion src/.gitignore.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
/build/

# Debug
npm-debug.log*
*.log

# Typescript
*.tsbuildinfo
Expand Down
27 changes: 27 additions & 0 deletions src/Taskfile.dist.yaml.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,33 @@ tasks:
--clean
--overwrite
{{ '{{ .CLI_ARGS }}' }}
apis:
desc: Generate code for APIs
sources:
- openapi/**/*
- flake.lock
- "*.nix"
- openapi-ts.config.mts
- package-lock.json
- package.json
- Taskfile.dist.yaml
- "{taskfile,Taskfile}.{yaml,yml}"
- tsconfig.json
generates:
- src/common/apis/**/*
cmds:
- task: install-internal
vars:
CLI_ARGS: ""
- >
npm
exec
--
openapi-ts
{{ '{{ .CLI_ARGS }}' }}
- task: fmt
vars:
CLI_ARGS: src/common/apis
dev:
desc: Run in development mode
interactive: true
Expand Down
4 changes: 4 additions & 0 deletions src/docker-compose.yaml.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ services:
context: ./
network: host
environment:
- "{{ envprefix }}__APIS__ICANHAZDADJOKE__HOST=${ {{- envprefix }}__APIS__ICANHAZDADJOKE__HOST:-icanhazdadjoke.com}"
- "{{ envprefix }}__APIS__ICANHAZDADJOKE__PATH=${ {{- envprefix }}__APIS__ICANHAZDADJOKE__PATH:-}"
- "{{ envprefix }}__APIS__ICANHAZDADJOKE__PORT=${ {{- envprefix }}__APIS__ICANHAZDADJOKE__PORT:-}"
- "{{ envprefix }}__APIS__ICANHAZDADJOKE__SCHEME=${ {{- envprefix }}__APIS__ICANHAZDADJOKE__SCHEME:-https}"
- "{{ envprefix }}__DEBUG=${ {{- envprefix }}__DEBUG:-true}"
- "{{ envprefix }}__SERVER__HOST=${ {{- envprefix }}__SERVER__HOST:-0.0.0.0}"
- "{{ envprefix }}__SERVER__PORT=${ {{- envprefix }}__SERVER__PORT:-{{ port -}} }"
Expand Down
6 changes: 5 additions & 1 deletion src/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineConfig } from "@eslint/config-helpers";
import { defineConfig, globalIgnores } from "@eslint/config-helpers";
import jseslint from "@eslint/js";
import nexteslint from "@next/eslint-plugin-next";
import tanstackqueryeslint from "@tanstack/eslint-plugin-query";
Expand All @@ -10,6 +10,7 @@ import globals from "globals";
import tseslint from "typescript-eslint";

const files = {
ignored: ["build/", "node_modules/", "src/common/apis/"],
js: ["**/*.js", "**/*.cjs", "**/*.mjs", "**/*.jsx"],
ts: ["**/*.ts", "**/*.cts", "**/*.mts", "**/*.tsx"],
tsproject: [
Expand All @@ -27,6 +28,9 @@ const files = {
};

export default defineConfig(
// Global ignores
globalIgnores(files.ignored),

// JavaScript support
{
files: files.js,
Expand Down
122 changes: 122 additions & 0 deletions src/openapi-ts.config.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import type { UserConfig } from "@hey-api/openapi-ts";

import { defineConfig } from "@hey-api/openapi-ts";

export default defineConfig(
[
{
name: "icanhazdadjoke",
},
].map(
({ name }) =>
({
input: {
path: `./openapi/${name}.yaml`,
},

output: {
fileName: {
// Custom file name mappings
name: (name) => {
switch (name) {
case "client":
return "clnt";
case "zod":
return "schemas";
default:
return name;
}
},

// Don't add any suffix to generated files
suffix: null,
},

// Don't generate index file
indexFile: false,

path: `./src/common/apis/${name}`,
},

parser: {
filters: {
// Exclude deprecated resources
deprecated: false,

// Exclude orphaned resources
orphans: false,
},
},

plugins: [
// Generate types
{
definitions: {
name: "{{name}}",
},

errors: {
error: "{{name}}Error",
name: "{{name}}Errors",
},

name: "@hey-api/typescript",

requests: {
name: "{{name}}Request",
},

responses: {
name: "{{name}}Responses",
response: "{{name}}Response",
},
},

// Generate Zod schemas
{
// Use PascalCase for schema names
case: "PascalCase",

definitions: {
name: "{{name}}Schema",
},

// Include metadata in schemas
metadata: true,

name: "zod",

requests: {
name: "{{name}}RequestSchema",
},

responses: {
name: "{{name}}ResponseSchema",
},
},

// Generate Fetch API client
{
name: "@hey-api/client-fetch",
},

// Generate SDK
{
// Generate SDK class
asClass: true,

// Don't use generated client by default
client: false,

// Make SDK class instantiable
instance: true,

name: "@hey-api/sdk",

// Use generated schemas for validation
validator: true,
},
],
}) satisfies UserConfig,
),
);
41 changes: 41 additions & 0 deletions src/openapi/icanhazdadjoke.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
openapi: "3.1.2"
info:
title: icanhazdadjoke
version: "1"
paths:
/:
get:
summary: Get a random joke
operationId: getRandomJoke
responses:
"200":
description: Successful response with a random joke
content:
application/json:
schema:
$ref: "#/components/schemas/GetRandomJokeSuccessResponsePayload"
components:
schemas:
GetRandomJokeSuccessResponsePayload:
description: Success response payload for getting a random joke
type: object
properties:
id:
description: Unique identifier of the joke
type: string
example: R7UfaahVfFd
joke:
description: The text of the joke
type: string
example: >-
My dog used to chase people on a bike a lot.
It got so bad I had to take his bike away.
status:
description: Status code of the response
type: integer
const: 200
example: 200
required:
- id
- joke
- status
Loading
Loading