master 0542164d3c94 cached
20 files
24.1 KB
6.6k tokens
7 symbols
1 requests
Download .txt
Repository: Sean-Bradley/Seans-TypeScript-NodeJS-CRUD-REST-API-Boilerplate
Branch: master
Commit: 0542164d3c94
Files: 20
Total size: 24.1 KB

Directory structure:
gitextract_m3qilazq/

├── .github/
│   └── FUNDING.yml
├── .gitignore
├── .gitlab-ci.yml
├── Dockerfile
├── LICENSE
├── app.json
├── docker-compose.yml
├── nginx/
│   ├── Dockerfile
│   ├── nginx.conf
│   └── static/
│       └── index.html
├── package.json
├── readme.md
├── src/
│   ├── app.ts
│   ├── models/
│   │   ├── Bird.ts
│   │   ├── Cat.ts
│   │   └── Dog.ts
│   ├── router.ts
│   ├── server.ts
│   └── swagger.json
└── tsconfig.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: [Sean-Bradley]# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: seanwasere
open_collective: # Replace with a single Open Collective username
ko_fi: sean_bradley
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']


================================================
FILE: .gitignore
================================================
node_modules
npm-debug.log
dist/

================================================
FILE: .gitlab-ci.yml
================================================
image: docker:latest
services:
  - docker:dind

stages:
  - test
  - deploy

step-develop:
  stage: test
  before_script:
    - export DYNAMIC_ENV_VAR=DEVELOP
  only:
    - develop
  tags:
    - develop
  script:
    - echo running tests in $DYNAMIC_ENV_VAR

step-uat:
  stage: deploy
  before_script:
    - export DYNAMIC_ENV_VAR=UAT
  only:
    - uat
  tags:
    - uat
  script:
    - echo setting up env $DYNAMIC_ENV_VAR
    - sudo apt-get install -y python-pip
    - sudo pip install docker-compose
    - sudo docker image prune -f
    - sudo docker-compose -f docker-compose.yml build --no-cache
    - sudo docker-compose -f docker-compose.yml up -d

step-deploy-staging:
  stage: deploy
  before_script:
    - export DYNAMIC_ENV_VAR=STAGING
  only:
    - staging
  tags:
    - staging
  script:
    - echo setting up env $DYNAMIC_ENV_VAR
    - sudo apt-get install -y python-pip
    - sudo pip install docker-compose
    - sudo docker image prune -f
    - sudo docker-compose -f docker-compose.yml build --no-cache
    - sudo docker-compose -f docker-compose.yml up -d

step-deploy-production:
  stage: deploy
  before_script:
    - export DYNAMIC_ENV_VAR=PRODUCTION
  only:
    - production
  tags:
    - production
  script:
    - echo setting up env $DYNAMIC_ENV_VAR
    - sudo apt-get install -y python-pip
    - sudo pip install docker-compose
    - sudo docker image prune -f
    - sudo docker-compose -f docker-compose.yml build --no-cache
    - sudo docker-compose -f docker-compose.yml up -d
  when: manual





================================================
FILE: Dockerfile
================================================
FROM node:alpine

LABEL github=https://github.com/Sean-Bradley

COPY src /nodejs/src
COPY package.json /nodejs/package.json
COPY tsconfig.json /nodejs/tsconfig.json

WORKDIR /nodejs

RUN npm install

EXPOSE 3000:3000


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2019 seanwasere youtube

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: app.json
================================================
{
    "name": "seans-typescript-nodejs-crud-rest-api-boilerplate",
    "description": "A barebones TypeScript Node.js CRUD REST API",
    "repository": "https://github.com/Sean-Bradley/Seans-TypeScript-NodeJS-CRUD-REST-API-Boilerplate",
    "logo": "https://github.com/Sean-Bradley/Seans-TypeScript-NodeJS-CRUD-REST-API-Boilerplate/blob/master/cosmo1.png",
    "keywords": ["node", "typescript", "crud", "seanwasere"]
  }

================================================
FILE: docker-compose.yml
================================================
version: '2'
services:
  nginx:
    build: 
      context: nginx
      dockerfile: Dockerfile
    ports:
      - "80:80"
    command: nginx -g "daemon off";
    depends_on:
      - nodejs
      
  nodejs:
    build:
      context: .      
      dockerfile: Dockerfile
    image: service-cats:1.01
    expose:
      - "3000"
    command: npm start



