From b8d452bda0a84b76eb71429255617c3bd061481d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 21 Apr 2022 01:46:15 +0200 Subject: [PATCH 1/6] feat: update readme --- README.md | 42 ------------------------------------------ templates/README.md | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 42 deletions(-) create mode 100644 templates/README.md diff --git a/README.md b/README.md index 81e06fa2ae..c642e60422 100644 --- a/README.md +++ b/README.md @@ -34,46 +34,4 @@ We aim to provide a fully tested API for our peace of mind, this is accomplished Since this will only support an API, we redirect the requests to root to the /api folder. We also added a redirect for future-proofing API versioning when we might need it, without having to resort to dirty hacks like a v1/v2 folders with lots of duplicated code, instead we redirect /api/v*/:rest to /api/:rest?version=* -The priority is the booking-related API routes so people can build their own booking flow, then event type management routes, then availability management routes etc -How to add a new model or endpoint - -Basically there's three places of the codebase you need to think about for each feature. - -/pages/api/ - -- This is the most important one, and where your endpoint will live. You will leverage nextjs dynamic routes and expose one file for each endpoint you want to support ideally. - -## How the codebase is organized. - -## The example resource -model- and it's endpoints - -### `pages/api/endpoint/` - -GET pages/api/endpoint/index.ts - Read All of your resource -POST pages/api/endpoint/new.ts - Create new resource - -### `pages/api/endpoint/[id]/` - -GET pages/api/endpoint/[id]/index.ts - Read All of your resource -PATCH pages/api/endpoint/[id]/edit.ts - Create new resource -DELETE pages/api/endpoint/[id]/delete.ts - Create new resource - -## `/tests/` - -This is where all your endpoint's tests live, we mock prisma calls. We aim for at least 50% global coverage. Test each of your endpoints. - -### `/tests/endpoint/` - -/tests/endpoint/resource.index.test.ts - Test for your pages/api/endpoint/index.ts file -tests/endpoint/resource.new.test.ts - Create new resource - -### `/tests/endpoint/[id]/` - -`/tests/endpoint/[id]/resource.index.test.ts` - Read All of your resource -`/tests/endpoint/[id]/resource.edit.test.ts` - Create new resource -`/tests/endpoint/[id]/resource.delete.test.ts` - Create new resource - -## `/lib/validations/yourEndpoint.ts` - -- This is where our model validations, live, we try to make a 1:1 for db models, and also extract out any re-usable code into the /lib/validations/shared/ sub-folder. diff --git a/templates/README.md b/templates/README.md new file mode 100644 index 0000000000..c44fe4ef59 --- /dev/null +++ b/templates/README.md @@ -0,0 +1,41 @@ +# How to add a new model or endpoint + +Basically there's three places of the codebase you need to think about for each feature. + +/pages/api/ + +- This is the most important one, and where your endpoint will live. You will leverage nextjs dynamic routes and expose one file for each endpoint you want to support ideally. + +## How the codebase is organized. + +## The example resource -model- and it's endpoints + +### `pages/api/endpoint/` + +GET pages/api/endpoint/index.ts - Read All of your resource +POST pages/api/endpoint/new.ts - Create new resource + +### `pages/api/endpoint/[id]/` + +GET pages/api/endpoint/[id]/index.ts - Read All of your resource +PATCH pages/api/endpoint/[id]/edit.ts - Create new resource +DELETE pages/api/endpoint/[id]/delete.ts - Create new resource + +## `/tests/` + +This is where all your endpoint's tests live, we mock prisma calls. We aim for at least 50% global coverage. Test each of your endpoints. + +### `/tests/endpoint/` + +/tests/endpoint/resource.index.test.ts - Test for your pages/api/endpoint/index.ts file +tests/endpoint/resource.new.test.ts - Create new resource + +### `/tests/endpoint/[id]/` + +`/tests/endpoint/[id]/resource.index.test.ts` - Read All of your resource +`/tests/endpoint/[id]/resource.edit.test.ts` - Create new resource +`/tests/endpoint/[id]/resource.delete.test.ts` - Create new resource + +## `/lib/validations/yourEndpoint.ts` + +- This is where our model validations, live, we try to make a 1:1 for db models, and also extract out any re-usable code into the /lib/validations/shared/ sub-folder. From c08f5038075a700872e05b2e1a025224bd86504b Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 21 Apr 2022 01:55:44 +0200 Subject: [PATCH 2/6] update readme round 2 --- README.md | 157 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 145 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index c642e60422..40183411f5 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,109 @@ # Cal.com Public API (Enterprise Only) -## This will be the new public enterprise-only API +This is the public REST api for cal.com. It exposes CRUD Endpoints of all our most important resources. It makes it easy for anyone to integrate with cal at the programming level. -This is the public REST api for cal.com +## Stack -## NextJS + TypeScript +- NextJS +- TypeScript +- Prisma +- No tRPC ** -It's a barebones **NextJS** + **TypeScript** project leveraging the nextJS API with a pages/api folder. +** (for now) We hook directly into prisma client, but probably should look into adding a new @calcom/trpc package that adds pagination and such stuff and can be shared between webapp and API. -- `api.cal.com/v1` -- `api.cal.com/api/v1` +## Development + +### Setup + +1. Clone the main repo (NOT THIS ONE) + + ```sh + git clone --recurse-submodules -j8 https://github.com/calcom/cal.com.git + ``` + +1. Go to the project folder + + ```sh + cd cal.com + ``` + +1. Copy `apps/api/.env.example` to `apps/api/.env` + + ```sh + cp apps/api/.env.example apps/api/.env + cp packages/prisma/.env.example packages/prisma/.env + ``` + +1. Install packages with yarn + + ```sh + yarn + ``` + +1. Start developing + + ```sh + yarn workspace @calcom/api dev + ``` + +1. Open [http://localhost:3002](http://localhost:3002) with your browser to see the result. + +## API Authentication (API Keys) + +The API requires a valid apiKey query param to be passed: +You can generate them at + +For example: + +```sh +GET https://api.cal.com/v1/users?apiKey={INSERT_YOUR_CAL.COM_API_KEY_HERE} +``` + +API Keys optionally may have expiry dates, if they are expired they won't work. If you create an apiKey without a userId relation, it won't work either for now as it relies on it to establish the current authenticated user. + +In the future we might add support for header Beaer Auth if we need to or our customers require it. + +## Next.config.js + +### Redirects + +Since this is an API only project, we don't want to have to type /api/ in all the routes, and so redirect all traffic to api, so a call to `api.cal.com/v1` will resolve to `api.cal.com/api/v1` + +Likewise, v1 is added as param query called version to final /api call so we don't duplicate endpoints in the future for versioning if needed. + +### Transpiling locally shared monorepo modules + +We're calling several packages from monorepo, this need to be transpiled before building since are not available as regular npm packages. That's what withTM does. + +```sh + "@calcom/app-store", + "@calcom/prisma", + "@calcom/lib", + "@calcom/ee", +``` ## API Endpoint Validation -### Zod +We validate that only the supported methods are accepted at each endpoint, so in -The API uses `zod` library like our main web repo. It validates that either GET query parameters or POST body content's are valid and up to our spec. It gives appropiate errors when parsing result's with schemas. +- **/endpoint**: you can only [GET] (all) and [POST] (create new) +- **/endpoint/id**: you can read create and edit [GET, PATCH, DELETE] + +### Zod Validations + +The API uses `zod` library like our main web repo. It validates that either GET query parameters or POST body content's are valid and up to our spec. It gives errors when parsing result's with schemas and failing validation. + +We use it in several ways, but mainly, we first import the auto-generated schema from @calcom/prisma for each model, which lives in `lib/validations/` + +We have some shared validations which several resources require, like baseApiParams which parses apiKey in all requests, or querIdAsString or TransformParseInt which deal with the id's coming from req.query. + +- **[*]BaseBodyParams** that omits any values from the model that are too sensitive or we don't want to pick when creating a new resource like id, userId, etc.. (those are gotten from context or elswhere) + +- **[*]Public** that also omits any values that we don't want to expose when returning the model as a response, which we parse against before returning all resources. + +- **[*]BodyParams** which merges both `[*]BaseBodyParams.merge([*]RequiredParams);` + +- **withValid[*]** which is currently not being much used because is only useful in only post endpoints (we do post/get all in same file). This would validate the req.body of a POST call to API against our BaseBodyParams validation ### Next Validations @@ -27,11 +115,56 @@ We also use this useful helper library that let's us wrap our endpoints in a val We aim to provide a fully tested API for our peace of mind, this is accomplished by using jest + node-mocks-http -## Next.config.js +## Endpoints matrix -### Redirects +| resource | get [id] | get all | create | edit | delete | +|--------------------------|----------|----------|---------|-------|--------| +| attendees | ✅ | ✅ | ✅ | ✅ | ✅ | +| availabilities | ✅ | ✅ | ✅ | ✅ | ✅ | +| booking-references | ✅ | ✅ | ✅ | ✅ | ✅ | +| daily-event-references | ✅ | ✅ | ✅ | ✅ | ✅ | +| destination-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | +| event-type-custom-inputs | ✅ | ✅ | ✅ | ✅ | ✅ | +| event-types | ✅ | ✅ | ✅ | ✅ | ✅ | +| memberships | ✅ | ✅ | ✅ | ✅ | ✅ | +| payments | ✅ | ✅ | ❌ | ❌ | ❌ | +| schedules | ✅ | ✅ | ✅ | ✅ | ✅ | +| selected-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | +| teams | ✅ | ✅ | ✅ | ✅ | ✅ | +| users | ✅ | 👤[1] | ✅ | ✅ | ✅ | -Since this will only support an API, we redirect the requests to root to the /api folder. -We also added a redirect for future-proofing API versioning when we might need it, without having to resort to dirty hacks like a v1/v2 folders with lots of duplicated code, instead we redirect /api/v*/:rest to /api/:rest?version=* +## Models from database that are not exposed +mostly because they're deemed too sensitive can be revisited if needed. most are expected to be used via cal's webapp. +- [ ] Api Keys +- [ ] Credentials +- [ ] Webhooks +- [ ] ResetPasswordRequest +- [ ] VerificationToken +- [ ] ReminderMail + +## Documentation (OpenAPI) + +You will see that each endpoint has a comment at the top with the annotation `@swagger` with the documentation of the endpoint, **please update it if you change the code!** This is what auto-generates the OpenAPI spec by collecting the YAML in each endpoint and parsing it in /docs alongside the json-schema (auto-generated from prisma package, not added to code but manually for now, need to fix later) + +### @calcom/apps/swagger + +The documentation of the API lives inside the code, and it's auto-generated, the only endpoints that return without a valid apiKey are the homepage, with a JSON message redirecting you to the docs. and the /docs endpoint, which returns the OpenAPI 3.0 JSON Spec. Which SwaggerUi then consumes and generates the docs on. + +## Deployment + +`scripts/vercel-deploy.sh` +The API is deployed to vercel.com, it uses a similar deployment script to website or webapp, and requires transpilation of several shared packages that are part of our turborepo ["app-store", "prisma", "lib", "ee"] +in order to build and deploy properly. + +## Envirorment variables + +### Required + +DATABASE_URL=DATABASE_URL="postgresql://postgres:@localhost:5450/calendso" + +## Optional + +API_KEY_PREFIX=cal_# This can be changed per envirorment so cal_test_ for staging for example. +> If you're self-hosting under our commercial license, you can use any prefix you want for api keys. either leave the default cal_ (not providing any envirorment variable) or modify it From 8437a284a83cfe9f2e0b8f55354341dd41caccb3 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 21 Apr 2022 01:57:32 +0200 Subject: [PATCH 3/6] update readme round 2b --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index 40183411f5..19ee4a65f5 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,6 @@ This is the public REST api for cal.com. It exposes CRUD Endpoints of all our mo - NextJS - TypeScript - Prisma -- No tRPC ** - -** (for now) We hook directly into prisma client, but probably should look into adding a new @calcom/trpc package that adds pagination and such stuff and can be shared between webapp and API. ## Development @@ -75,7 +72,7 @@ Likewise, v1 is added as param query called version to final /api call so we don We're calling several packages from monorepo, this need to be transpiled before building since are not available as regular npm packages. That's what withTM does. -```sh +```js "@calcom/app-store", "@calcom/prisma", "@calcom/lib", From cac972eb15adf345e39e833039a37f23741cb0c0 Mon Sep 17 00:00:00 2001 From: alannnc Date: Wed, 20 Apr 2022 18:14:23 -0600 Subject: [PATCH 4/6] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 19ee4a65f5..0a7997d6e8 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ GET https://api.cal.com/v1/users?apiKey={INSERT_YOUR_CAL.COM_API_KEY_HERE} API Keys optionally may have expiry dates, if they are expired they won't work. If you create an apiKey without a userId relation, it won't work either for now as it relies on it to establish the current authenticated user. -In the future we might add support for header Beaer Auth if we need to or our customers require it. +In the future we might add support for header Bearer Auth if we need to or our customers require it. ## Next.config.js From cb4f0a9cd0d886c3c3e830fdb1a25464aa9b4fdd Mon Sep 17 00:00:00 2001 From: alannnc Date: Wed, 20 Apr 2022 18:15:20 -0600 Subject: [PATCH 5/6] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a7997d6e8..f7e74712c8 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ GET https://api.cal.com/v1/users?apiKey={INSERT_YOUR_CAL.COM_API_KEY_HERE} API Keys optionally may have expiry dates, if they are expired they won't work. If you create an apiKey without a userId relation, it won't work either for now as it relies on it to establish the current authenticated user. -In the future we might add support for header Bearer Auth if we need to or our customers require it. +In the future we might add support for header Bearer Auth if we need to or if our customers require it. ## Next.config.js From a2cdb04985bef4c6130c58a57af2a536e0576b93 Mon Sep 17 00:00:00 2001 From: alannnc Date: Wed, 20 Apr 2022 18:19:48 -0600 Subject: [PATCH 6/6] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f7e74712c8..15cc019306 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ We have some shared validations which several resources require, like baseApiPar [Next-Validations Docs](https://next-validations.productsway.com/) [Next-Validations Repo](https://github.com/jellydn/next-validations) -We also use this useful helper library that let's us wrap our endpoints in a validate HOC that checks the req against our validation schema built out with zod for either query and / or body's requests. +We also use this useful helper library that let us wrap our endpoints in a validate HOC that checks the req against our validation schema built out with zod for either query and / or body's requests. ## Testing with Jest + node-mocks-http @@ -132,7 +132,7 @@ We aim to provide a fully tested API for our peace of mind, this is accomplished ## Models from database that are not exposed -mostly because they're deemed too sensitive can be revisited if needed. most are expected to be used via cal's webapp. +mostly because they're deemed too sensitive can be revisited if needed. Also they are expected to be used via cal's webapp. - [ ] Api Keys - [ ] Credentials