================================================
FILE: nginx/Dockerfile
================================================
FROM nginx
LABEL github=https://github.com/Sean-Bradley
COPY /nginx.conf	/etc/nginx/nginx.conf
#COPY /server.crt	/etc/nginx/server.crt
#COPY /server.key	/etc/nginx/server.key
COPY /static	    /static


================================================
FILE: nginx/nginx.conf
================================================
user www-data;
worker_processes 1;
pid /run/nginx.pid;
events {
    worker_connections 768;
}
http {
    sendfile off;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    #access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
    gzip on;
    gzip_disable "msie6";
    server {
        listen 80;
        server_name localhost;
#ssl_certificate      server.crt;
#ssl_certificate_key  server.key;
        location / {
            root /static;
            index index.html;
        }
        location /api/ {
            proxy_pass_header Server;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Scheme $scheme;
            proxy_set_header X-Real-IP	$remote_addr;
            proxy_set_header X-Forwarded-For	$proxy_add_x_forwarded_for;
            proxy_redirect off;
            proxy_connect_timeout 20;
            proxy_read_timeout 20;
            proxy_pass http://nodejs:3000/;
        }
    }
}


================================================
FILE: nginx/static/index.html
================================================
put the static html generated from you favourite front end framework here.

================================================
FILE: package.json
================================================
{
  "name": "seans-typescript-nodejs-crud-rest-api-boilerplate",
  "version": "1.0.1",
  "description": "",
  "main": "server.js",
  "scripts": {
    "start": "tsc && node dist/server.js",
    "build": "tsc",
    "dev": "concurrently --kill-others \"tsc -w\" \"nodemon dist/server.js\""
  },
  "keywords": [
    "typescript",
    "nodejs",
    "crud",
    "rest",
    "swagger"
  ],
  "author": "Sean Bradley",
  "license": "ISC",
  "dependencies": {
    "@types/express": "^4.17.11",
    "@types/node": "^13.13.40",
    "body-parser": "^1.20.2",
    "cors": "^2.8.5",
    "express": "^4.18.2",
    "swagger-ui-express": "^5.0.0",
    "typescript": "^5.2.2",
    "uuid": "^9.0.1"
  },
  "devDependencies": {
    "concurrently": "^8.2.2",
    "nodemon": "^3.0.1"
  }
}


================================================
FILE: readme.md
================================================
## Seans-TypeScript-NodeJS-CRUD-REST-API-Boilerplate

> To help support this TypeScript boilerplate, please take a moment to look at my official **Design Patterns in TypeScript** book and **TypeScript Courses**. <br/>  
>  <img src="docs/threejs-course-image-w100.png" style="margin-bottom:-4px"> [Three.js and TypeScript](https://www.udemy.com/course/threejs-tutorials/?referralCode=4C7E1DE91C3E42F69D0F)
>
> <img src="docs/tssock-course-w100.png" style="margin-bottom:-4px"> [Socket.IO and TypeScript](https://www.udemy.com/course/typescript-socketio/?referralCode=2F6E227AC7EB9D147327)
>
> <img src="docs/threejs_typescript_116.jpg"> Three.js and TypeScript : [ASIN B094716FD6](https://www.amazon.com/dp/B09GYTKRCH)
>
> <img src="docs/dp_typescript_116.jpg"> Design Patterns in TypeScript : Paperback [ASIN B0948BCH24](https://www.amazon.com/dp/B0948BCH24), eBook : [ASIN B094716FD6](https://www.amazon.com/dp/B094716FD6)

### MIT License

Remember, No guarantees, or even fit for a particular purpose.

If you have a suggestion, or you want to contribute some code, you can make a pull request.

Your contributions will be visible since this project is public.

### Setup

```bash
npm install
```

### Development with nodemon and tsc --watch

```bash
npm run dev
```

Then visit `http://localhost:3000/cats`

### Run without nodemon and tsc --watch

```bash
npm start
```

Then visit `http://localhost:3000/cats`

## Swagger

Visit `http://localhost:3000/swagger` to view the OPENAPI document in Swagger-UI
![Swagger-UI](docs/swagger.png)

### Video tutorial on setting up Swagger in an existing NodeJS TypeScript API

[![Add Swagger-UI Documentation To Existing NodeJS TypeScript API](https://img.youtube.com/vi/qemG0CWOx1I/0.jpg)](https://youtu.be/qemG0CWOx1I)

## Continuous Integration and Deployment

I've also added gitlab-ci.yml and dockerised with Docker-Compose. See video tutorial on how all this works.
[![CI/CD a NodeJS API with Docker-Compose and GitLab](https://img.youtube.com/vi/Qlj6NiOy5jM/0.jpg)](https://youtu.be/Qlj6NiOy5jM)

## Usage

### List all records

![Example Get all records](docs/get-example.png)

### Post (Create) Record

![Example Post (Create) new record](docs/post-example.png)

### Get by Id

![Example Get by ID](docs/get-id-example.png)

### Put (Update) Record

![Example Put (Update)](docs/put-example.png)

### Delete Record

![Example Delete](docs/delete-example.png)

# TypeScript Courses

If you got this far, you probably like TypeScript just like I do,
I have created two TypeScript courses specializing in the [Three.js](https://www.udemy.com/course/threejs-tutorials/?referralCode=4C7E1DE91C3E42F69D0F) and [Socket.IO](https://www.udemy.com/course/typescript-socketio/?referralCode=2F6E227AC7EB9D147327)
libraries that you may find useful.

## Threejs and TypeScript Course

[![TypeScript Threejs Introduction](docs/threejs-course-image.png)](https://youtu.be/BcF3yuVqfwo)

## Socket.io and TypeScript Course

[![TypeScript SocketIO Introduction](docs/tssock-course.png)](https://youtu.be/3uLSNctzkkw)

# Programming Books

To help support my projects, please check out my books.

## Three.js and TypeScript

<img style="float:left; min-width:150px;" src="./docs/threejs-typescript-250.jpg">

&nbsp;<a href="https://www.amazon.com/dp/B09GYTKRCH"><img src="/docs/flag_us.gif">&nbsp; https://www.amazon.com/dp/B09GYTKRCH</a><br/>
&nbsp;<a href="https://www.amazon.co.uk/dp/B09GYTKRCH"><img src="/docs/flag_uk.gif">&nbsp; https://www.amazon.co.uk/dp/B09GYTKRCH</a><br/>
&nbsp;<a href="https://www.amazon.in/dp/B09GYTKRCH"><img src="/docs/flag_in.gif">&nbsp; https://www.amazon.in/dp/B09GYTKRCH</a><br/>
&nbsp;<a href="https://www.amazon.de/dp/B09GYTKRCH"><img src="/docs/flag_de.gif">&nbsp; https://www.amazon.de/dp/B09GYTKRCH</a><br/>
&nbsp;<a href="https://www.amazon.fr/dp/B09GYTKRCH"><img src="/docs/flag_fr.gif">&nbsp; https://www.amazon.fr/dp/B09GYTKRCH</a><br/>
&nbsp;<a href="https://www.amazon.es/dp/B09GYTKRCH"><img src="/docs/flag_es.gif">&nbsp; https://www.amazon.es/dp/B09GYTKRCH</a><br/>
&nbsp;<a href="https://www.amazon.it/dp/B09GYTKRCH"><img src="/docs/flag_it.gif">&nbsp; https://www.amazon.it/dp/B09GYTKRCH</a><br/>
&nbsp;<a href="https://www.amazon.nl/dp/B09GYTKRCH"><img src="/docs/flag_nl.gif">&nbsp; https://www.amazon.nl/dp/B09GYTKRCH</a><br/>
&nbsp;<a href="https://www.amazon.co.jp/dp/B09GYTKRCH"><img src="/docs/flag_jp.gif">&nbsp; https://www.amazon.co.jp/dp/B09GYTKRCH</a><br/>
&nbsp;<a href="https://www.amazon.ca/dp/B09GYTKRCH"><img src="/docs/flag_ca.gif">&nbsp; https://www.amazon.ca/dp/B09GYTKRCH</a><br/>
&nbsp;<a href="https://www.amazon.com.br/dp/B09GYTKRCH"><img src="/docs/flag_br.gif">&nbsp; https://www.amazon.com.br/dp/B09GYTKRCH</a><br/>
&nbsp;<a href="https://www.amazon.com.mx/dp/B09GYTKRCH"><img src="/docs/flag_mx.gif">&nbsp; https://www.amazon.com.mx/dp/B09GYTKRCH</a><br/>
&nbsp;<a href="https://www.amazon.com.au/dp/B09GYTKRCH"><img src="/docs/flag_au.gif">&nbsp; https://www.amazon.com.au/dp/B09GYTKRCH</a>

(ASIN : B09GZM9KGJ / B09GYTKRCH)

**Design Patterns in TypeScript**.

<img style="float:left; min-width:150px;" src="/docs/dp_typescript_250.jpg">

&nbsp;<a href="https://www.amazon.com/dp/B0948BCH24"><img src="/docs/flag_us.gif">&nbsp; https://www.amazon.com/dp/B0948BCH24</a><br/>
&nbsp;<a href="https://www.amazon.co.uk/dp/B0948BCH24"><img src="/docs/flag_uk.gif">&nbsp; https://www.amazon.co.uk/dp/B0948BCH24</a><br/>
&nbsp;<a href="https://www.amazon.in/dp/B094716FD6"><img src="/docs/flag_in.gif">&nbsp; https://www.amazon.in/dp/B094716FD6</a><br/>
&nbsp;<a href="https://www.amazon.de/dp/B0948BCH24"><img src="/docs/flag_de.gif">&nbsp; https://www.amazon.de/dp/B0948BCH24</a><br/>
&nbsp;<a href="https://www.amazon.fr/dp/B0948BCH24"><img src="/docs/flag_fr.gif">&nbsp; https://www.amazon.fr/dp/B0948BCH24</a><br/>
&nbsp;<a href="https://www.amazon.es/dp/B0948BCH24"><img src="/docs/flag_es.gif">&nbsp; https://www.amazon.es/dp/B0948BCH24</a><br/>
&nbsp;<a href="https://www.amazon.it/dp/B0948BCH24"><img src="/docs/flag_it.gif">&nbsp; https://www.amazon.it/dp/B0948BCH24</a><br/>
&nbsp;<a href="https://www.amazon.co.jp/dp/B0948BCH24"><img src="/docs/flag_jp.gif">&nbsp; https://www.amazon.co.jp/dp/B0948BCH24</a><br/>
&nbsp;<a href="https://www.amazon.ca/dp/B0948BCH24"><img src="/docs/flag_ca.gif">&nbsp; https://www.amazon.ca/dp/B0948BCH24</a><br/>
&nbsp;<a href="https://www.amazon.com.au/dp/B094716FD6"><img src="/docs/flag_au.gif">&nbsp; https://www.amazon.com.au/dp/B094716FD6</a>

(ASIN : B0948BCH24 / B094716FD6)

---

Thanks

Sean


================================================
FILE: src/app.ts
================================================
import express from 'express'
import Router from './router'
import swaggerUi from 'swagger-ui-express'
import * as swaggerDocument from './swagger.json'
import * as bodyParser from 'body-parser'

class App {
  private httpServer: any

  constructor() {
    this.httpServer = express()

    this.httpServer.use(bodyParser.urlencoded({ extended: true }));
    this.httpServer.use(bodyParser.json());
    
    new Router(this.httpServer);

    this.httpServer.use('/swagger', swaggerUi.serve, swaggerUi.setup(swaggerDocument));     
  }

  public Start = (port: number) => {
    return new Promise((resolve, reject) => {

      this.httpServer.listen(
        port,
        () => {
          resolve(port)
        })
        .on('error', (err: object) => reject(err));
    })
  }
}

export default App;


================================================
FILE: src/models/Bird.ts
================================================
type Bird = {
    genus: String;
    name: String;
    isHungry: Boolean;
    lastFedDate: Date;
}
export default Bird



================================================
FILE: src/models/Cat.ts
================================================
type Cat = {
    genus: String;
    name: String;
    isHungry: Boolean;
    lastFedDate: Date;
}
export default Cat



================================================
FILE: src/models/Dog.ts
================================================
type Dog = {
    genus: String;
    name: String;
    isHungry: Boolean;
    lastFedDate: Date;
}
export default Dog



================================================
FILE: src/router.ts
================================================
import * as express from 'express'
import Cat from './models/Cat'
import { v4 as uuid } from 'uuid';
import cors from 'cors'

class Router {

    constructor(server: express.Express) {
        const router = express.Router()

        const cats = new Map<string, Cat>();
        cats[uuid()] = { genus: "feline", name: "Cosmo", isHungry: true, lastFedDate: new Date() }
        cats[uuid()] = { genus: "feline", name: "Emmy", isHungry: true, lastFedDate: new Date() }

        router.get('/', (req: express.Request, res: express.Response) => {
            res.json({
                message: `Nothing to see here, [url]/cats instead.`
            })
        })

        //get all cats
        router.get('/cats', cors(), (req: express.Request, res: express.Response) => {
            res.json({
                cats
            })
        })

        //create new cat
        router.post('/cats', cors(), (req: express.Request, res: express.Response) => {
            try {
                let cat: Cat = {} as Cat;
                Object.assign(cat, req.body)
                const newUUID = uuid();
                cats[newUUID] = cat;
                res.json({
                    uuid: newUUID
                })
            } catch (e) {
                res.status(400).send(JSON.stringify({ "error": "problem with posted data" }));
            }
        })

        //get cat by id
        router.get('/cats/:id', cors(), (req: express.Request, res: express.Response) => {
            if (!!cats[req.params.id]) {
                res.json({
                    cat: cats[req.params.id]
                })
            } else {
                res.status(404).send(JSON.stringify({ "error": "no such cat" }));
            }
        })

        //update cat
        router.put('/cats/:id', cors(), (req: express.Request, res: express.Response) => {
            try {
                if (!!cats[req.params.id]) {
                    let cat: Cat = {} as Cat;
                    Object.assign(cat, req.body)
                    cats[req.params.id] = cat;
                    res.json({
                        cat: cats[req.params.id]
                    })
                } else {
                    res.status(404).send(JSON.stringify({ "error": "no such cat" }));
                }
            } catch (e) {
                res.status(400).send(JSON.stringify({ "error": "problem with posted data" }));
            }
        })

        //delete cat
        router.delete('/cats/:id', cors(), (req: express.Request, res: express.Response) => {
            if (!!cats[req.params.id]) {
                delete cats[req.params.id]
                res.json({
                    uuid: req.params.id
                })
            } else {
                res.status(404).send(JSON.stringify({ "error": "no such cat" }));
            }
        });

        router.options('*', cors());

        server.use('/', router)
    }
}

export default Router;

================================================
FILE: src/server.ts
================================================
import app from './app'

const port = parseInt(process.env.PORT || '3000')

const server = new app().Start(port)
  .then(port => console.log(`Server running on port ${port}`))
  .catch(error => {
    console.log(error)
    process.exit(1);
  });

export default server;

================================================
FILE: src/swagger.json
================================================
{
    "openapi": "3.0.0",
    "info": {
        "version": "1.0.0",
        "title": "Seans-TypeScript-NodeJS-CRUD-REST-API-Boilerplate",
        "description": "A minimal and easy to follow example of what you need to create a CRUD style API in NodeJs using TypeScript",
        "license": {
            "name": "MIT",
            "url": "https://opensource.org/licenses/MIT"
        }
    },
    "servers": [
        {
            "url": "/",
            "description": "Local Dev, or from Heroku"
        },
        {
            "url": "/api/",
            "description": "With docker-compose and nginx proxy"
        }
    ],
    "tags": [
        {
            "name": "Cats",
            "description": "API for cats in the system"
        }
    ],
    "consumes": [
        "application/json"
    ],
    "produces": [
        "application/json"
    ],
    "paths": {
        "/cats": {
            "get": {
                "tags": [
                    "Cats"
                ],
                "summary": "Get all cats in system",
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/Cats"
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Cats"
                ],
                "summary": "Create a new cat in system",
                "requestBody": {
                    "description": "Cat Object",
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/definitions/Cat"
                            }
                        }
                    }
                },
                "produces": [
                    "application/json"
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/id"
                        }
                    },
                    "400": {
                        "description": "Failed. Bad post data."
                    }
                }
            }
        },
        "/cats/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "description": "ID of the cat that we want to match",
                    "type": "string"
                }
            ],
            "get": {
                "tags": [
                    "Cats"
                ],
                "summary": "Get cat with given ID",
                "parameters": [
                    {
                        "in": "path",
                        "name": "id",
                        "required": true,
                        "description": "Cat with id",
                        "schema": {
                            "$ref": "#/definitions/id"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/Cat"
                        }
                    },
                    "404": {
                        "description": "Failed. Cat not found."
                    }
                }
            },
            "put": {
                "summary": "Update cat with given ID",
                "tags": [
                    "Cats"
                ],
                "requestBody": {
                    "description": "Cat Object",
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/definitions/Cat"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "in": "path",
                        "name": "id",
                        "required": true,
                        "description": "Cat with new values of properties",
                        "schema": {
                            "$ref": "#/definitions/id"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/Cat"
                        }
                    },
                    "400": {
                        "description": "Failed. Bad post data."
                    },
                    "404": {
                        "description": "Failed. Cat not found."
                    }
                }
            },
            "delete": {
                "summary": "Delete cat with given ID",
                "tags": [
                    "Cats"
                ],
                "parameters": [
                    {
                        "in": "path",
                        "name": "id",
                        "required": true,
                        "description": "Delete Cat with id",
                        "schema": {
                            "$ref": "#/definitions/id"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/id"
                        }
                    },
                    "404": {
                        "description": "Failed. Cat not found."
                    }
                }
            }
        }
    },
    "definitions": {
        "id": {
            "properties": {
                "uuid": {
                    "type": "string"
                }
            }
        },
        "Cat": {
            "type": "object",
            "properties": {
                "genus": {
                    "type": "string"
                },
                "name": {
                    "type": "string"
                },
                "isHungry": {
                    "type": "boolean"
                },
                "lastFedDate": {
                    "type": "string"
                }
            }
        },
        "Cats": {
            "type": "object",
            "properties": {
                "cats": {
                    "type": "object",
                    "additionalProperties": {
                        "$ref": "#/definitions/Cat"
                    }
                }
            }
        }
    }
}

================================================
FILE: tsconfig.json
================================================
{
  "compilerOptions": {
    "target": "es2017",
    "module": "commonjs",
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "outDir": "dist",
    //"sourceMap": true
  },
  "files": [
    "./node_modules/@types/node/index.d.ts"
  ],
  "include": [
    "src/**/*.ts"
  ],
  "exclude": [
    "node_modules"
  ]
}
Download .txt
gitextract_m3qilazq/

├── .github/
│   └── FUNDING.yml
├── .gitignore
├── .gitlab-ci.yml
├── Dockerfile
├── LICENSE
├── app.json
├── docker-compose.yml
├── nginx/
│   ├── Dockerfile
│   ├── nginx.conf
│   └── static/
│       └── index.html
├── package.json
├── readme.md
├── src/
│   ├── app.ts
│   ├── models/
│   │   ├── Bird.ts
│   │   ├── Cat.ts
│   │   └── Dog.ts
│   ├── router.ts
│   ├── server.ts
│   └── swagger.json
└── tsconfig.json
Download .txt
SYMBOL INDEX (7 symbols across 5 files)

FILE: src/app.ts
  class App (line 7) | class App {
    method constructor (line 10) | constructor() {

FILE: src/models/Bird.ts
  type Bird (line 1) | type Bird = {

FILE: src/models/Cat.ts
  type Cat (line 1) | type Cat = {

FILE: src/models/Dog.ts
  type Dog (line 1) | type Dog = {

FILE: src/router.ts
  class Router (line 6) | class Router {
    method constructor (line 8) | constructor(server: express.Express) {
Condensed preview — 20 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (27K chars).
[
  {
    "path": ".github/FUNDING.yml",
    "chars": 669,
    "preview": "# These are supported funding model platforms\n\ngithub: [Sean-Bradley]# Replace with up to 4 GitHub Sponsors-enabled user"
  },
  {
    "path": ".gitignore",
    "chars": 32,
    "preview": "node_modules\nnpm-debug.log\ndist/"
  },
  {
    "path": ".gitlab-ci.yml",
    "chars": 1525,
    "preview": "image: docker:latest\nservices:\n  - docker:dind\n\nstages:\n  - test\n  - deploy\n\nstep-develop:\n  stage: test\n  before_script"
  },
  {
    "path": "Dockerfile",
    "chars": 217,
    "preview": "FROM node:alpine\n\nLABEL github=https://github.com/Sean-Bradley\n\nCOPY src /nodejs/src\nCOPY package.json /nodejs/package.j"
  },
  {
    "path": "LICENSE",
    "chars": 1075,
    "preview": "MIT License\n\nCopyright (c) 2019 seanwasere youtube\n\nPermission is hereby granted, free of charge, to any person obtainin"
  },
  {
    "path": "app.json",
    "chars": 421,
    "preview": "{\n    \"name\": \"seans-typescript-nodejs-crud-rest-api-boilerplate\",\n    \"description\": \"A barebones TypeScript Node.js CR"
  },
  {
    "path": "docker-compose.yml",
    "chars": 348,
    "preview": "version: '2'\nservices:\n  nginx:\n    build: \n      context: nginx\n      dockerfile: Dockerfile\n    ports:\n      - \"80:80\""
  },
  {
    "path": "nginx/Dockerfile",
    "chars": 200,
    "preview": "FROM nginx\nLABEL github=https://github.com/Sean-Bradley\nCOPY /nginx.conf\t/etc/nginx/nginx.conf\n#COPY /server.crt\t/etc/ng"
  },
  {
    "path": "nginx/nginx.conf",
    "chars": 1134,
    "preview": "user www-data;\nworker_processes 1;\npid /run/nginx.pid;\nevents {\n    worker_connections 768;\n}\nhttp {\n    sendfile off;\n "
  },
  {
    "path": "nginx/static/index.html",
    "chars": 74,
    "preview": "put the static html generated from you favourite front end framework here."
  },
  {
    "path": "package.json",
    "chars": 768,
    "preview": "{\n  \"name\": \"seans-typescript-nodejs-crud-rest-api-boilerplate\",\n  \"version\": \"1.0.1\",\n  \"description\": \"\",\n  \"main\": \"s"
  },
  {
    "path": "readme.md",
    "chars": 6557,
    "preview": "## Seans-TypeScript-NodeJS-CRUD-REST-API-Boilerplate\n\n> To help support this TypeScript boilerplate, please take a momen"
  },
  {
    "path": "src/app.ts",
    "chars": 800,
    "preview": "import express from 'express'\nimport Router from './router'\nimport swaggerUi from 'swagger-ui-express'\nimport * as swagg"
  },
  {
    "path": "src/models/Bird.ts",
    "chars": 120,
    "preview": "type Bird = {\n    genus: String;\n    name: String;\n    isHungry: Boolean;\n    lastFedDate: Date;\n}\nexport default Bird\n\n"
  },
  {
    "path": "src/models/Cat.ts",
    "chars": 118,
    "preview": "type Cat = {\n    genus: String;\n    name: String;\n    isHungry: Boolean;\n    lastFedDate: Date;\n}\nexport default Cat\n\n"
  },
  {
    "path": "src/models/Dog.ts",
    "chars": 118,
    "preview": "type Dog = {\n    genus: String;\n    name: String;\n    isHungry: Boolean;\n    lastFedDate: Date;\n}\nexport default Dog\n\n"
  },
  {
    "path": "src/router.ts",
    "chars": 2953,
    "preview": "import * as express from 'express'\nimport Cat from './models/Cat'\nimport { v4 as uuid } from 'uuid';\nimport cors from 'c"
  },
  {
    "path": "src/server.ts",
    "chars": 269,
    "preview": "import app from './app'\n\nconst port = parseInt(process.env.PORT || '3000')\n\nconst server = new app().Start(port)\n  .then"
  },
  {
    "path": "src/swagger.json",
    "chars": 6931,
    "preview": "{\n    \"openapi\": \"3.0.0\",\n    \"info\": {\n        \"version\": \"1.0.0\",\n        \"title\": \"Seans-TypeScript-NodeJS-CRUD-REST-"
  },
  {
    "path": "tsconfig.json",
    "chars": 325,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"es2017\",\n    \"module\": \"commonjs\",\n    \"resolveJsonModule\": true,\n    \"esModuleI"
  }
]

About this extraction

This page contains the full source code of the Sean-Bradley/Seans-TypeScript-NodeJS-CRUD-REST-API-Boilerplate GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 20 files (24.1 KB), approximately 6.6k tokens, and a symbol index with 7 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!