mirror of
https://github.com/wasp-lang/wasp.git
synced 2024-12-26 02:23:21 +03:00
Fix broken documentation links & remove old docs.
* Removed old docs leftovers. * Fixed broken links in the docs. * fix
This commit is contained in:
parent
8b4e7303c1
commit
7f91081bd8
@ -1,7 +1,7 @@
|
|||||||
# Waspleau
|
# Waspleau
|
||||||
|
|
||||||
Welcome to the Waspleau example! This is a small Wasp project that tracks status of wasp-lang/wasp repo via a nice looking dashboard.
|
Welcome to the Waspleau example! This is a small Wasp project that tracks status of wasp-lang/wasp repo via a nice looking dashboard.
|
||||||
It pulls in data via [Jobs](https://wasp-lang.dev/docs/language/features#jobs) and stores them in the database.
|
It pulls in data via [Jobs](https://wasp-lang.dev/docs/advanced/jobs) and stores them in the database.
|
||||||
|
|
||||||
This example project can serve as a good starting point for building your own dashboard with Wasp, that regularly pulls in external data by using Jobs Wasp feature.
|
This example project can serve as a good starting point for building your own dashboard with Wasp, that regularly pulls in external data by using Jobs Wasp feature.
|
||||||
|
|
||||||
|
@ -10,9 +10,9 @@ The backend is hosted on Fly.io at https://waspello.fly.dev.
|
|||||||
# Development
|
# Development
|
||||||
|
|
||||||
### Database
|
### Database
|
||||||
Wasp needs the Postgres database running. Check out the docs for details on [how to setup PostgreSQL](https://wasp-lang.dev/docs/language/features#postgresql)
|
Wasp needs the Postgres database running.
|
||||||
|
|
||||||
You can use `wasp start db` to start a PostgreSQL locally using Docker.
|
Easiest way to do this is to use `wasp start db` to start a PostgreSQL locally using Docker.
|
||||||
|
|
||||||
### Env variables
|
### Env variables
|
||||||
Copy `env.server` to `.env.server` and fill in the values.
|
Copy `env.server` to `.env.server` and fill in the values.
|
||||||
|
@ -42,7 +42,7 @@ export type UpdateQuery<ActionInput, CachedData> = (item: ActionInput, oldData:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A public query specifier used for addressing Wasp queries. See our docs for details:
|
* A public query specifier used for addressing Wasp queries. See our docs for details:
|
||||||
* https://wasp-lang.dev/docs/language/features#the-useaction-hook.
|
* https://wasp-lang.dev/docs/data-model/operations/actions#the-useaction-hook-and-optimistic-updates
|
||||||
*/
|
*/
|
||||||
export type QuerySpecifier<Input, Output> = [Query<Input, Output>, ...any[]]
|
export type QuerySpecifier<Input, Output> = [Query<Input, Output>, ...any[]]
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ type InternalAction<Input, Output> = Action<Input, Output> & {
|
|||||||
*
|
*
|
||||||
* @param publicOptimisticUpdateDefinition An optimistic update definition
|
* @param publicOptimisticUpdateDefinition An optimistic update definition
|
||||||
* object that's a part of the public API:
|
* object that's a part of the public API:
|
||||||
* https://wasp-lang.dev/docs/language/features#the-useaction-hook.
|
* https://wasp-lang.dev/docs/data-model/operations/actions#the-useaction-hook-and-optimistic-updates
|
||||||
* @returns An internally-used optimistic update definition object.
|
* @returns An internally-used optimistic update definition object.
|
||||||
*/
|
*/
|
||||||
function translateToInternalDefinition<Item, CachedData>(
|
function translateToInternalDefinition<Item, CachedData>(
|
||||||
@ -260,7 +260,7 @@ function getOptimisticUpdateDefinitionForSpecificItem<ActionInput, CachedData>(
|
|||||||
* Translates a Wasp query specifier to a query cache key used by React Query.
|
* Translates a Wasp query specifier to a query cache key used by React Query.
|
||||||
*
|
*
|
||||||
* @param querySpecifier A query specifier that's a part of the public API:
|
* @param querySpecifier A query specifier that's a part of the public API:
|
||||||
* https://wasp-lang.dev/docs/language/features#the-useaction-hook.
|
* https://wasp-lang.dev/docs/data-model/operations/actions#the-useaction-hook-and-optimistic-updates
|
||||||
* @returns A cache key React Query internally uses for addressing queries.
|
* @returns A cache key React Query internally uses for addressing queries.
|
||||||
*/
|
*/
|
||||||
function getRqQueryKeyFromSpecifier(querySpecifier: QuerySpecifier<unknown, unknown>): QueryKey {
|
function getRqQueryKeyFromSpecifier(querySpecifier: QuerySpecifier<unknown, unknown>): QueryKey {
|
||||||
|
@ -60,7 +60,7 @@ This is one of the features we are most excited about! Now, when you define an e
|
|||||||
|
|
||||||
This feature beautifully showcases the power of the Wasp language approach and how much it can cut down on the boilerplate. And we're just getting started!
|
This feature beautifully showcases the power of the Wasp language approach and how much it can cut down on the boilerplate. And we're just getting started!
|
||||||
|
|
||||||
For more details, [check out our docs on reusing entity types on both a client and a server](/docs/typescript#entity-types).
|
For more details, [check out our entity docs](/docs/data-model/entities).
|
||||||
|
|
||||||
## 🗓 We set a date for the next launch - April 11th! 🚀
|
## 🗓 We set a date for the next launch - April 11th! 🚀
|
||||||
|
|
||||||
|
@ -710,7 +710,7 @@ You should see a login screen this time. Go ahead and first register a user, the
|
|||||||
|
|
||||||
Once logged in, you’ll see the same hardcoded poll data as in the previous example, because, again, we haven’t set up the [Socket.IO](http://Socket.IO) client on the frontend. But this time it should be much easier.
|
Once logged in, you’ll see the same hardcoded poll data as in the previous example, because, again, we haven’t set up the [Socket.IO](http://Socket.IO) client on the frontend. But this time it should be much easier.
|
||||||
|
|
||||||
Why? Well, besides less configuration, another nice benefit of working with [TypeScript with Wasp](/docs/typescript#websocket-full-stack-type-support), is that you just have to define payload types with matching event names on the server, and those types will get exposed automatically on the client!
|
Why? Well, besides less configuration, another nice benefit of working with [TypeScript with Wasp](/docs/advanced/web-sockets), is that you just have to define payload types with matching event names on the server, and those types will get exposed automatically on the client!
|
||||||
|
|
||||||
Let’s take a look at how that works now.
|
Let’s take a look at how that works now.
|
||||||
|
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
import Admonition from "@theme/Admonition";
|
|
||||||
import Link from "@docusaurus/Link";
|
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
export default function OldDocsNote() {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "sticky",
|
|
||||||
top: "calc(var(--ifm-navbar-height) + 1rem)",
|
|
||||||
zIndex: 1,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Admonition type="caution" title="Deprecated Page">
|
|
||||||
This page is part of a previous documentation version and is no longer
|
|
||||||
actively maintained. The content is likely out of date and may no longer
|
|
||||||
be relevant to current releases.
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
Go to the <Link to="/docs">current documentation</Link> for updated
|
|
||||||
content.
|
|
||||||
</Admonition>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -5,7 +5,7 @@ title: Custom HTTP API Endpoints
|
|||||||
import { ShowForTs, ShowForJs } from '@site/src/components/TsJsHelpers'
|
import { ShowForTs, ShowForJs } from '@site/src/components/TsJsHelpers'
|
||||||
import { Required } from '@site/src/components/Required'
|
import { Required } from '@site/src/components/Required'
|
||||||
|
|
||||||
In Wasp, the default client-server interaction mechanism is through [Operations](/docs/data-model/operations/overview). However, if you need a specific URL method/path, or a specific response, Operations may not be suitable for you. For these cases, you can use an `api`. Best of all, they should look and feel very familiar.
|
In Wasp, the default client-server interaction mechanism is through [Operations](../data-model/operations/overview). However, if you need a specific URL method/path, or a specific response, Operations may not be suitable for you. For these cases, you can use an `api`. Best of all, they should look and feel very familiar.
|
||||||
|
|
||||||
## How to Create an API
|
## How to Create an API
|
||||||
|
|
||||||
@ -231,11 +231,11 @@ export const apiMiddleware: MiddlewareConfigFn = (config) => {
|
|||||||
|
|
||||||
We are returning the default middleware which enables CORS for all APIs under the `/foo` path.
|
We are returning the default middleware which enables CORS for all APIs under the `/foo` path.
|
||||||
|
|
||||||
For more information about middleware configuration, please see: [Middleware Configuration](/docs/advanced/middleware-config)
|
For more information about middleware configuration, please see: [Middleware Configuration](../advanced/middleware-config)
|
||||||
|
|
||||||
## Using Entities in APIs
|
## Using Entities in APIs
|
||||||
|
|
||||||
In many cases, resources used in APIs will be [Entities](/docs/data-model/entities.md).
|
In many cases, resources used in APIs will be [Entities](../data-model/entities.md).
|
||||||
To use an Entity in your API, add it to the `api` declaration in Wasp:
|
To use an Entity in your API, add it to the `api` declaration in Wasp:
|
||||||
|
|
||||||
<Tabs groupId="js-ts">
|
<Tabs groupId="js-ts">
|
||||||
@ -340,4 +340,4 @@ The `api` declaration has the following fields:
|
|||||||
|
|
||||||
- `middlewareConfigFn: ServerImport`
|
- `middlewareConfigFn: ServerImport`
|
||||||
|
|
||||||
The import statement to an Express middleware config function for this API. See more in [middleware section](/docs/advanced/middleware-config) of the docs.
|
The import statement to an Express middleware config function for this API. See more in [middleware section](../advanced/middleware-config) of the docs.
|
@ -1,4 +1,4 @@
|
|||||||
:::tip Using an external auth method?
|
:::tip Using an external auth method?
|
||||||
|
|
||||||
If your app is using an external authentication method(s) supported by Wasp (such as [Google](/docs/auth/social-auth/google#4-adding-environment-variables) or [GitHub](/docs/auth/social-auth/github#4-adding-environment-variables)), make sure to set the necessary environment variables.
|
If your app is using an external authentication method(s) supported by Wasp (such as [Google](../../auth/social-auth/google#4-adding-environment-variables) or [GitHub](../../auth/social-auth/github#4-adding-environment-variables)), make sure to set the necessary environment variables.
|
||||||
:::
|
:::
|
||||||
|
@ -34,7 +34,7 @@ wasp build
|
|||||||
|
|
||||||
:::caution PostgreSQL in production
|
:::caution PostgreSQL in production
|
||||||
You won't be able to build the app if you are using SQLite as a database (which is the default database).
|
You won't be able to build the app if you are using SQLite as a database (which is the default database).
|
||||||
You'll have to [switch to PostgreSQL](/docs/data-model/backends#migrating-from-sqlite-to-postgresql) before deploying to production.
|
You'll have to [switch to PostgreSQL](../../data-model/backends#migrating-from-sqlite-to-postgresql) before deploying to production.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### 2. Deploying the API Server (backend)
|
### 2. Deploying the API Server (backend)
|
||||||
@ -92,7 +92,7 @@ We'll cover a few different deployment providers below:
|
|||||||
## Fly.io
|
## Fly.io
|
||||||
|
|
||||||
:::tip We automated this process for you
|
:::tip We automated this process for you
|
||||||
If you want to do all of the work below with one command, you can use the [Wasp CLI](/docs/advanced/deployment/cli#flyio).
|
If you want to do all of the work below with one command, you can use the [Wasp CLI](../../advanced/deployment/cli#flyio).
|
||||||
|
|
||||||
Wasp CLI deploys the server, deploys the client, and sets up a database.
|
Wasp CLI deploys the server, deploys the client, and sets up a database.
|
||||||
It also gives you a way to redeploy (update) your app with a single command.
|
It also gives you a way to redeploy (update) your app with a single command.
|
||||||
@ -547,7 +547,7 @@ heroku logs --tail --app <app-name>
|
|||||||
|
|
||||||
:::note Using `pg-boss` with Heroku
|
:::note Using `pg-boss` with Heroku
|
||||||
|
|
||||||
If you wish to deploy an app leveraging [Jobs](/docs/advanced/jobs) that use `pg-boss` as the executor to Heroku, you need to set an additional environment variable called `PG_BOSS_NEW_OPTIONS` to `{"connectionString":"<REGULAR_HEROKU_DATABASE_URL>","ssl":{"rejectUnauthorized":false}}`. This is because pg-boss uses the `pg` extension, which does not seem to connect to Heroku over SSL by default, which Heroku requires. Additionally, Heroku uses a self-signed cert, so we must handle that as well.
|
If you wish to deploy an app leveraging [Jobs](../../advanced/jobs) that use `pg-boss` as the executor to Heroku, you need to set an additional environment variable called `PG_BOSS_NEW_OPTIONS` to `{"connectionString":"<REGULAR_HEROKU_DATABASE_URL>","ssl":{"rejectUnauthorized":false}}`. This is because pg-boss uses the `pg` extension, which does not seem to connect to Heroku over SSL by default, which Heroku requires. Additionally, Heroku uses a self-signed cert, so we must handle that as well.
|
||||||
|
|
||||||
Read more: https://devcenter.heroku.com/articles/connecting-heroku-postgres#connecting-in-node-js
|
Read more: https://devcenter.heroku.com/articles/connecting-heroku-postgres#connecting-in-node-js
|
||||||
:::
|
:::
|
||||||
|
@ -11,7 +11,7 @@ Wasp apps are full-stack apps that consist of:
|
|||||||
|
|
||||||
You can deploy each part **anywhere** where you can usually deploy Node.js apps or static apps. For example, you can deploy your client on [Netlify](https://www.netlify.com/), the server on [Fly.io](https://fly.io/), and the database on [Neon](https://neon.tech/).
|
You can deploy each part **anywhere** where you can usually deploy Node.js apps or static apps. For example, you can deploy your client on [Netlify](https://www.netlify.com/), the server on [Fly.io](https://fly.io/), and the database on [Neon](https://neon.tech/).
|
||||||
|
|
||||||
To make deploying as smooth as possible, Wasp also offers a single-command deployment through the **Wasp CLI**. Read more about deploying through the CLI [here](/docs/advanced/deployment/cli).
|
To make deploying as smooth as possible, Wasp also offers a single-command deployment through the **Wasp CLI**. Read more about deploying through the CLI [here](../../advanced/deployment/cli).
|
||||||
|
|
||||||
<DeploymentOptionsGrid />
|
<DeploymentOptionsGrid />
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ Let's write an example Job that will print a message to the console and return a
|
|||||||
`MySpecialJob` is a generic type Wasp generates to help you correctly type the Job's worker function, ensuring type information about the function's arguments and return value. Read more about type-safe jobs in the [Javascript API section](#javascript-api).
|
`MySpecialJob` is a generic type Wasp generates to help you correctly type the Job's worker function, ensuring type information about the function's arguments and return value. Read more about type-safe jobs in the [Javascript API section](#javascript-api).
|
||||||
</ShowForTs>
|
</ShowForTs>
|
||||||
|
|
||||||
3. After successfully defining the job, you can submit work to be done in your [Operations](/docs/data-model/operations/overview) or [setupFn](/docs/project/server-config#setup-function) (or any other NodeJS code):
|
3. After successfully defining the job, you can submit work to be done in your [Operations](../data-model/operations/overview) or [setupFn](../project/server-config#setup-function) (or any other NodeJS code):
|
||||||
|
|
||||||
<Tabs groupId="js-ts">
|
<Tabs groupId="js-ts">
|
||||||
<TabItem value="js" label="JavaScript">
|
<TabItem value="js" label="JavaScript">
|
||||||
@ -333,7 +333,7 @@ The Job declaration has the following fields:
|
|||||||
|
|
||||||
- `entities: [Entity]`
|
- `entities: [Entity]`
|
||||||
|
|
||||||
A list of entities you wish to use inside your Job (similar to [Queries and Actions](/docs/data-model/operations/queries#using-entities-in-queries)).
|
A list of entities you wish to use inside your Job (similar to [Queries and Actions](../data-model/operations/queries#using-entities-in-queries)).
|
||||||
|
|
||||||
### JavaScript API
|
### JavaScript API
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ Wasp's Express server has the following middleware by default:
|
|||||||
- [express.json](https://expressjs.com/en/api.html#express.json) (which uses [body-parser](https://github.com/expressjs/body-parser#bodyparserjsonoptions)): parses incoming request bodies in a middleware before your handlers, making the result available under the `req.body` property.
|
- [express.json](https://expressjs.com/en/api.html#express.json) (which uses [body-parser](https://github.com/expressjs/body-parser#bodyparserjsonoptions)): parses incoming request bodies in a middleware before your handlers, making the result available under the `req.body` property.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
JSON middlware is required for [Operations](/docs/data-model/operations/overview) to function properly.
|
JSON middlware is required for [Operations](../data-model/operations/overview) to function properly.
|
||||||
:::
|
:::
|
||||||
- [express.urlencoded](https://expressjs.com/en/api.html#express.urlencoded) (which uses [body-parser](https://expressjs.com/en/resources/middleware/body-parser.html#bodyparserurlencodedoptions)): returns middleware that only parses urlencoded bodies and only looks at requests where the `Content-Type` header matches the type option.
|
- [express.urlencoded](https://expressjs.com/en/api.html#express.urlencoded) (which uses [body-parser](https://expressjs.com/en/resources/middleware/body-parser.html#bodyparserurlencodedoptions)): returns middleware that only parses urlencoded bodies and only looks at requests where the `Content-Type` header matches the type option.
|
||||||
- [cookieParser](https://github.com/expressjs/cookie-parser#readme): parses Cookie header and populates `req.cookies` with an object keyed by the cookie names.
|
- [cookieParser](https://github.com/expressjs/cookie-parser#readme): parses Cookie header and populates `req.cookies` with an object keyed by the cookie names.
|
||||||
|
@ -240,7 +240,7 @@ We'll define the React components for these pages in the `client/pages/auth.{jsx
|
|||||||
### 4. Create the Client Pages
|
### 4. Create the Client Pages
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](/docs/project/css-frameworks).
|
We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](../project/css-frameworks).
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Let's create a `auth.{jsx,tsx}` file in the `client/pages` folder and add the following to it:
|
Let's create a `auth.{jsx,tsx}` file in the `client/pages` folder and add the following to it:
|
||||||
@ -418,7 +418,7 @@ export function Layout({ children }: { children: React.ReactNode }) {
|
|||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
We imported the generated Auth UI components and used them in our pages. Read more about the Auth UI components [here](/docs/auth/ui).
|
We imported the generated Auth UI components and used them in our pages. Read more about the Auth UI components [here](../auth/ui).
|
||||||
|
|
||||||
### 5. Set up an Email Sender
|
### 5. Set up an Email Sender
|
||||||
|
|
||||||
@ -461,15 +461,15 @@ app myApp {
|
|||||||
SENDGRID_API_KEY=<your key>
|
SENDGRID_API_KEY=<your key>
|
||||||
```
|
```
|
||||||
|
|
||||||
If you are not sure how to get a SendGrid API key, read more [here](/docs/advanced/email#getting-the-api-key).
|
If you are not sure how to get a SendGrid API key, read more [here](../advanced/email#getting-the-api-key).
|
||||||
|
|
||||||
Read more about setting up email senders in the [sending emails docs](/docs/advanced/email).
|
Read more about setting up email senders in the [sending emails docs](../advanced/email).
|
||||||
|
|
||||||
### Conclusion
|
### Conclusion
|
||||||
|
|
||||||
That's it! We have set up email authentication in our app. 🎉
|
That's it! We have set up email authentication in our app. 🎉
|
||||||
|
|
||||||
Running `wasp db migrate-dev` and then `wasp start` should give you a working app with email authentication. If you want to put some of the pages behind authentication, read the [using auth docs](/docs/auth/overview).
|
Running `wasp db migrate-dev` and then `wasp start` should give you a working app with email authentication. If you want to put some of the pages behind authentication, read the [using auth docs](../auth/overview).
|
||||||
|
|
||||||
## Login and Signup Flows
|
## Login and Signup Flows
|
||||||
|
|
||||||
@ -500,7 +500,7 @@ Some of the behavior you get out of the box:
|
|||||||
|
|
||||||
4. Password validation
|
4. Password validation
|
||||||
|
|
||||||
Read more about the default password validation rules and how to override them in [using auth docs](/docs/auth/overview).
|
Read more about the default password validation rules and how to override them in [using auth docs](../auth/overview).
|
||||||
|
|
||||||
## Email Verification Flow
|
## Email Verification Flow
|
||||||
|
|
||||||
@ -597,7 +597,7 @@ The content of the e-mail can be customized, read more about it [here](#password
|
|||||||
|
|
||||||
## Using The Auth
|
## Using The Auth
|
||||||
|
|
||||||
To read more about how to set up the logout button and how to get access to the logged-in user in our client and server code, read the [using auth docs](/docs/auth/overview).
|
To read more about how to set up the logout button and how to get access to the logged-in user in our client and server code, read the [using auth docs](../auth/overview).
|
||||||
|
|
||||||
## API Reference
|
## API Reference
|
||||||
|
|
||||||
|
@ -78,11 +78,11 @@ Wasp supports the following auth methods:
|
|||||||
|
|
||||||
<AuthMethodsGrid />
|
<AuthMethodsGrid />
|
||||||
|
|
||||||
Let's say we enabled the [Username & password](/docs/auth/username-and-pass) authentication.
|
Let's say we enabled the [Username & password](../auth/username-and-pass) authentication.
|
||||||
|
|
||||||
We get an auth backend with signup and login endpoints. We also get the `user` object in our [Operations](/docs/data-model/operations/overview) and we can decide what to do based on whether the user is logged in or not.
|
We get an auth backend with signup and login endpoints. We also get the `user` object in our [Operations](../data-model/operations/overview) and we can decide what to do based on whether the user is logged in or not.
|
||||||
|
|
||||||
We would also get the [Auth UI](/docs/auth/ui) generated for us. We can set up our login and signup pages where our users can **create their account** and **login**. We can then protect certain pages by setting `authRequired: true` for them. This will make sure that only logged-in users can access them.
|
We would also get the [Auth UI](../auth/ui) generated for us. We can set up our login and signup pages where our users can **create their account** and **login**. We can then protect certain pages by setting `authRequired: true` for them. This will make sure that only logged-in users can access them.
|
||||||
|
|
||||||
We will also have access to the `user` object in our frontend code, so we can show different UI to logged-in and logged-out users. For example, we can show the user's name in the header alongside a **logout button** or a login button if the user is not logged in.
|
We will also have access to the `user` object in our frontend code, so we can show different UI to logged-in and logged-out users. For example, we can show the user's name in the header alongside a **logout button** or a login button if the user is not logged in.
|
||||||
|
|
||||||
@ -301,7 +301,7 @@ Since the `user` prop is only available in a page's React component: use the `us
|
|||||||
|
|
||||||
#### Using the `context.user` object
|
#### Using the `context.user` object
|
||||||
|
|
||||||
When authentication is enabled, all [queries and actions](/docs/data-model/operations/overview) have access to the `user` object through the `context` argument. `context.user` contains all User entity's fields, except for the password.
|
When authentication is enabled, all [queries and actions](../data-model/operations/overview) have access to the `user` object through the `context` argument. `context.user` contains all User entity's fields, except for the password.
|
||||||
|
|
||||||
<Tabs groupId="js-ts">
|
<Tabs groupId="js-ts">
|
||||||
<TabItem value="js" label="JavaScript">
|
<TabItem value="js" label="JavaScript">
|
||||||
@ -361,7 +361,7 @@ export const createTask: CreateTask<CreateTaskPayload, Task> = async (
|
|||||||
|
|
||||||
To implement access control in your app, each operation must check `context.user` and decide what to do. For example, if `context.user` is `undefined` inside a private operation, the user's access should be denied.
|
To implement access control in your app, each operation must check `context.user` and decide what to do. For example, if `context.user` is `undefined` inside a private operation, the user's access should be denied.
|
||||||
|
|
||||||
When using WebSockets, the `user` object is also available on the `socket.data` object. Read more in the [WebSockets section](/docs/advanced/web-sockets#websocketfn-function).
|
When using WebSockets, the `user` object is also available on the `socket.data` object. Read more in the [WebSockets section](../advanced/web-sockets#websocketfn-function).
|
||||||
|
|
||||||
## User entity
|
## User entity
|
||||||
|
|
||||||
@ -419,7 +419,7 @@ Default validations depend on the auth method you use.
|
|||||||
|
|
||||||
#### Username & password
|
#### Username & password
|
||||||
|
|
||||||
If you use [Username & password](/docs/auth/username-and-pass) authentication, the default validations are:
|
If you use [Username & password](../auth/username-and-pass) authentication, the default validations are:
|
||||||
|
|
||||||
- The `username` must not be empty
|
- The `username` must not be empty
|
||||||
- The `password` must not be empty, have at least 8 characters, and contain a number
|
- The `password` must not be empty, have at least 8 characters, and contain a number
|
||||||
@ -428,7 +428,7 @@ Note that `username`s are stored in a **case-sensitive** manner.
|
|||||||
|
|
||||||
#### Email
|
#### Email
|
||||||
|
|
||||||
If you use [Email](/docs/auth/email) authentication, the default validations are:
|
If you use [Email](../auth/email) authentication, the default validations are:
|
||||||
|
|
||||||
- The `email` must not be empty and a valid email address
|
- The `email` must not be empty and a valid email address
|
||||||
- The `password` must not be empty, have at least 8 characters, and contain a number
|
- The `password` must not be empty, have at least 8 characters, and contain a number
|
||||||
@ -726,7 +726,7 @@ Now that we defined the fields, Wasp knows how to:
|
|||||||
1. Validate the data sent from the client
|
1. Validate the data sent from the client
|
||||||
2. Save the data to the database
|
2. Save the data to the database
|
||||||
|
|
||||||
Next, let's see how to customize [Auth UI](/docs/auth/ui) to include those fields.
|
Next, let's see how to customize [Auth UI](../auth/ui) to include those fields.
|
||||||
|
|
||||||
### 2. Customizing the Signup Component
|
### 2. Customizing the Signup Component
|
||||||
|
|
||||||
@ -736,8 +736,8 @@ If you are not using Wasp's Auth UI, you can skip this section. Just make sure t
|
|||||||
|
|
||||||
Read more about using the signup actions for:
|
Read more about using the signup actions for:
|
||||||
|
|
||||||
- email auth [here](/docs/auth/email#fields-in-the-email-dict) <!-- TODO: these docs are not great at explaining using signup and login actions: https://github.com/wasp-lang/wasp/issues/1438 -->
|
- email auth [here](../auth/email#fields-in-the-email-dict) <!-- TODO: these docs are not great at explaining using signup and login actions: https://github.com/wasp-lang/wasp/issues/1438 -->
|
||||||
- username & password auth [here](/docs/auth/username-and-pass#customizing-the-auth-flow)
|
- username & password auth [here](../auth/username-and-pass#customizing-the-auth-flow)
|
||||||
:::
|
:::
|
||||||
|
|
||||||
If you are using Wasp's Auth UI, you can customize the `SignupForm` component by passing the `additionalFields` prop to it. It can be either a list of extra fields or a render function.
|
If you are using Wasp's Auth UI, you can customize the `SignupForm` component by passing the `additionalFields` prop to it. It can be either a list of extra fields or a render function.
|
||||||
@ -1046,7 +1046,7 @@ psl=}
|
|||||||
The same `externalAuthEntity` can be used across different social login providers (e.g., both GitHub and Google can use the same entity).
|
The same `externalAuthEntity` can be used across different social login providers (e.g., both GitHub and Google can use the same entity).
|
||||||
:::
|
:::
|
||||||
|
|
||||||
See [Google docs](/docs/auth/social-auth/google) and [GitHub docs](/docs/auth/social-auth/github) for more details.
|
See [Google docs](../auth/social-auth/google) and [GitHub docs](../auth/social-auth/github) for more details.
|
||||||
|
|
||||||
#### `methods: dict` <Required />
|
#### `methods: dict` <Required />
|
||||||
|
|
||||||
@ -1057,7 +1057,7 @@ A dictionary of auth methods enabled for the app.
|
|||||||
#### `onAuthFailedRedirectTo: String` <Required />
|
#### `onAuthFailedRedirectTo: String` <Required />
|
||||||
|
|
||||||
The route to which Wasp should redirect unauthenticated user when they try to access a private page (i.e., a page that has `authRequired: true`).
|
The route to which Wasp should redirect unauthenticated user when they try to access a private page (i.e., a page that has `authRequired: true`).
|
||||||
Check out these [essentials docs on auth](/docs/tutorial/auth#adding-auth-to-the-project) to see an example of usage.
|
Check out these [essentials docs on auth](../tutorial/auth#adding-auth-to-the-project) to see an example of usage.
|
||||||
|
|
||||||
#### `onAuthSucceededRedirectTo: String`
|
#### `onAuthSucceededRedirectTo: String`
|
||||||
|
|
||||||
@ -1065,7 +1065,7 @@ The route to which Wasp will send a successfully authenticated after a successfu
|
|||||||
The default value is `"/"`.
|
The default value is `"/"`.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
Automatic redirect on successful login only works when using the Wasp-provided [Auth UI](/docs/auth/ui).
|
Automatic redirect on successful login only works when using the Wasp-provided [Auth UI](../auth/ui).
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### `signup: SignupOptions`
|
#### `signup: SignupOptions`
|
||||||
|
@ -5,6 +5,6 @@ Provider-specific behavior comes down to implementing two functions.
|
|||||||
|
|
||||||
The reference shows how to define both.
|
The reference shows how to define both.
|
||||||
|
|
||||||
For behavior common to all providers, check the general [API Reference](/docs/auth/overview.md#api-reference).
|
For behavior common to all providers, check the general [API Reference](../../auth/overview.md#api-reference).
|
||||||
|
|
||||||
<!-- This snippet is used in google.md and github.md -->
|
<!-- This snippet is used in google.md and github.md -->
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
To read more about how to set up the logout button and get access to the logged-in user in both client and server code, read the docs on [using auth](/docs/auth/overview).
|
To read more about how to set up the logout button and get access to the logged-in user in both client and server code, read the docs on [using auth](../../auth/overview).
|
||||||
|
|
||||||
<!-- This snippet is used in google.md and github.md -->
|
<!-- This snippet is used in google.md and github.md -->
|
||||||
|
@ -159,7 +159,7 @@ psl=}
|
|||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
`externalAuthEntity` and `userEntity` are explained in [the social auth overview](/docs/auth/social-auth/overview#social-login-entity).
|
`externalAuthEntity` and `userEntity` are explained in [the social auth overview](../../auth/social-auth/overview#social-login-entity).
|
||||||
|
|
||||||
### 3. Creating a GitHub OAuth App
|
### 3. Creating a GitHub OAuth App
|
||||||
|
|
||||||
@ -231,7 +231,7 @@ We'll define the React components for these pages in the `client/pages/auth.{jsx
|
|||||||
### 6. Creating the Client Pages
|
### 6. Creating the Client Pages
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](/docs/project/css-frameworks).
|
We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](../../project/css-frameworks).
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Let's create a `auth.{jsx,tsx}` file in the `client/pages` folder and add the following to it:
|
Let's create a `auth.{jsx,tsx}` file in the `client/pages` folder and add the following to it:
|
||||||
@ -295,7 +295,7 @@ export function Layout({ children }: { children: React.ReactNode }) {
|
|||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
We imported the generated Auth UI component and used them in our pages. Read more about the Auth UI components [here](/docs/auth/ui).
|
We imported the generated Auth UI component and used them in our pages. Read more about the Auth UI components [here](../../auth/ui).
|
||||||
|
|
||||||
### Conclusion
|
### Conclusion
|
||||||
|
|
||||||
@ -304,7 +304,7 @@ Yay, we've successfully set up Github Auth! 🎉
|
|||||||
![Github Auth](/img/auth/github.png)
|
![Github Auth](/img/auth/github.png)
|
||||||
|
|
||||||
Running `wasp db migrate-dev` and `wasp start` should now give you a working app with authentication.
|
Running `wasp db migrate-dev` and `wasp start` should now give you a working app with authentication.
|
||||||
To see how to protect specific pages (i.e., hide them from non-authenticated users), read the docs on [using auth](/docs/auth/overview).
|
To see how to protect specific pages (i.e., hide them from non-authenticated users), read the docs on [using auth](../../auth/overview).
|
||||||
|
|
||||||
## Default Behaviour
|
## Default Behaviour
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ app myApp {
|
|||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
`externalAuthEntity` and `userEntity` are explained in [the social auth overview](/docs/auth/social-auth/overview#social-login-entity).
|
`externalAuthEntity` and `userEntity` are explained in [the social auth overview](../../auth/social-auth/overview#social-login-entity).
|
||||||
|
|
||||||
### 2. Adding the Entities
|
### 2. Adding the Entities
|
||||||
|
|
||||||
@ -271,7 +271,7 @@ We'll define the React components for these pages in the `client/pages/auth.{jsx
|
|||||||
### 6. Create the Client Pages
|
### 6. Create the Client Pages
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](/docs/project/css-frameworks).
|
We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](../../project/css-frameworks).
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Let's now create a `auth.{jsx,tsx}` file in the `client/pages`.
|
Let's now create a `auth.{jsx,tsx}` file in the `client/pages`.
|
||||||
@ -337,7 +337,7 @@ export function Layout({ children }: { children: React.ReactNode }) {
|
|||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
:::info Auth UI
|
:::info Auth UI
|
||||||
Our pages use an automatically-generated Auth UI component. Read more about Auth UI components [here](/docs/auth/ui).
|
Our pages use an automatically-generated Auth UI component. Read more about Auth UI components [here](../../auth/ui).
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### Conclusion
|
### Conclusion
|
||||||
@ -347,7 +347,7 @@ Yay, we've successfully set up Google Auth! 🎉
|
|||||||
![Google Auth](/img/auth/google.png)
|
![Google Auth](/img/auth/google.png)
|
||||||
|
|
||||||
Running `wasp db migrate-dev` and `wasp start` should now give you a working app with authentication.
|
Running `wasp db migrate-dev` and `wasp start` should now give you a working app with authentication.
|
||||||
To see how to protect specific pages (i.e., hide them from non-authenticated users), read the docs on [using auth](/docs/auth/overview).
|
To see how to protect specific pages (i.e., hide them from non-authenticated users), read the docs on [using auth](../../auth/overview).
|
||||||
|
|
||||||
## Default Behaviour
|
## Default Behaviour
|
||||||
|
|
||||||
|
@ -258,7 +258,7 @@ export const getUserFields: GetUserFieldsFn = async (_context, _args) => {
|
|||||||
|
|
||||||
#### 3. Showing the Correct State on the Client
|
#### 3. Showing the Correct State on the Client
|
||||||
|
|
||||||
You can query the user's `isSignupComplete` flag on the client with the [`useAuth()`](/docs/auth/overview) hook.
|
You can query the user's `isSignupComplete` flag on the client with the [`useAuth()`](../../auth/overview) hook.
|
||||||
Depending on the flag's value, you can redirect users to the appropriate signup step.
|
Depending on the flag's value, you can redirect users to the appropriate signup step.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
@ -317,7 +317,7 @@ Each provider has their own rules for defining the `getUserFieldsFn` and `config
|
|||||||
## UI Helpers
|
## UI Helpers
|
||||||
|
|
||||||
:::tip Use Auth UI
|
:::tip Use Auth UI
|
||||||
[Auth UI](/docs/auth/ui) is a common name for all high-level auth forms that come with Wasp.
|
[Auth UI](../../auth/ui) is a common name for all high-level auth forms that come with Wasp.
|
||||||
|
|
||||||
These include fully functional auto-generated login and signup forms with working social login buttons.
|
These include fully functional auto-generated login and signup forms with working social login buttons.
|
||||||
If you're looking for the fastest way to get your auth up and running, that's where you should look.
|
If you're looking for the fastest way to get your auth up and running, that's where you should look.
|
||||||
|
@ -218,7 +218,7 @@ export function SignupPage() {
|
|||||||
|
|
||||||
It will automatically show the correct authentication providers based on your `main.wasp` file.
|
It will automatically show the correct authentication providers based on your `main.wasp` file.
|
||||||
|
|
||||||
Read more about customizing the signup process like adding additional fields or extra UI in the [Using Auth](/docs/auth/overview#customizing-the-signup-process) section.
|
Read more about customizing the signup process like adding additional fields or extra UI in the [Using Auth](../auth/overview#customizing-the-signup-process) section.
|
||||||
|
|
||||||
### Forgot Password Form
|
### Forgot Password Form
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ We'll define the React components for these pages in the `client/pages/auth.{jsx
|
|||||||
### 4. Create the Client Pages
|
### 4. Create the Client Pages
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](/docs/project/css-frameworks).
|
We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](../project/css-frameworks).
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Let's create a `auth.{jsx,tsx}` file in the `client/pages` folder and add the following to it:
|
Let's create a `auth.{jsx,tsx}` file in the `client/pages` folder and add the following to it:
|
||||||
@ -255,19 +255,19 @@ export function Layout({ children }: { children: React.ReactNode }) {
|
|||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
We imported the generated Auth UI components and used them in our pages. Read more about the Auth UI components [here](/docs/auth/ui).
|
We imported the generated Auth UI components and used them in our pages. Read more about the Auth UI components [here](../auth/ui).
|
||||||
|
|
||||||
### Conclusion
|
### Conclusion
|
||||||
|
|
||||||
That's it! We have set up username authentication in our app. 🎉
|
That's it! We have set up username authentication in our app. 🎉
|
||||||
|
|
||||||
Running `wasp db migrate-dev` and then `wasp start` should give you a working app with username authentication. If you want to put some of the pages behind authentication, read the [using auth docs](/docs/auth/overview).
|
Running `wasp db migrate-dev` and then `wasp start` should give you a working app with username authentication. If you want to put some of the pages behind authentication, read the [using auth docs](../auth/overview).
|
||||||
|
|
||||||
## Customizing the Auth Flow
|
## Customizing the Auth Flow
|
||||||
|
|
||||||
The login and signup flows are pretty standard: they allow the user to sign up and then log in with their username and password. The signup flow validates the username and password and then creates a new user entity in the database.
|
The login and signup flows are pretty standard: they allow the user to sign up and then log in with their username and password. The signup flow validates the username and password and then creates a new user entity in the database.
|
||||||
|
|
||||||
Read more about the default username and password validation rules and how to override them in the [using auth docs](/docs/auth/overview).
|
Read more about the default username and password validation rules and how to override them in the [using auth docs](../auth/overview).
|
||||||
|
|
||||||
If you require more control in your authentication flow, you can achieve that in the following ways:
|
If you require more control in your authentication flow, you can achieve that in the following ways:
|
||||||
1. Create your UI and use `signup` and `login` actions.
|
1. Create your UI and use `signup` and `login` actions.
|
||||||
@ -538,7 +538,7 @@ export const signUp: SignupUser<SignupPayload, User> = async (args, context) =>
|
|||||||
|
|
||||||
## Using Auth
|
## Using Auth
|
||||||
|
|
||||||
To read more about how to set up the logout button and how to get access to the logged-in user in our client and server code, read the [using auth docs](/docs/auth/overview).
|
To read more about how to set up the logout button and how to get access to the logged-in user in our client and server code, read the [using auth docs](../auth/overview).
|
||||||
|
|
||||||
## API Reference
|
## API Reference
|
||||||
|
|
||||||
@ -649,4 +649,4 @@ app myApp {
|
|||||||
`usernameAndPassword` dict doesn't have any options at the moment.
|
`usernameAndPassword` dict doesn't have any options at the moment.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
You can read about the rest of the `auth` options in the [using auth](/docs/auth/overview) section of the docs.
|
You can read about the rest of the `auth` options in the [using auth](../auth/overview) section of the docs.
|
||||||
|
@ -4,7 +4,7 @@ title: Databases
|
|||||||
|
|
||||||
import { Required } from '@site/src/components/Required'
|
import { Required } from '@site/src/components/Required'
|
||||||
|
|
||||||
[Entities](/docs/data-model/entities.md), [Operations](/docs/data-model/operations/overview) and [Automatic CRUD](/docs/data-model/crud.md) together make a high-level interface for working with your app's data. Still, all that data has to live somewhere, so let's see how Wasp deals with databases.
|
[Entities](../data-model/entities.md), [Operations](../data-model/operations/overview) and [Automatic CRUD](../data-model/crud.md) together make a high-level interface for working with your app's data. Still, all that data has to live somewhere, so let's see how Wasp deals with databases.
|
||||||
|
|
||||||
## Supported Database Backends
|
## Supported Database Backends
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ Also, make sure that:
|
|||||||
|
|
||||||
If you want to spin up your own dev database (or connect to an external one), you can tell Wasp about it using the `DATABASE_URL` environment variable. Wasp will use the value of `DATABASE_URL` as a connection string.
|
If you want to spin up your own dev database (or connect to an external one), you can tell Wasp about it using the `DATABASE_URL` environment variable. Wasp will use the value of `DATABASE_URL` as a connection string.
|
||||||
|
|
||||||
The easiest way to set the necessary `DATABASE_URL` environment variable is by adding it to the [.env.server](/docs/project/env-vars) file in the root dir of your Wasp project (if that file doesn't yet exist, create it).
|
The easiest way to set the necessary `DATABASE_URL` environment variable is by adding it to the [.env.server](../project/env-vars) file in the root dir of your Wasp project (if that file doesn't yet exist, create it).
|
||||||
|
|
||||||
Alternatively, you can set it inline when running `wasp` (this applies to all environment variables):
|
Alternatively, you can set it inline when running `wasp` (this applies to all environment variables):
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ If you have a lot of experience writing full-stack apps, you probably ended up d
|
|||||||
|
|
||||||
Wasp makes handling these boring bits easy by offering a higher-level concept called Automatic CRUD.
|
Wasp makes handling these boring bits easy by offering a higher-level concept called Automatic CRUD.
|
||||||
|
|
||||||
With a single declaration, you can tell Wasp to automatically generate server-side logic (i.e., Queries and Actions) for creating, reading, updating and deleting [Entities](/docs/data-model/entities). As you update definitions for your Entities, Wasp automatically regenerates the backend logic.
|
With a single declaration, you can tell Wasp to automatically generate server-side logic (i.e., Queries and Actions) for creating, reading, updating and deleting [Entities](../data-model/entities). As you update definitions for your Entities, Wasp automatically regenerates the backend logic.
|
||||||
|
|
||||||
:::caution Early preview
|
:::caution Early preview
|
||||||
This feature is currently in early preview and we are actively working on it. Read more about [our plans](#future-of-crud-operations-in-wasp) for CRUD operations.
|
This feature is currently in early preview and we are actively working on it. Read more about [our plans](#future-of-crud-operations-in-wasp) for CRUD operations.
|
||||||
@ -62,7 +62,7 @@ Keep reading for an example of Automatic CRUD in action, or skip ahead for the [
|
|||||||
|
|
||||||
## Example: A Simple TODO App
|
## Example: A Simple TODO App
|
||||||
|
|
||||||
Let's create a full-app example that uses automatic CRUD. We'll stick to using the `Task` entity from the previous example, but we'll add a `User` entity and enable [username and password](/docs/auth/username-and-pass) based auth.
|
Let's create a full-app example that uses automatic CRUD. We'll stick to using the `Task` entity from the previous example, but we'll add a `User` entity and enable [username and password](../auth/username-and-pass) based auth.
|
||||||
|
|
||||||
<ImgWithCaption alt="Automatic CRUD with Wasp" source="img/crud-guide.gif" caption="We are building a simple tasks app with username based auth"/>
|
<ImgWithCaption alt="Automatic CRUD with Wasp" source="img/crud-guide.gif" caption="We are building a simple tasks app with username based auth"/>
|
||||||
|
|
||||||
@ -328,7 +328,7 @@ export const MainPage = () => {
|
|||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
And here are the login and signup pages, where we are using Wasp's [Auth UI](/docs/auth/ui) components:
|
And here are the login and signup pages, where we are using Wasp's [Auth UI](../auth/ui) components:
|
||||||
|
|
||||||
<Tabs groupId="js-ts">
|
<Tabs groupId="js-ts">
|
||||||
<TabItem value="js" label="JavaScript">
|
<TabItem value="js" label="JavaScript">
|
||||||
@ -692,7 +692,7 @@ export const getAllOverride: GetAllQuery<Input, Output> = async (
|
|||||||
|
|
||||||
</ShowForTs>
|
</ShowForTs>
|
||||||
|
|
||||||
For a usage example, check the [example guide](/docs/data-model/crud#adding-crud-to-the-task-entity-).
|
For a usage example, check the [example guide](../data-model/crud#adding-crud-to-the-task-entity-).
|
||||||
|
|
||||||
#### Using the CRUD operations in client code
|
#### Using the CRUD operations in client code
|
||||||
|
|
||||||
@ -742,7 +742,7 @@ const deleteAction = Tasks.delete.useAction()
|
|||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
All CRUD operations are implemented with [Queries and Actions](/docs/data-model/operations/overview) under the hood, which means they come with all the features you'd expect (e.g., automatic SuperJSON serialization, full-stack type safety when using TypeScript)
|
All CRUD operations are implemented with [Queries and Actions](../data-model/operations/overview) under the hood, which means they come with all the features you'd expect (e.g., automatic SuperJSON serialization, full-stack type safety when using TypeScript)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -62,11 +62,11 @@ Let's see how you can define and work with Wasp Entities:
|
|||||||
1. Create/update some Entities in your `.wasp` file.
|
1. Create/update some Entities in your `.wasp` file.
|
||||||
2. Run `wasp db migrate-dev`. This command syncs the database model with the Entity definitions in your `.wasp` file. It does this by creating migration scripts.
|
2. Run `wasp db migrate-dev`. This command syncs the database model with the Entity definitions in your `.wasp` file. It does this by creating migration scripts.
|
||||||
3. Migration scripts are automatically placed in the `migrations/` folder. Make sure to commit this folder into version control.
|
3. Migration scripts are automatically placed in the `migrations/` folder. Make sure to commit this folder into version control.
|
||||||
4. Use Wasp's JavasScript API to work with the database when implementing Operations (we'll cover this in detail when we talk about [operations](/docs/data-model/operations/overview)).
|
4. Use Wasp's JavasScript API to work with the database when implementing Operations (we'll cover this in detail when we talk about [operations](../data-model/operations/overview)).
|
||||||
|
|
||||||
#### Using Entities in Operations
|
#### Using Entities in Operations
|
||||||
|
|
||||||
Most of the time, you will be working with Entities within the context of [Operations (Queries & Actions)](/docs/data-model/operations/overview). We'll see how that's done on the next page.
|
Most of the time, you will be working with Entities within the context of [Operations (Queries & Actions)](../data-model/operations/overview). We'll see how that's done on the next page.
|
||||||
|
|
||||||
#### Using Entities directly
|
#### Using Entities directly
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import SuperjsonNote from './\_superjson-note.md';
|
|||||||
|
|
||||||
We'll explain what Actions are and how to use them. If you're looking for a detailed API specification, skip ahead to the [API Reference](#api-reference).
|
We'll explain what Actions are and how to use them. If you're looking for a detailed API specification, skip ahead to the [API Reference](#api-reference).
|
||||||
|
|
||||||
Actions are quite similar to [Queries](/docs/data-model/operations/queries.md), but with a key distinction: Actions are designed to modify and add data, while Queries are solely for reading data. Examples of Actions include adding a comment to a blog post, liking a video, or updating a product's price.
|
Actions are quite similar to [Queries](../../data-model/operations/queries.md), but with a key distinction: Actions are designed to modify and add data, while Queries are solely for reading data. Examples of Actions include adding a comment to a blog post, liking a video, or updating a product's price.
|
||||||
|
|
||||||
Actions and Queries work together to keep data caches up-to-date.
|
Actions and Queries work together to keep data caches up-to-date.
|
||||||
|
|
||||||
@ -373,7 +373,7 @@ export const createTask: CreateTask = async (args, context) => {
|
|||||||
|
|
||||||
### Using Entities in Actions
|
### Using Entities in Actions
|
||||||
|
|
||||||
In most cases, resources used in Actions will be [Entities](/docs/data-model/entities.md).
|
In most cases, resources used in Actions will be [Entities](../../data-model/entities.md).
|
||||||
To use an Entity in your Action, add it to the `action` declaration in Wasp:
|
To use an Entity in your Action, add it to the `action` declaration in Wasp:
|
||||||
|
|
||||||
<Tabs groupId="js-ts">
|
<Tabs groupId="js-ts">
|
||||||
@ -626,7 +626,7 @@ Since both arguments are positional, you can name the parameters however you wan
|
|||||||
|
|
||||||
2. `context` (type depends on the Action)
|
2. `context` (type depends on the Action)
|
||||||
|
|
||||||
An additional context object **passed into the Action by Wasp**. This object contains user session information, as well as information about entities. Check the [section about using entities in Actions](#using-entities-in-actions) to see how to use the entities field on the `context` object, or the [auth section](/docs/auth/overview#using-the-contextuser-object) to see how to use the `user` object.
|
An additional context object **passed into the Action by Wasp**. This object contains user session information, as well as information about entities. Check the [section about using entities in Actions](#using-entities-in-actions) to see how to use the entities field on the `context` object, or the [auth section](../../auth/overview#using-the-contextuser-object) to see how to use the `user` object.
|
||||||
|
|
||||||
<ShowForTs>
|
<ShowForTs>
|
||||||
|
|
||||||
@ -704,7 +704,7 @@ In this case, the Action expects to receive an object with a `bar` field of type
|
|||||||
|
|
||||||
### The `useAction` Hook and Optimistic Updates
|
### The `useAction` Hook and Optimistic Updates
|
||||||
|
|
||||||
Make sure you understand how [Queries](/docs/data-model/operations/queries.md) and [Cache Invalidation](#cache-invalidation) work before reading this chapter.
|
Make sure you understand how [Queries](../../data-model/operations/queries.md) and [Cache Invalidation](#cache-invalidation) work before reading this chapter.
|
||||||
|
|
||||||
When using Actions in components, you can enhance them with the help of the `useAction` hook. This hook comes bundled with Wasp, and is used for decorating Wasp Actions.
|
When using Actions in components, you can enhance them with the help of the `useAction` hook. This hook comes bundled with Wasp, and is used for decorating Wasp Actions.
|
||||||
In other words, the hook returns a function whose API matches the original Action while also doing something extra under the hood (depending on how you configure it).
|
In other words, the hook returns a function whose API matches the original Action while also doing something extra under the hood (depending on how you configure it).
|
||||||
|
@ -6,7 +6,7 @@ import { Required } from '@site/src/components/Required';
|
|||||||
|
|
||||||
While Entities enable help you define your app's data model and relationships, Operations are all about working with this data.
|
While Entities enable help you define your app's data model and relationships, Operations are all about working with this data.
|
||||||
|
|
||||||
There are two kinds of Operations: [Queries](/docs/data-model/operations/queries.md) and [Actions](/docs/data-model/operations/actions.md). As their names suggest,
|
There are two kinds of Operations: [Queries](../../data-model/operations/queries.md) and [Actions](../../data-model/operations/actions.md). As their names suggest,
|
||||||
Queries are meant for reading data, and Actions are meant for changing it (either by updating existing entries or creating new ones).
|
Queries are meant for reading data, and Actions are meant for changing it (either by updating existing entries or creating new ones).
|
||||||
|
|
||||||
Keep reading to find out all there is to know about Operations in Wasp.
|
Keep reading to find out all there is to know about Operations in Wasp.
|
||||||
|
@ -15,7 +15,7 @@ Fetching all comments on a blog post, a list of users that liked a video, inform
|
|||||||
Queries are fairly similar to Actions in terms of their API.
|
Queries are fairly similar to Actions in terms of their API.
|
||||||
Therefore, if you're already familiar with Actions, you might find reading the entire guide repetitive.
|
Therefore, if you're already familiar with Actions, you might find reading the entire guide repetitive.
|
||||||
|
|
||||||
We instead recommend skipping ahead and only reading [the differences between Queries and Actions](/docs/data-model/operations/actions#differences-between-queries-and-actions), and consulting the [API Reference](#api-reference) as needed.
|
We instead recommend skipping ahead and only reading [the differences between Queries and Actions](../../data-model/operations/actions#differences-between-queries-and-actions), and consulting the [API Reference](#api-reference) as needed.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
## Working with Queries
|
## Working with Queries
|
||||||
@ -395,7 +395,7 @@ To prevent information leakage, the server won't forward these fields for any ot
|
|||||||
|
|
||||||
### Using Entities in Queries
|
### Using Entities in Queries
|
||||||
|
|
||||||
In most cases, resources used in Queries will be [Entities](/docs/data-model/entities.md).
|
In most cases, resources used in Queries will be [Entities](../../data-model/entities.md).
|
||||||
To use an Entity in your Query, add it to the `query` declaration in Wasp:
|
To use an Entity in your Query, add it to the `query` declaration in Wasp:
|
||||||
|
|
||||||
<Tabs groupId="js-ts">
|
<Tabs groupId="js-ts">
|
||||||
@ -552,7 +552,7 @@ Since both arguments are positional, you can name the parameters however you wan
|
|||||||
|
|
||||||
2. `context` (type depends on the Query)
|
2. `context` (type depends on the Query)
|
||||||
|
|
||||||
An additional context object **passed into the Query by Wasp**. This object contains user session information, as well as information about entities. Check the [section about using entities in Queries](#using-entities-in-queries) to see how to use the entities field on the `context` object, or the [auth section](/docs/auth/overview#using-the-contextuser-object) to see how to use the `user` object.
|
An additional context object **passed into the Query by Wasp**. This object contains user session information, as well as information about entities. Check the [section about using entities in Queries](#using-entities-in-queries) to see how to use the entities field on the `context` object, or the [auth section](../../auth/overview#using-the-contextuser-object) to see how to use the `user` object.
|
||||||
|
|
||||||
<ShowForTs>
|
<ShowForTs>
|
||||||
|
|
||||||
@ -651,6 +651,6 @@ Wasp's `useQuery` hook accepts three arguments:
|
|||||||
[the default
|
[the default
|
||||||
behavior](https://react-query.tanstack.com/guides/important-defaults) for
|
behavior](https://react-query.tanstack.com/guides/important-defaults) for
|
||||||
this particular Query. If you want to change the global defaults, you can do
|
this particular Query. If you want to change the global defaults, you can do
|
||||||
so in the [client setup function](/docs/project/client-config.md#overriding-default-behaviour-for-queries).
|
so in the [client setup function](../../project/client-config.md#overriding-default-behaviour-for-queries).
|
||||||
|
|
||||||
For an example of usage, check [this section](#the-usequery-hook).
|
For an example of usage, check [this section](#the-usequery-hook).
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
---
|
|
||||||
title: Examples
|
|
||||||
---
|
|
||||||
|
|
||||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
|
||||||
|
|
||||||
We have a constantly growing collection of fully-functioning example apps, which you can use to learn more about Wasp's features.
|
|
||||||
|
|
||||||
The full list of examples can be found [here](https://github.com/wasp-lang/wasp/tree/release/examples/). Here is a few of them:
|
|
||||||
|
|
||||||
## Todo App
|
|
||||||
- **Features**: Auth ([username/password](language/features#authentication--authorization)), [Queries & Actions](language/features#queries-and-actions-aka-operations), [Entities](language/features#entity), [Routes](language/features#route)
|
|
||||||
- JS source code: [GitHub](https://github.com/wasp-lang/wasp/tree/release/examples/tutorials/TodoApp)
|
|
||||||
- TS source code: [GitHub](https://github.com/wasp-lang/wasp/tree/release/examples/todo-typescript)
|
|
||||||
- in-browser dev environment: [GitPod](https://gitpod.io/#https://github.com/wasp-lang/gitpod-template)
|
|
||||||
|
|
||||||
## Waspello (Trello Clone)
|
|
||||||
- **Features**: Auth ([Google](language/features#social-login-providers-oauth-20), [username/password](language/features#authentication--authorization)), [Optimistic Updates](language/features#the-useaction-hook), [Tailwind CSS integration](/docs/project/css-frameworks)
|
|
||||||
- Source code: [GitHub](https://github.com/wasp-lang/wasp/tree/main/examples/waspello)
|
|
||||||
- Hosted at [https://waspello-demo.netlify.app](https://waspello-demo.netlify.app/login)
|
|
||||||
<p align='center'>
|
|
||||||
<img src={useBaseUrl('img/wespello-new.png')} width='75%'/>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
## Waspleau (Realtime Statistics Dashboard)
|
|
||||||
- **Features**: Cron [Jobs](language/features#jobs), [Server Setup](language/features#server-configuration)
|
|
||||||
- Source code: [GitHub](https://github.com/wasp-lang/wasp/tree/main/examples/waspleau)
|
|
||||||
- Hosted at [https://waspleau-app-client.fly.dev/](https://waspleau-app-client.fly.dev/)
|
|
||||||
<p align='center'>
|
|
||||||
<img src={useBaseUrl('img/waspleau.png')} width='75%'/>
|
|
||||||
</p>
|
|
@ -5,7 +5,7 @@ This guide provides an overview of the Wasp CLI commands, arguments, and options
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
Once [installed](/docs/quick-start), you can use the wasp command from your command line.
|
Once [installed](../quick-start), you can use the wasp command from your command line.
|
||||||
|
|
||||||
If you run the `wasp` command without any arguments, it will show you a list of available commands and their descriptions:
|
If you run the `wasp` command without any arguments, it will show you a list of available commands and their descriptions:
|
||||||
|
|
||||||
@ -96,13 +96,13 @@ Newsletter: https://wasp-lang.dev/#signup
|
|||||||
Deleted .wasp/ directory.
|
Deleted .wasp/ directory.
|
||||||
```
|
```
|
||||||
|
|
||||||
- `wasp build` generates the complete web app code, which is ready for [deployment](/docs/advanced/deployment/overview). Use this command when you're deploying or ejecting. The generated code is stored in the `.wasp/build` folder.
|
- `wasp build` generates the complete web app code, which is ready for [deployment](../advanced/deployment/overview). Use this command when you're deploying or ejecting. The generated code is stored in the `.wasp/build` folder.
|
||||||
|
|
||||||
- `wasp deploy` makes it easy to get your app hosted on the web.
|
- `wasp deploy` makes it easy to get your app hosted on the web.
|
||||||
|
|
||||||
Currently, Wasp offers support for [Fly.io](https://fly.io). If you prefer a different hosting provider, feel free to let us know on Discord or submit a PR by updating [this TypeScript app](https://github.com/wasp-lang/wasp/tree/main/waspc/packages/deploy).
|
Currently, Wasp offers support for [Fly.io](https://fly.io). If you prefer a different hosting provider, feel free to let us know on Discord or submit a PR by updating [this TypeScript app](https://github.com/wasp-lang/wasp/tree/main/waspc/packages/deploy).
|
||||||
|
|
||||||
Read more about automatic deployment [here](/docs/advanced/deployment/cli).
|
Read more about automatic deployment [here](../advanced/deployment/cli).
|
||||||
|
|
||||||
- `wasp telemetry` displays the status of [telemetry](https://wasp-lang.dev/docs/telemetry).
|
- `wasp telemetry` displays the status of [telemetry](https://wasp-lang.dev/docs/telemetry).
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ slug: /editor-setup
|
|||||||
---
|
---
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
This page assumes you have already installed Wasp. If you do not have Wasp installed yet, check out the [Quick Start](/docs/quick-start) guide.
|
This page assumes you have already installed Wasp. If you do not have Wasp installed yet, check out the [Quick Start](./quick-start.md) guide.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Wasp comes with the Wasp language server, which gives supported editors powerful support and integration with the language.
|
Wasp comes with the Wasp language server, which gives supported editors powerful support and integration with the language.
|
||||||
|
@ -6,7 +6,7 @@ slug: /
|
|||||||
import ImgWithCaption from '@site/blog/components/ImgWithCaption'
|
import ImgWithCaption from '@site/blog/components/ImgWithCaption'
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
If you are looking for the installation instructions, check out the [Quick Start](/docs/quick-start) section.
|
If you are looking for the installation instructions, check out the [Quick Start](./quick-start.md) section.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
We will give a brief overview of what Wasp is, how it works on a high level and when to use it.
|
We will give a brief overview of what Wasp is, how it works on a high level and when to use it.
|
||||||
@ -170,7 +170,7 @@ export function HomePage({ user }: { user: User }) {
|
|||||||
|
|
||||||
And voila! We are listing all the recipes in our app 🎉
|
And voila! We are listing all the recipes in our app 🎉
|
||||||
|
|
||||||
This was just a quick example to give you a taste of what Wasp is. For step by step tour through the most important Wasp features, check out the [Todo app tutorial](/docs/tutorial/create).
|
This was just a quick example to give you a taste of what Wasp is. For step by step tour through the most important Wasp features, check out the [Todo app tutorial](../tutorial/01-create.md).
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
Above we skipped defining /login and /signup pages to keep the example a bit shorter, but those are very simple to do by using Wasp's Auth UI feature.
|
Above we skipped defining /login and /signup pages to keep the example a bit shorter, but those are very simple to do by using Wasp's Auth UI feature.
|
@ -43,8 +43,8 @@ Check [More Details](#more-details) section below if anything went wrong, or if
|
|||||||
|
|
||||||
### What next?
|
### What next?
|
||||||
|
|
||||||
- [ ] 👉 **Check out the [Todo App tutorial](/docs/tutorial/create), which will take you through all the core features of Wasp!** 👈
|
- [ ] 👉 **Check out the [Todo App tutorial](../tutorial/01-create.md), which will take you through all the core features of Wasp!** 👈
|
||||||
- [ ] [Setup your editor](/docs/editor-setup) for working with Wasp.
|
- [ ] [Setup your editor](./editor-setup.md) for working with Wasp.
|
||||||
- [ ] Join us on [Discord](https://discord.gg/rzdnErX)! Any feedback or questions you have, we are there for you.
|
- [ ] Join us on [Discord](https://discord.gg/rzdnErX)! Any feedback or questions you have, we are there for you.
|
||||||
- [ ] Follow Wasp development by subscribing to our newsletter: https://wasp-lang.dev/#signup . We usually send 1 per month, and Matija does his best to unleash his creativity to make them engaging and fun to read :D!
|
- [ ] Follow Wasp development by subscribing to our newsletter: https://wasp-lang.dev/#signup . We usually send 1 per month, and Matija does his best to unleash his creativity to make them engaging and fun to read :D!
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -211,7 +211,7 @@ export default async function mySetupFunction(): Promise<void> {
|
|||||||
### Overriding Default Behaviour for Queries
|
### Overriding Default Behaviour for Queries
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
You can change the options for a **single** Query using the `options` object, as described [here](/docs/data-model/operations/queries#the-usequery-hook-1).
|
You can change the options for a **single** Query using the `options` object, as described [here](../data-model/operations/queries#the-usequery-hook-1).
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Wasp's `useQuery` hook uses `react-query`'s `useQuery` hook under the hood. Since `react-query` comes configured with aggressive but sane default options, you most likely won't have to change those defaults for all Queries.
|
Wasp's `useQuery` hook uses `react-query`'s `useQuery` hook under the hood. Since `react-query` comes configured with aggressive but sane default options, you most likely won't have to change those defaults for all Queries.
|
||||||
|
@ -85,7 +85,7 @@ Make sure to use the `.cjs` extension for these config files, if you name them w
|
|||||||
|
|
||||||
### Adding Tailwind Plugins
|
### Adding Tailwind Plugins
|
||||||
|
|
||||||
To add Tailwind plugins, add it to [dependencies](/docs/project/dependencies) in your `main.wasp` file and to the plugins list in your `tailwind.config.cjs` file:
|
To add Tailwind plugins, add it to [dependencies](../project/dependencies) in your `main.wasp` file and to the plugins list in your `tailwind.config.cjs` file:
|
||||||
|
|
||||||
```wasp title="./main.wasp" {4-5}
|
```wasp title="./main.wasp" {4-5}
|
||||||
app todoApp {
|
app todoApp {
|
||||||
|
@ -113,28 +113,28 @@ The rest of the fields are covered in dedicated sections of the docs:
|
|||||||
|
|
||||||
- `auth: dict`
|
- `auth: dict`
|
||||||
|
|
||||||
Authentication configuration. Read more in the [authentication section](/docs/auth/overview) of the docs.
|
Authentication configuration. Read more in the [authentication section](../auth/overview) of the docs.
|
||||||
|
|
||||||
- `client: dict`
|
- `client: dict`
|
||||||
|
|
||||||
Configuration for the client side of your app. Read more in the [client configuration section](/docs/project/client-config) of the docs.
|
Configuration for the client side of your app. Read more in the [client configuration section](../project/client-config) of the docs.
|
||||||
|
|
||||||
- `server: dict`
|
- `server: dict`
|
||||||
|
|
||||||
Configuration for the server side of your app. Read more in the [server configuration section](/docs/project/server-config) of the docs.
|
Configuration for the server side of your app. Read more in the [server configuration section](../project/server-config) of the docs.
|
||||||
|
|
||||||
- `db: dict`
|
- `db: dict`
|
||||||
|
|
||||||
Database configuration. Read more in the [database configuration section](/docs/data-model/backends) of the docs.
|
Database configuration. Read more in the [database configuration section](../data-model/backends) of the docs.
|
||||||
|
|
||||||
- `dependencies: [(string, string)]`
|
- `dependencies: [(string, string)]`
|
||||||
|
|
||||||
List of npm dependencies for your app. Read more in the [dependencies section](/docs/project/dependencies) of the docs.
|
List of npm dependencies for your app. Read more in the [dependencies section](../project/dependencies) of the docs.
|
||||||
|
|
||||||
- `emailSender: dict`
|
- `emailSender: dict`
|
||||||
|
|
||||||
Email sender configuration. Read more in the [email sending section](/docs/advanced/email) of the docs.
|
Email sender configuration. Read more in the [email sending section](../advanced/email) of the docs.
|
||||||
|
|
||||||
- `webSocket: dict`
|
- `webSocket: dict`
|
||||||
|
|
||||||
WebSocket configuration. Read more in the [WebSocket section](/docs/advanced/web-sockets) of the docs.
|
WebSocket configuration. Read more in the [WebSocket section](../advanced/web-sockets) of the docs.
|
||||||
|
@ -131,4 +131,4 @@ The way you provide env vars to your Wasp project in production depends on where
|
|||||||
flyctl secrets set SOME_VAR_NAME=somevalue
|
flyctl secrets set SOME_VAR_NAME=somevalue
|
||||||
```
|
```
|
||||||
|
|
||||||
You can read a lot more details in the [deployment section](/docs/advanced/deployment/manually) of the docs. We go into detail on how to define env vars for each deployment option.
|
You can read a lot more details in the [deployment section](../advanced/deployment/manually) of the docs. We go into detail on how to define env vars for each deployment option.
|
||||||
|
@ -90,7 +90,7 @@ function addCustomRoute(app: Application) {
|
|||||||
|
|
||||||
### Storing Some Values for Later Use
|
### Storing Some Values for Later Use
|
||||||
|
|
||||||
In case you want to store some values for later use, or to be accessed by the [Operations](/docs/data-model/operations/overview) you do that in the `setupFn` function.
|
In case you want to store some values for later use, or to be accessed by the [Operations](../data-model/operations/overview) you do that in the `setupFn` function.
|
||||||
|
|
||||||
Dummy example of such function and its usage:
|
Dummy example of such function and its usage:
|
||||||
|
|
||||||
@ -247,4 +247,4 @@ app MyApp {
|
|||||||
|
|
||||||
- #### `middlewareConfigFn: ServerImport`
|
- #### `middlewareConfigFn: ServerImport`
|
||||||
|
|
||||||
The import statement to an Express middleware config function. This is a global modification affecting all operations and APIs. See more in the [configuring middleware section](/docs/advanced/middleware-config#1-customize-global-middleware).
|
The import statement to an Express middleware config function. This is a global modification affecting all operations and APIs. See more in the [configuring middleware section](../advanced/middleware-config#1-customize-global-middleware).
|
||||||
|
@ -69,7 +69,7 @@ Wasp provides several functions to help you write React tests:
|
|||||||
const { mockQuery, mockApi } = mockServer();
|
const { mockQuery, mockApi } = mockServer();
|
||||||
```
|
```
|
||||||
|
|
||||||
- `mockQuery`: Takes a Wasp [query](/docs/data-model/operations/queries) to mock and the JSON data it should return.
|
- `mockQuery`: Takes a Wasp [query](../data-model/operations/queries) to mock and the JSON data it should return.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import getTasks from "@wasp/queries/getTasks";
|
import getTasks from "@wasp/queries/getTasks";
|
||||||
@ -81,7 +81,7 @@ Wasp provides several functions to help you write React tests:
|
|||||||
- Behind the scenes, Wasp uses [`msw`](https://npmjs.com/package/msw) to create a server request handle that responds with the specified data.
|
- Behind the scenes, Wasp uses [`msw`](https://npmjs.com/package/msw) to create a server request handle that responds with the specified data.
|
||||||
- Mock are cleared between each test.
|
- Mock are cleared between each test.
|
||||||
|
|
||||||
- `mockApi`: Similar to `mockQuery`, but for [APIs](/docs/advanced/apis). Instead of a Wasp query, it takes a route containing an HTTP method and a path.
|
- `mockApi`: Similar to `mockQuery`, but for [APIs](../advanced/apis). Instead of a Wasp query, it takes a route containing an HTTP method and a path.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import { HttpMethod } from "@wasp/types";
|
import { HttpMethod } from "@wasp/types";
|
||||||
|
@ -5,7 +5,7 @@ title: 1. Creating a New Project
|
|||||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
You'll need to have the latest version of Wasp installed locally to follow this tutorial. If you haven't installed it yet, check out the [QuickStart](/docs/quick-start) guide!
|
You'll need to have the latest version of Wasp installed locally to follow this tutorial. If you haven't installed it yet, check out the [QuickStart](../quick-start) guide!
|
||||||
:::
|
:::
|
||||||
|
|
||||||
In this section, we'll guide you through the process of creating a simple Todo app with Wasp. In the process, we'll take you through the most important and useful features of Wasp.
|
In this section, we'll guide you through the process of creating a simple Todo app with Wasp. In the process, we'll take you through the most important and useful features of Wasp.
|
||||||
|
@ -35,7 +35,7 @@ By _your code_, we mean the _"the code you write"_, as opposed to the code gener
|
|||||||
|
|
||||||
Many of the other files (`tsconfig.json`, `vite-env.d.ts`, etc.) are used by your IDE to improve your development experience with tools like autocompletion, intellisense, and error reporting.
|
Many of the other files (`tsconfig.json`, `vite-env.d.ts`, etc.) are used by your IDE to improve your development experience with tools like autocompletion, intellisense, and error reporting.
|
||||||
The file `vite.config.ts` is used to configure [Vite](https://vitejs.dev/guide/), Wasp's build tool of choice.
|
The file `vite.config.ts` is used to configure [Vite](https://vitejs.dev/guide/), Wasp's build tool of choice.
|
||||||
We won't be configuring Vite in this tutorial, so you can safely ignore the file. Still, if you ever end up wanting more control over Vite, you'll find everything you need to know in [custom Vite config docs](/docs/project/custom-vite-config.md).
|
We won't be configuring Vite in this tutorial, so you can safely ignore the file. Still, if you ever end up wanting more control over Vite, you'll find everything you need to know in [custom Vite config docs](../project/custom-vite-config.md).
|
||||||
|
|
||||||
:::note TypeScript Support
|
:::note TypeScript Support
|
||||||
Wasp supports TypeScript out of the box, but you are free to choose between or mix JavaScript and TypeScript as you see fit.
|
Wasp supports TypeScript out of the box, but you are free to choose between or mix JavaScript and TypeScript as you see fit.
|
||||||
|
@ -142,7 +142,7 @@ Now you can visit `/hello/johnny` and see "Here's johnny!"
|
|||||||
<ShowForTs>
|
<ShowForTs>
|
||||||
|
|
||||||
:::tip Type-safe links
|
:::tip Type-safe links
|
||||||
Since you are using Typescript, you can benefit from using Wasp's type-safe `Link` component and the `routes` object. Check out the [type-safe links docs](/docs/advanced/links) for more details.
|
Since you are using Typescript, you can benefit from using Wasp's type-safe `Link` component and the `routes` object. Check out the [type-safe links docs](../advanced/links) for more details.
|
||||||
:::
|
:::
|
||||||
</ShowForTs>
|
</ShowForTs>
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ psl=}
|
|||||||
:::note
|
:::note
|
||||||
Wasp uses [Prisma](https://www.prisma.io) as a way to talk to the database. You define entities by defining [Prisma models](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-schema/data-model/) using the Prisma Schema Language (PSL) between the `{=psl psl=}` tags.
|
Wasp uses [Prisma](https://www.prisma.io) as a way to talk to the database. You define entities by defining [Prisma models](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-schema/data-model/) using the Prisma Schema Language (PSL) between the `{=psl psl=}` tags.
|
||||||
|
|
||||||
Read more in the [Entities](/docs/data-model/entities) section of the docs.
|
Read more in the [Entities](../data-model/entities) section of the docs.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
To update the database schema to include this entity, stop the `wasp start` process, if its running, and run:
|
To update the database schema to include this entity, stop the `wasp start` process, if its running, and run:
|
||||||
|
@ -5,7 +5,7 @@ title: 5. Querying the Database
|
|||||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
import { ShowForTs, ShowForJs } from '@site/src/components/TsJsHelpers';
|
import { ShowForTs, ShowForJs } from '@site/src/components/TsJsHelpers';
|
||||||
|
|
||||||
We want to know which tasks we need to do, so let's list them! The primary way of interacting with entities in Wasp is by using [queries and actions](/docs/data-model/operations/overview), collectively known as _operations_.
|
We want to know which tasks we need to do, so let's list them! The primary way of interacting with entities in Wasp is by using [queries and actions](../data-model/operations/overview), collectively known as _operations_.
|
||||||
|
|
||||||
Queries are used to read an entity, while actions are used to create, modify, and delete entities. Since we want to list the tasks, we'll want to use a query.
|
Queries are used to read an entity, while actions are used to create, modify, and delete entities. Since we want to list the tasks, we'll want to use a query.
|
||||||
|
|
||||||
@ -225,14 +225,14 @@ Most of this code is regular React, the only exception being the <ShowForJs>two<
|
|||||||
<ShowForJs>
|
<ShowForJs>
|
||||||
|
|
||||||
- `import getTasks from '@wasp/queries/getTasks'` - Imports the client-side query function.
|
- `import getTasks from '@wasp/queries/getTasks'` - Imports the client-side query function.
|
||||||
- `import { useQuery } from '@wasp/queries'` - Imports Wasp's [useQuery](/docs/data-model/operations/queries#the-usequery-hook-1) React hook, which is based on [react-query](https://github.com/tannerlinsley/react-query)'s hook with the same name.
|
- `import { useQuery } from '@wasp/queries'` - Imports Wasp's [useQuery](../data-model/operations/queries#the-usequery-hook-1) React hook, which is based on [react-query](https://github.com/tannerlinsley/react-query)'s hook with the same name.
|
||||||
|
|
||||||
</ShowForJs>
|
</ShowForJs>
|
||||||
|
|
||||||
<ShowForTs>
|
<ShowForTs>
|
||||||
|
|
||||||
- `import getTasks from '@wasp/queries/getTasks'` - Imports the client-side query function.
|
- `import getTasks from '@wasp/queries/getTasks'` - Imports the client-side query function.
|
||||||
- `import { useQuery } from '@wasp/queries'` - Imports Wasp's [useQuery](/docs/data-model/operations/queries#the-usequery-hook-1) React hook, which is based on [react-query](https://github.com/tannerlinsley/react-query)'s hook with the same name.
|
- `import { useQuery } from '@wasp/queries'` - Imports Wasp's [useQuery](../data-model/operations/queries#the-usequery-hook-1) React hook, which is based on [react-query](https://github.com/tannerlinsley/react-query)'s hook with the same name.
|
||||||
- `import { Task } from '@wasp/entities'` - The type for the task entity we defined in `main.wasp`.
|
- `import { Task } from '@wasp/entities'` - The type for the task entity we defined in `main.wasp`.
|
||||||
|
|
||||||
Notice how you don't need to annotate the type of the query's return value: Wasp uses the types you defined while implementing the query for the generated client-side function. This is **full-stack type safety**: the types on the client always match the types on the server.
|
Notice how you don't need to annotate the type of the query's return value: Wasp uses the types you defined while implementing the query for the generated client-side function. This is **full-stack type safety**: the types on the client always match the types on the server.
|
||||||
|
@ -39,7 +39,7 @@ wasp db migrate-dev
|
|||||||
|
|
||||||
## Adding Auth to the Project
|
## Adding Auth to the Project
|
||||||
|
|
||||||
Next, we want to tell Wasp that we want to use full-stack [authentication](/docs/auth/overview) in our app:
|
Next, we want to tell Wasp that we want to use full-stack [authentication](../auth/overview) in our app:
|
||||||
|
|
||||||
```wasp {7-16} title="main.wasp"
|
```wasp {7-16} title="main.wasp"
|
||||||
app TodoApp {
|
app TodoApp {
|
||||||
@ -65,13 +65,13 @@ app TodoApp {
|
|||||||
|
|
||||||
By doing this, Wasp will create:
|
By doing this, Wasp will create:
|
||||||
|
|
||||||
- [Auth UI](/docs/auth/ui) with login and signup forms.
|
- [Auth UI](../auth/ui) with login and signup forms.
|
||||||
- A `logout()` action.
|
- A `logout()` action.
|
||||||
- A React hook `useAuth()`.
|
- A React hook `useAuth()`.
|
||||||
- `context.user` for use in Queries and Actions.
|
- `context.user` for use in Queries and Actions.
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
Wasp also supports authentication using [Google](/docs/auth/social-auth/google), [GitHub](/docs/auth/social-auth/github), and [email](/docs/auth/email), with more on the way!
|
Wasp also supports authentication using [Google](../auth/social-auth/google), [GitHub](../auth/social-auth/github), and [email](../auth/email), with more on the way!
|
||||||
:::
|
:::
|
||||||
|
|
||||||
## Adding Login and Signup Pages
|
## Adding Login and Signup Pages
|
||||||
@ -216,7 +216,7 @@ export default SignupPage
|
|||||||
<ShowForTs>
|
<ShowForTs>
|
||||||
|
|
||||||
:::tip Type-safe links
|
:::tip Type-safe links
|
||||||
Since you are using Typescript, you can benefit from using Wasp's type-safe `Link` component and the `routes` object. Check out the [type-safe links docs](/docs/advanced/links) for more details.
|
Since you are using Typescript, you can benefit from using Wasp's type-safe `Link` component and the `routes` object. Check out the [type-safe links docs](../advanced/links) for more details.
|
||||||
:::
|
:::
|
||||||
</ShowForTs>
|
</ShowForTs>
|
||||||
|
|
||||||
@ -515,8 +515,8 @@ You should be ready to learn about more complicated features and go more in-dept
|
|||||||
|
|
||||||
Looking for inspiration?
|
Looking for inspiration?
|
||||||
|
|
||||||
- Get a jump start on your next project with [Starter Templates](/docs/project/starter-templates)
|
- Get a jump start on your next project with [Starter Templates](../project/starter-templates)
|
||||||
- Make a real-time app with [Web Sockets](/docs/advanced/web-sockets)
|
- Make a real-time app with [Web Sockets](../advanced/web-sockets)
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
If you notice that some of the features you'd like to have are missing, or have any other kind of feedback, please write to us on [Discord](https://discord.gg/rzdnErX) or create an issue on [Github](https://github.com/wasp-lang/wasp), so we can learn which features to add/improve next 🙏
|
If you notice that some of the features you'd like to have are missing, or have any other kind of feedback, please write to us on [Discord](https://discord.gg/rzdnErX) or create an issue on [Github](https://github.com/wasp-lang/wasp), so we can learn which features to add/improve next 🙏
|
||||||
|
@ -1,521 +0,0 @@
|
|||||||
---
|
|
||||||
title: TypeScript Support
|
|
||||||
---
|
|
||||||
|
|
||||||
import OldDocsNote from '@site/docs/OldDocsNote'
|
|
||||||
|
|
||||||
# Using Wasp with TypeScript
|
|
||||||
|
|
||||||
<OldDocsNote />
|
|
||||||
|
|
||||||
TypeScript is a programming language that brings static type analysis to JavaScript. It is a superset of JavaScript (i.e., all valid JavaScript programs are valid TypeScript programs) and compiles to JavaScript before running. TypeScript's type system detects common errors at build time (reducing the chance of runtime errors in production) and enables type-based auto-completion in IDEs.
|
|
||||||
|
|
||||||
This document assumes you are familiar with TypeScript and primarily focuses on how to use it with Wasp. To learn more about TypeScript itself, we recommend reading [the official docs](https://www.typescriptlang.org/docs/).
|
|
||||||
|
|
||||||
The document also assumes a basic understanding of core Wasp features (e.g., Queries, Actions, Entities). You can read more about these features in [our feature docs](/docs/language/features).
|
|
||||||
|
|
||||||
Besides allowing you to write your code in TypeScript, Wasp also supports:
|
|
||||||
|
|
||||||
- Importing and using Wasp Entity types (on both the server and the client).
|
|
||||||
- Automatic full-stack type support for Queries and Actions - frontend types are automatically inferred from backend definitions.
|
|
||||||
- Type-safe generic hooks (`useQuery` and `useAction`) with the accompanying type inference.
|
|
||||||
- Type-safe optimistic update definitions.
|
|
||||||
|
|
||||||
We'll dig into the details of each feature in the following sections. But first, let's see how you can introduce TypeScript to an existing Wasp project.
|
|
||||||
|
|
||||||
:::info
|
|
||||||
To get the best IDE experience, make sure to leave `wasp start` running in the background. Wasp will track the working directory and ensure the generated code/types are up to date with your changes.
|
|
||||||
|
|
||||||
Your editor may sometimes report type and import errors even while `wasp start` is running. This happens when the TypeScript Language Server gets out of sync with the current code. If you're using VS Code, you can manually restart the language server by opening the command palette and selecting _"TypeScript: Restart TS Server."_
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Migrating your project to TypeScript
|
|
||||||
|
|
||||||
Wasp supports TypeScript out of the box!
|
|
||||||
|
|
||||||
Our scaffolding already includes TypeScript, so migrating your project to TypeScript is as simple as changing file extensions and using the language. This approach allows you to gradually migrate your project on a file-by-file basis.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
Let's first assume your Wasp file contains the following definitions:
|
|
||||||
|
|
||||||
```wasp title=main.wasp
|
|
||||||
entity Task {=psl
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
description String
|
|
||||||
isDone Boolean @default(false)
|
|
||||||
psl=}
|
|
||||||
|
|
||||||
query getTaskInfo {
|
|
||||||
fn: import { getTaskInfo } from "@server/queries.js",
|
|
||||||
entities: [Task]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Let's now assume that your `queries.js` file looks something like this:
|
|
||||||
|
|
||||||
```javascript title="src/server/queries.js"
|
|
||||||
import HttpError from "@wasp/core/HttpError.js"
|
|
||||||
|
|
||||||
function getInfoMessage(task) {
|
|
||||||
const isDoneText = task.isDone ? "is done" : "is not done"
|
|
||||||
return `Task '${task.description}' is ${isDoneText}.`
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getTaskInfo = async ({ id }, context) => {
|
|
||||||
const Task = context.entities.Task
|
|
||||||
const task = await Task.findUnique({ where: { id } })
|
|
||||||
if (!task) {
|
|
||||||
throw new HttpError(404)
|
|
||||||
}
|
|
||||||
return getInfoMessage(task)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
To migrate this file to TypeScript, all you have to do is:
|
|
||||||
|
|
||||||
1. Change the filename from `queries.js` to `queries.ts`.
|
|
||||||
2. Write some types.
|
|
||||||
|
|
||||||
Let's start by only providing a basic `getInfoMessage` function. We'll see how to properly type the rest of the file in the following sections.
|
|
||||||
|
|
||||||
```typescript title=src/server/queries.ts
|
|
||||||
import HttpError from "@wasp/core/HttpError.js"
|
|
||||||
|
|
||||||
// highlight-next-line
|
|
||||||
function getInfoMessage(task: {
|
|
||||||
isDone: boolean
|
|
||||||
description: string
|
|
||||||
}): string {
|
|
||||||
const isDoneText = task.isDone ? "is done" : "is not done"
|
|
||||||
return `Task '${task.description}' is ${isDoneText}.`
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getTaskInfo = async ({ id }, context) => {
|
|
||||||
const Task = context.entities.Task
|
|
||||||
const task = await Task.findUnique({ where: { id } })
|
|
||||||
if (!task) {
|
|
||||||
throw new HttpError(404)
|
|
||||||
}
|
|
||||||
return getInfoMessage(task)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You don't need to change anything inside the `.wasp` file.
|
|
||||||
:::caution
|
|
||||||
|
|
||||||
<!-- This block is mostly duplicated in 03-listing-tasks.md -->
|
|
||||||
|
|
||||||
Even when you use TypeScript, and your file is called `queries.ts`, you still need to import it using the `.js` extension:
|
|
||||||
|
|
||||||
```wasp
|
|
||||||
query getTaskInfo {
|
|
||||||
fn: import { getTaskInfo } from "@server/queries.js",
|
|
||||||
entities: [Task]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Wasp internally uses `esnext` module resolution, which always requires specifying the extension as `.js` (i.e., the extension used in the emitted JS file). This applies to all `@server` imports (and files on the server in general). This quirk does not apply to client files (the transpiler takes care of it).
|
|
||||||
|
|
||||||
Read more about ES modules in TypeScript [here](https://www.typescriptlang.org/docs/handbook/esm-node.html). If you're interested in the discussion and the reasoning behind this, read about it [in this GitHub issue](https://github.com/microsoft/TypeScript/issues/33588).
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Entity Types
|
|
||||||
|
|
||||||
Instead of manually specifying the types for `isDone` and `description`, we can get them from the `Task` entity type. Wasp will generate types for all entities and let you import them from `"@wasp/entities"`:
|
|
||||||
|
|
||||||
```typescript title=src/server/queries.ts
|
|
||||||
import HttpError from "@wasp/core/HttpError.js"
|
|
||||||
// highlight-next-line
|
|
||||||
import { Task } from "@wasp/entities"
|
|
||||||
|
|
||||||
// highlight-next-line
|
|
||||||
function getInfoMessage(task: Pick<Task, "isDone" | "description">): string {
|
|
||||||
const isDoneText = task.isDone ? "is done" : "is not done"
|
|
||||||
return `Task '${task.description}' is ${isDoneText}.`
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getTaskInfo = async ({ id }, context) => {
|
|
||||||
const Task = context.entities.Task
|
|
||||||
const task = await Task.findUnique({ where: { id } })
|
|
||||||
if (!task) {
|
|
||||||
throw new HttpError(404)
|
|
||||||
}
|
|
||||||
return getInfoMessage(task)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
By doing this, we've connected the argument type of the `getInfoMessage` function with the `Task` entity. This coupling removes duplication and ensures the function keeps the correct signature even if we change the entity. Of course, the function might throw type errors depending on how we change the entity, but that's precisely what we want!
|
|
||||||
|
|
||||||
Don't worry about typing the query function for now. We'll see how to handle this in the next section.
|
|
||||||
|
|
||||||
Entity types are also available on the client under the same import:
|
|
||||||
|
|
||||||
```tsx title=src/client/Main.jsx
|
|
||||||
import { Task } from "@wasp/entities"
|
|
||||||
|
|
||||||
export function ExamplePage() {}
|
|
||||||
const task: Task = {
|
|
||||||
id: 123,
|
|
||||||
description: "Some random task",
|
|
||||||
isDone: false,
|
|
||||||
}
|
|
||||||
return <div>{task.description}</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
The mentioned type safety mechanisms also apply here: changing the task entity in our `.wasp` file changes the imported type, which might throw a type error and warn us that our task definition is outdated.
|
|
||||||
|
|
||||||
## Backend type support for Queries and Actions
|
|
||||||
|
|
||||||
Wasp automatically generates the appropriate types for all Operations (i.e., Actions and Queries) you define inside your `.wasp` file. Assuming your `.wasp` file contains the following definition:
|
|
||||||
|
|
||||||
```wasp title=main.wasp
|
|
||||||
// ...
|
|
||||||
|
|
||||||
query GetTaskInfo {
|
|
||||||
fn: import { getTaskInfo } from "@server/queries.js",
|
|
||||||
entities: [Task]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Wasp will generate a type called `GetTaskInfo`, which you can use to type the Query's implementation. By assigning the `GetTaskInfo` type to your function, you get the type information for its context. In this case, TypeScript will know the `context.entities` object must include the `Task` entity. If the Query had auth enabled, it would also know that `context` includes user information.
|
|
||||||
|
|
||||||
`GetTaskInfo` can is a generic type that takes two (optional) type arguments:
|
|
||||||
|
|
||||||
1. `Input` - The argument (i.e., payload) received by the query function.
|
|
||||||
2. `Output` - The query function's return type.
|
|
||||||
|
|
||||||
Suppose you don't care about typing the Query's inputs and outputs. In that case, you can omit both type arguments, and TypeScript will infer the most general types (i.e., `never` for the input, `unknown` for the output.).
|
|
||||||
|
|
||||||
```typescript title=src/server/queries.ts
|
|
||||||
import HttpError from "@wasp/core/HttpError.js"
|
|
||||||
import { Task } from "@wasp/entities"
|
|
||||||
// highlight-next-line
|
|
||||||
import { GetTaskInfo } from "@wasp/queries/types"
|
|
||||||
|
|
||||||
function getInfoMessage(task: Pick<Task, "isDone" | "description">): string {
|
|
||||||
const isDoneText = task.isDone ? "is done" : "is not done"
|
|
||||||
return `Task '${task.description}' is ${isDoneText}.`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the type parameters to specify the Query's argument and return types.
|
|
||||||
// highlight-next-line
|
|
||||||
export const getTaskInfo: GetTaskInfo<Pick<Task, "id">, string> = async ({ id }, context) => {
|
|
||||||
// Thanks to the definition in your .wasp file, the compiler knows the type of
|
|
||||||
// `context` (and that it contains the `Task` entity).
|
|
||||||
const Task = context.entities.Task
|
|
||||||
|
|
||||||
// Thanks to the first type argument in `GetTaskInfo`, the compiler knows `args`
|
|
||||||
// is of type `Pick<Task, "id">`.
|
|
||||||
const task = await Task.findUnique({ where: { id } })
|
|
||||||
if (!task) {
|
|
||||||
throw new HttpError(404)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Thanks to the second type argument in `GetTaskInfo`, the compiler knows the
|
|
||||||
// function must return a value of type `string`.
|
|
||||||
return getInfoMessage(task)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
Everything described above applies to Actions as well.
|
|
||||||
:::tip
|
|
||||||
|
|
||||||
If don't want to define a new type for the Query's return value, the new `satisfies` keyword will allow TypeScript to infer it automatically:
|
|
||||||
```typescript
|
|
||||||
const getFoo = (async (_args, context) => {
|
|
||||||
const foos = await context.entities.Foo.findMany()
|
|
||||||
return {
|
|
||||||
foos,
|
|
||||||
message: "Here are some foos!",
|
|
||||||
queriedAt: new Date(),
|
|
||||||
}
|
|
||||||
}) satisfies GetFoo
|
|
||||||
```
|
|
||||||
From the snippet above, TypeScript knows:
|
|
||||||
1. The correct type for `context`.
|
|
||||||
2. The Query's return type is `{ foos: Foo[], message: string, queriedAt: Date }`.
|
|
||||||
|
|
||||||
If you don't need the context, you can skip specifying the Query's type (and arguments):
|
|
||||||
```typescript
|
|
||||||
const getFoo = () => {{ name: 'Foo', date: new Date() }}
|
|
||||||
```
|
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Frontend type support for Queries and Actions
|
|
||||||
|
|
||||||
Wasp supports automatic full-stack type safety à la tRPC. You only need to define the Operation's type on the backend, and the frontend will automatically know how to call it.
|
|
||||||
|
|
||||||
### Frontend type support for Queries
|
|
||||||
The examples assume you've defined the Query `getTaskInfo` from the previous sections:
|
|
||||||
|
|
||||||
```typescript title="src/server/queries.ts"
|
|
||||||
export const getTaskInfo: GetTaskInfo<Pick<Task, "id">, string> =
|
|
||||||
async ({ id }, context) => {
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Wasp will use the type of `getTaskInfo` to infer the Query's types on the frontend:
|
|
||||||
|
|
||||||
```tsx title="src/client/TaskInfo.tsx"
|
|
||||||
import { useQuery } from "@wasp/queries"
|
|
||||||
// Wasp knows the type of `getTaskInfo` thanks to your backend definition.
|
|
||||||
// highlight-next-line
|
|
||||||
import getTaskInfo from "@wasp/queries/getTaskInfo"
|
|
||||||
|
|
||||||
export const TaskInfo = () => {
|
|
||||||
const {
|
|
||||||
// TypeScript knows `taskInfo` is a `string | undefined` thanks to the
|
|
||||||
// backend definition.
|
|
||||||
data: taskInfo,
|
|
||||||
// TypeScript also knows `isError` is a `boolean`.
|
|
||||||
isError,
|
|
||||||
// TypeScript knows `error` is of type `Error`.
|
|
||||||
error,
|
|
||||||
// TypeScript knows `id` must be a `Task["id"]` (i.e., a number) thanks to
|
|
||||||
// your backend definition.
|
|
||||||
// highlight-next-line
|
|
||||||
} = useQuery(getTaskInfo, { id: 1 })
|
|
||||||
|
|
||||||
if (isError) {
|
|
||||||
return <div> Error during fetching tasks: {error.message || "unknown"}</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeScript forces you to perform this check.
|
|
||||||
return taskInfo === undefined ? (
|
|
||||||
<div>Waiting for info...</div>
|
|
||||||
) : (
|
|
||||||
<div>{taskInfo}</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Frontend type support for Actions
|
|
||||||
|
|
||||||
Assuming the following action definition in your `.wasp` file
|
|
||||||
|
|
||||||
```wasp title=main.wasp
|
|
||||||
action addTask {
|
|
||||||
fn: import { addTask } from "@server/actions.js"
|
|
||||||
entities: [Task]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
And its corresponding implementation in `src/server/actions.ts`:
|
|
||||||
|
|
||||||
```typescript title=src/server/actions.ts
|
|
||||||
import { AddTask } from "@wasp/actions/types"
|
|
||||||
|
|
||||||
type TaskPayload = Pick<Task, "description" | "isDone">
|
|
||||||
|
|
||||||
const addTask: AddTask<TaskPayload, Task> = async (args, context) => {
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Here's how to use it on the frontend:
|
|
||||||
```tsx title=src/client/AddTask.tsx
|
|
||||||
import { useAction } from "@wasp/actions"
|
|
||||||
// TypeScript knows `addTask` is a function that expects a value of type
|
|
||||||
// `TaskPayload` and returns a value of type `Promise<Task>`.
|
|
||||||
import addTask from "@wasp/queries/addTask"
|
|
||||||
|
|
||||||
const AddTask = ({ description }: Pick<Task, "description">) => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<button onClick={() => addTask({ description, isDone: false })}>
|
|
||||||
Add unfinished task
|
|
||||||
</button>
|
|
||||||
<button onClick={() => addTask({ description, isDone: true })}>
|
|
||||||
Add finished task
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
#### Type support for the `useAction` hook
|
|
||||||
Type inference also works if you decide to use the action via the `useAction` hook:
|
|
||||||
```typescript
|
|
||||||
// addTaskFn is of type (args: TaskPayload) => Task
|
|
||||||
const addTaskFn = useAction(addTask)
|
|
||||||
```
|
|
||||||
|
|
||||||
The `useAction` hook also includes support for optimistic updates. Read [the feature docs](/docs/language/features#the-useaction-hook) to understand more about optimistic updates and how to define them in Wasp.
|
|
||||||
|
|
||||||
Here's an example that shows how you can use static type checking in their definitions (the example assumes an appropriate action defined in the `.wasp` file and implemented on the server):
|
|
||||||
|
|
||||||
```tsx title=Task.tsx
|
|
||||||
import { useQuery } from "@wasp/queries"
|
|
||||||
import { OptimisticUpdateDefinition, useAction } from "@wasp/actions"
|
|
||||||
import updateTaskIsDone from "@wasp/actions/updateTaskIsDone"
|
|
||||||
|
|
||||||
type TaskPayload = Pick<Task, "id" | "isDone">
|
|
||||||
|
|
||||||
const Task = ({ taskId }: Pick<Task, "id">) => {
|
|
||||||
const updateTaskIsDoneOptimistically = useAction(
|
|
||||||
updateTaskIsDone,
|
|
||||||
{
|
|
||||||
optimisticUpdates: [
|
|
||||||
{
|
|
||||||
getQuerySpecifier: () => [getTask, { id: taskId }],
|
|
||||||
// This query's cache should should never be empty
|
|
||||||
updateQuery: ({ isDone }, oldTask) => ({ ...oldTask!, isDone }),
|
|
||||||
// highlight-next-line
|
|
||||||
} as OptimisticUpdateDefinition<TaskPayload, Task>,
|
|
||||||
{
|
|
||||||
getQuerySpecifier: () => [getTasks],
|
|
||||||
updateQuery: (updatedTask, oldTasks) =>
|
|
||||||
oldTasks &&
|
|
||||||
oldTasks.map((task) =>
|
|
||||||
task.id === updatedTask.id ? { ...task, ...updatedTask } : task
|
|
||||||
),
|
|
||||||
// highlight-next-line
|
|
||||||
} as OptimisticUpdateDefinition<TaskPayload, Task[]>,
|
|
||||||
],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Database seeding
|
|
||||||
|
|
||||||
When implementing a seed function in TypeScript, you can import a `DbSeedFn` type via
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import type { DbSeedFn } from "@wasp/dbSeed/types.js"
|
|
||||||
```
|
|
||||||
|
|
||||||
and use it to type your seed function like this:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
export const devSeedSimple: DbSeedFn = async (prismaClient) => { ... }
|
|
||||||
```
|
|
||||||
|
|
||||||
## CRUD operations on entities
|
|
||||||
|
|
||||||
For a specific [Entity](/docs/language/features#entity), you can tell Wasp to automatically instantiate server-side logic ([Queries](/docs/language/features#query) and [Actions](/docs/language/features#action)) for creating, reading, updating and deleting such entities.
|
|
||||||
|
|
||||||
Read more about CRUD operations in Wasp [here](/docs/language/features#crud-operations).
|
|
||||||
|
|
||||||
### Using types for CRUD operations overrides
|
|
||||||
|
|
||||||
If you writing the override implementation in Typescript, you'll have access to generated types. The overrides are functions that take the following arguments:
|
|
||||||
- `args` - The arguments of the operation i.e. the data that's sent from the client.
|
|
||||||
- `context` - Context containing the `user` making the request and the `entities` object containing the entity that's being operated on.
|
|
||||||
|
|
||||||
You can types for each of the functions you want to override from `@wasp/crud/{crud name}`. The types that are available are:
|
|
||||||
- `GetAllQuery`
|
|
||||||
- `GetQuery`
|
|
||||||
- `CreateAction`
|
|
||||||
- `UpdateAction`
|
|
||||||
- `DeleteAction`
|
|
||||||
|
|
||||||
If you have a CRUD named `Tasks`, you would import the types like this:
|
|
||||||
```ts
|
|
||||||
import type { GetAllQuery, GetQuery, CreateAction, UpdateAction, DeleteAction } from '@wasp/crud/Tasks'
|
|
||||||
|
|
||||||
// Each of the types is a generic type, so you can use it like this:
|
|
||||||
export const getAllOverride: GetAllQuery<Input, Output> = async (args, context) => {
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## WebSocket full-stack type support
|
|
||||||
|
|
||||||
|
|
||||||
Defining event names with the matching payload types on the server makes those types exposed automatically on the client. This helps you avoid mistakes when emitting events or handling them.
|
|
||||||
|
|
||||||
### Defining the events handler
|
|
||||||
On the server, you will get Socket.IO `io: Server` argument and `context` for your WebSocket function, which contains all entities you defined in your Wasp app. You can type the `webSocketFn` function like this:
|
|
||||||
|
|
||||||
```ts title=src/server/webSocket.ts
|
|
||||||
import type { WebSocketDefinition, WaspSocketData } from '@wasp/webSocket'
|
|
||||||
|
|
||||||
// Using the generic WebSocketDefinition type to define the WebSocket function.
|
|
||||||
type WebSocketFn = WebSocketDefinition<
|
|
||||||
ClientToServerEvents,
|
|
||||||
ServerToClientEvents,
|
|
||||||
InterServerEvents,
|
|
||||||
SocketData
|
|
||||||
>
|
|
||||||
|
|
||||||
interface ServerToClientEvents {
|
|
||||||
// The type for the payload of the "chatMessage" event.
|
|
||||||
chatMessage: (msg: { id: string, username: string, text: string }) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ClientToServerEvents {
|
|
||||||
// The type for the payload of the "chatMessage" event.
|
|
||||||
chatMessage: (msg: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface InterServerEvents {}
|
|
||||||
|
|
||||||
interface SocketData extends WaspSocketData {}
|
|
||||||
|
|
||||||
// Use the WebSocketFn to type the webSocketFn function.
|
|
||||||
export const webSocketFn: WebSocketFn = (io, context) => {
|
|
||||||
io.on('connection', (socket) => {
|
|
||||||
socket.on('chatMessage', async (msg) => {
|
|
||||||
io.emit('chatMessage', { ... })
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Using the WebSocket on the client
|
|
||||||
|
|
||||||
After you have defined the WebSocket function on the server, you can use it on the client. The `useSocket` hook will give you the `socket` instance and the `isConnected` boolean. The `socket` instance is typed with the types you defined on the server.
|
|
||||||
|
|
||||||
The `useSocketListener` hook will give you a type-safe event handler. The event name and its payload type are defined on the server.
|
|
||||||
|
|
||||||
You can additonally use the `ClientToServerPayload` and `ServerToClientPayload` helper types to get the payload type for a specific event.
|
|
||||||
|
|
||||||
```tsx title=src/client/ChatPage.tsx
|
|
||||||
import React, { useState } from 'react'
|
|
||||||
import {
|
|
||||||
useSocket,
|
|
||||||
useSocketListener,
|
|
||||||
ServerToClientPayload,
|
|
||||||
ClientToServerPayload,
|
|
||||||
} from '@wasp/webSocket'
|
|
||||||
|
|
||||||
export const ChatPage = () => {
|
|
||||||
const [messageText, setMessageText] = useState<
|
|
||||||
// We are using a helper type to get the payload type for the "chatMessage" event.
|
|
||||||
ClientToServerPayload<'chatMessage'>
|
|
||||||
>('')
|
|
||||||
|
|
||||||
const [messages, setMessages] = useState<
|
|
||||||
// We are using a helper type to get the payload type for the "chatMessage" event.
|
|
||||||
ServerToClientPayload<'chatMessage'>[]
|
|
||||||
>([])
|
|
||||||
|
|
||||||
// The "socket" instance is typed with the types you defined on the server.
|
|
||||||
const { socket, isConnected } = useSocket()
|
|
||||||
|
|
||||||
// This is a type-safe event handler: "chatMessage" event and its payload type
|
|
||||||
// are defined on the server.
|
|
||||||
useSocketListener('chatMessage', logMessage)
|
|
||||||
|
|
||||||
function logMessage(msg: ServerToClientPayload<'chatMessage'>) {
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
|
|
||||||
e.preventDefault()
|
|
||||||
// This is a type-safe event emitter: "chatMessage" event and its payload type
|
|
||||||
// are defined on the server.
|
|
||||||
socket.emit('chatMessage', messageText)
|
|
||||||
setMessageText('')
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
...
|
|
||||||
)
|
|
||||||
}
|
|
||||||
```
|
|
@ -105,11 +105,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
label: "Todo app tutorial",
|
label: "Todo app tutorial",
|
||||||
to: "docs/tutorial/create",
|
to: "docs/tutorial/create",
|
||||||
},
|
}
|
||||||
{
|
|
||||||
label: "Reference",
|
|
||||||
to: "docs/language/features",
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -6,8 +6,8 @@ module.exports = {
|
|||||||
collapsed: false,
|
collapsed: false,
|
||||||
collapsible: false,
|
collapsible: false,
|
||||||
items: [
|
items: [
|
||||||
'introduction/what-is-wasp',
|
'introduction/introduction',
|
||||||
'introduction/getting-started',
|
'introduction/quick-start',
|
||||||
'introduction/editor-setup',
|
'introduction/editor-setup',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
import Admonition from "@theme/Admonition";
|
|
||||||
import Link from "@docusaurus/Link";
|
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
export default function OldDocsNote() {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "sticky",
|
|
||||||
top: "calc(var(--ifm-navbar-height) + 1rem)",
|
|
||||||
zIndex: 1,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Admonition type="caution" title="Deprecated Page">
|
|
||||||
This page is part of a previous documentation version and is no longer
|
|
||||||
actively maintained. The content is likely out of date and may no longer
|
|
||||||
be relevant to current releases.
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
Go to the <Link to="/docs">current documentation</Link> for updated
|
|
||||||
content.
|
|
||||||
</Admonition>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -5,7 +5,7 @@ title: Custom HTTP API Endpoints
|
|||||||
import { ShowForTs, ShowForJs } from '@site/src/components/TsJsHelpers'
|
import { ShowForTs, ShowForJs } from '@site/src/components/TsJsHelpers'
|
||||||
import { Required } from '@site/src/components/Required'
|
import { Required } from '@site/src/components/Required'
|
||||||
|
|
||||||
In Wasp, the default client-server interaction mechanism is through [Operations](/docs/data-model/operations/overview). However, if you need a specific URL method/path, or a specific response, Operations may not be suitable for you. For these cases, you can use an `api`. Best of all, they should look and feel very familiar.
|
In Wasp, the default client-server interaction mechanism is through [Operations](../data-model/operations/overview). However, if you need a specific URL method/path, or a specific response, Operations may not be suitable for you. For these cases, you can use an `api`. Best of all, they should look and feel very familiar.
|
||||||
|
|
||||||
## How to Create an API
|
## How to Create an API
|
||||||
|
|
||||||
@ -231,11 +231,11 @@ export const apiMiddleware: MiddlewareConfigFn = (config) => {
|
|||||||
|
|
||||||
We are returning the default middleware which enables CORS for all APIs under the `/foo` path.
|
We are returning the default middleware which enables CORS for all APIs under the `/foo` path.
|
||||||
|
|
||||||
For more information about middleware configuration, please see: [Middleware Configuration](/docs/advanced/middleware-config)
|
For more information about middleware configuration, please see: [Middleware Configuration](../advanced/middleware-config)
|
||||||
|
|
||||||
## Using Entities in APIs
|
## Using Entities in APIs
|
||||||
|
|
||||||
In many cases, resources used in APIs will be [Entities](/docs/data-model/entities.md).
|
In many cases, resources used in APIs will be [Entities](../data-model/entities.md).
|
||||||
To use an Entity in your API, add it to the `api` declaration in Wasp:
|
To use an Entity in your API, add it to the `api` declaration in Wasp:
|
||||||
|
|
||||||
<Tabs groupId="js-ts">
|
<Tabs groupId="js-ts">
|
||||||
@ -340,4 +340,4 @@ The `api` declaration has the following fields:
|
|||||||
|
|
||||||
- `middlewareConfigFn: ServerImport`
|
- `middlewareConfigFn: ServerImport`
|
||||||
|
|
||||||
The import statement to an Express middleware config function for this API. See more in [middleware section](/docs/advanced/middleware-config) of the docs.
|
The import statement to an Express middleware config function for this API. See more in [middleware section](../advanced/middleware-config) of the docs.
|
@ -1,4 +1,4 @@
|
|||||||
:::tip Using an external auth method?
|
:::tip Using an external auth method?
|
||||||
|
|
||||||
If your app is using an external authentication method(s) supported by Wasp (such as [Google](/docs/auth/social-auth/google#4-adding-environment-variables) or [GitHub](/docs/auth/social-auth/github#4-adding-environment-variables)), make sure to set the necessary environment variables.
|
If your app is using an external authentication method(s) supported by Wasp (such as [Google](../../auth/social-auth/google#4-adding-environment-variables) or [GitHub](../../auth/social-auth/github#4-adding-environment-variables)), make sure to set the necessary environment variables.
|
||||||
:::
|
:::
|
||||||
|
@ -34,7 +34,7 @@ wasp build
|
|||||||
|
|
||||||
:::caution PostgreSQL in production
|
:::caution PostgreSQL in production
|
||||||
You won't be able to build the app if you are using SQLite as a database (which is the default database).
|
You won't be able to build the app if you are using SQLite as a database (which is the default database).
|
||||||
You'll have to [switch to PostgreSQL](/docs/data-model/backends#migrating-from-sqlite-to-postgresql) before deploying to production.
|
You'll have to [switch to PostgreSQL](../../data-model/backends#migrating-from-sqlite-to-postgresql) before deploying to production.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### 2. Deploying the API Server (backend)
|
### 2. Deploying the API Server (backend)
|
||||||
@ -92,7 +92,7 @@ We'll cover a few different deployment providers below:
|
|||||||
## Fly.io
|
## Fly.io
|
||||||
|
|
||||||
:::tip We automated this process for you
|
:::tip We automated this process for you
|
||||||
If you want to do all of the work below with one command, you can use the [Wasp CLI](/docs/advanced/deployment/cli#flyio).
|
If you want to do all of the work below with one command, you can use the [Wasp CLI](../../advanced/deployment/cli#flyio).
|
||||||
|
|
||||||
Wasp CLI deploys the server, deploys the client, and sets up a database.
|
Wasp CLI deploys the server, deploys the client, and sets up a database.
|
||||||
It also gives you a way to redeploy (update) your app with a single command.
|
It also gives you a way to redeploy (update) your app with a single command.
|
||||||
@ -547,7 +547,7 @@ heroku logs --tail --app <app-name>
|
|||||||
|
|
||||||
:::note Using `pg-boss` with Heroku
|
:::note Using `pg-boss` with Heroku
|
||||||
|
|
||||||
If you wish to deploy an app leveraging [Jobs](/docs/advanced/jobs) that use `pg-boss` as the executor to Heroku, you need to set an additional environment variable called `PG_BOSS_NEW_OPTIONS` to `{"connectionString":"<REGULAR_HEROKU_DATABASE_URL>","ssl":{"rejectUnauthorized":false}}`. This is because pg-boss uses the `pg` extension, which does not seem to connect to Heroku over SSL by default, which Heroku requires. Additionally, Heroku uses a self-signed cert, so we must handle that as well.
|
If you wish to deploy an app leveraging [Jobs](../../advanced/jobs) that use `pg-boss` as the executor to Heroku, you need to set an additional environment variable called `PG_BOSS_NEW_OPTIONS` to `{"connectionString":"<REGULAR_HEROKU_DATABASE_URL>","ssl":{"rejectUnauthorized":false}}`. This is because pg-boss uses the `pg` extension, which does not seem to connect to Heroku over SSL by default, which Heroku requires. Additionally, Heroku uses a self-signed cert, so we must handle that as well.
|
||||||
|
|
||||||
Read more: https://devcenter.heroku.com/articles/connecting-heroku-postgres#connecting-in-node-js
|
Read more: https://devcenter.heroku.com/articles/connecting-heroku-postgres#connecting-in-node-js
|
||||||
:::
|
:::
|
||||||
|
@ -11,7 +11,7 @@ Wasp apps are full-stack apps that consist of:
|
|||||||
|
|
||||||
You can deploy each part **anywhere** where you can usually deploy Node.js apps or static apps. For example, you can deploy your client on [Netlify](https://www.netlify.com/), the server on [Fly.io](https://fly.io/), and the database on [Neon](https://neon.tech/).
|
You can deploy each part **anywhere** where you can usually deploy Node.js apps or static apps. For example, you can deploy your client on [Netlify](https://www.netlify.com/), the server on [Fly.io](https://fly.io/), and the database on [Neon](https://neon.tech/).
|
||||||
|
|
||||||
To make deploying as smooth as possible, Wasp also offers a single-command deployment through the **Wasp CLI**. Read more about deploying through the CLI [here](/docs/advanced/deployment/cli).
|
To make deploying as smooth as possible, Wasp also offers a single-command deployment through the **Wasp CLI**. Read more about deploying through the CLI [here](../../advanced/deployment/cli).
|
||||||
|
|
||||||
<DeploymentOptionsGrid />
|
<DeploymentOptionsGrid />
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ Let's write an example Job that will print a message to the console and return a
|
|||||||
`MySpecialJob` is a generic type Wasp generates to help you correctly type the Job's worker function, ensuring type information about the function's arguments and return value. Read more about type-safe jobs in the [Javascript API section](#javascript-api).
|
`MySpecialJob` is a generic type Wasp generates to help you correctly type the Job's worker function, ensuring type information about the function's arguments and return value. Read more about type-safe jobs in the [Javascript API section](#javascript-api).
|
||||||
</ShowForTs>
|
</ShowForTs>
|
||||||
|
|
||||||
3. After successfully defining the job, you can submit work to be done in your [Operations](/docs/data-model/operations/overview) or [setupFn](/docs/project/server-config#setup-function) (or any other NodeJS code):
|
3. After successfully defining the job, you can submit work to be done in your [Operations](../data-model/operations/overview) or [setupFn](../project/server-config#setup-function) (or any other NodeJS code):
|
||||||
|
|
||||||
<Tabs groupId="js-ts">
|
<Tabs groupId="js-ts">
|
||||||
<TabItem value="js" label="JavaScript">
|
<TabItem value="js" label="JavaScript">
|
||||||
@ -333,7 +333,7 @@ The Job declaration has the following fields:
|
|||||||
|
|
||||||
- `entities: [Entity]`
|
- `entities: [Entity]`
|
||||||
|
|
||||||
A list of entities you wish to use inside your Job (similar to [Queries and Actions](/docs/data-model/operations/queries#using-entities-in-queries)).
|
A list of entities you wish to use inside your Job (similar to [Queries and Actions](../data-model/operations/queries#using-entities-in-queries)).
|
||||||
|
|
||||||
### JavaScript API
|
### JavaScript API
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ Wasp's Express server has the following middleware by default:
|
|||||||
- [express.json](https://expressjs.com/en/api.html#express.json) (which uses [body-parser](https://github.com/expressjs/body-parser#bodyparserjsonoptions)): parses incoming request bodies in a middleware before your handlers, making the result available under the `req.body` property.
|
- [express.json](https://expressjs.com/en/api.html#express.json) (which uses [body-parser](https://github.com/expressjs/body-parser#bodyparserjsonoptions)): parses incoming request bodies in a middleware before your handlers, making the result available under the `req.body` property.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
JSON middlware is required for [Operations](/docs/data-model/operations/overview) to function properly.
|
JSON middlware is required for [Operations](../data-model/operations/overview) to function properly.
|
||||||
:::
|
:::
|
||||||
- [express.urlencoded](https://expressjs.com/en/api.html#express.urlencoded) (which uses [body-parser](https://expressjs.com/en/resources/middleware/body-parser.html#bodyparserurlencodedoptions)): returns middleware that only parses urlencoded bodies and only looks at requests where the `Content-Type` header matches the type option.
|
- [express.urlencoded](https://expressjs.com/en/api.html#express.urlencoded) (which uses [body-parser](https://expressjs.com/en/resources/middleware/body-parser.html#bodyparserurlencodedoptions)): returns middleware that only parses urlencoded bodies and only looks at requests where the `Content-Type` header matches the type option.
|
||||||
- [cookieParser](https://github.com/expressjs/cookie-parser#readme): parses Cookie header and populates `req.cookies` with an object keyed by the cookie names.
|
- [cookieParser](https://github.com/expressjs/cookie-parser#readme): parses Cookie header and populates `req.cookies` with an object keyed by the cookie names.
|
||||||
|
@ -240,7 +240,7 @@ We'll define the React components for these pages in the `client/pages/auth.{jsx
|
|||||||
### 4. Create the Client Pages
|
### 4. Create the Client Pages
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](/docs/project/css-frameworks).
|
We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](../project/css-frameworks).
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Let's create a `auth.{jsx,tsx}` file in the `client/pages` folder and add the following to it:
|
Let's create a `auth.{jsx,tsx}` file in the `client/pages` folder and add the following to it:
|
||||||
@ -418,7 +418,7 @@ export function Layout({ children }: { children: React.ReactNode }) {
|
|||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
We imported the generated Auth UI components and used them in our pages. Read more about the Auth UI components [here](/docs/auth/ui).
|
We imported the generated Auth UI components and used them in our pages. Read more about the Auth UI components [here](../auth/ui).
|
||||||
|
|
||||||
### 5. Set up an Email Sender
|
### 5. Set up an Email Sender
|
||||||
|
|
||||||
@ -461,15 +461,15 @@ app myApp {
|
|||||||
SENDGRID_API_KEY=<your key>
|
SENDGRID_API_KEY=<your key>
|
||||||
```
|
```
|
||||||
|
|
||||||
If you are not sure how to get a SendGrid API key, read more [here](/docs/advanced/email#getting-the-api-key).
|
If you are not sure how to get a SendGrid API key, read more [here](../advanced/email#getting-the-api-key).
|
||||||
|
|
||||||
Read more about setting up email senders in the [sending emails docs](/docs/advanced/email).
|
Read more about setting up email senders in the [sending emails docs](../advanced/email).
|
||||||
|
|
||||||
### Conclusion
|
### Conclusion
|
||||||
|
|
||||||
That's it! We have set up email authentication in our app. 🎉
|
That's it! We have set up email authentication in our app. 🎉
|
||||||
|
|
||||||
Running `wasp db migrate-dev` and then `wasp start` should give you a working app with email authentication. If you want to put some of the pages behind authentication, read the [using auth docs](/docs/auth/overview).
|
Running `wasp db migrate-dev` and then `wasp start` should give you a working app with email authentication. If you want to put some of the pages behind authentication, read the [using auth docs](../auth/overview).
|
||||||
|
|
||||||
## Login and Signup Flows
|
## Login and Signup Flows
|
||||||
|
|
||||||
@ -500,7 +500,7 @@ Some of the behavior you get out of the box:
|
|||||||
|
|
||||||
4. Password validation
|
4. Password validation
|
||||||
|
|
||||||
Read more about the default password validation rules and how to override them in [using auth docs](/docs/auth/overview).
|
Read more about the default password validation rules and how to override them in [using auth docs](../auth/overview).
|
||||||
|
|
||||||
## Email Verification Flow
|
## Email Verification Flow
|
||||||
|
|
||||||
@ -597,7 +597,7 @@ The content of the e-mail can be customized, read more about it [here](#password
|
|||||||
|
|
||||||
## Using The Auth
|
## Using The Auth
|
||||||
|
|
||||||
To read more about how to set up the logout button and how to get access to the logged-in user in our client and server code, read the [using auth docs](/docs/auth/overview).
|
To read more about how to set up the logout button and how to get access to the logged-in user in our client and server code, read the [using auth docs](../auth/overview).
|
||||||
|
|
||||||
## API Reference
|
## API Reference
|
||||||
|
|
||||||
|
@ -78,11 +78,11 @@ Wasp supports the following auth methods:
|
|||||||
|
|
||||||
<AuthMethodsGrid />
|
<AuthMethodsGrid />
|
||||||
|
|
||||||
Let's say we enabled the [Username & password](/docs/auth/username-and-pass) authentication.
|
Let's say we enabled the [Username & password](../auth/username-and-pass) authentication.
|
||||||
|
|
||||||
We get an auth backend with signup and login endpoints. We also get the `user` object in our [Operations](/docs/data-model/operations/overview) and we can decide what to do based on whether the user is logged in or not.
|
We get an auth backend with signup and login endpoints. We also get the `user` object in our [Operations](../data-model/operations/overview) and we can decide what to do based on whether the user is logged in or not.
|
||||||
|
|
||||||
We would also get the [Auth UI](/docs/auth/ui) generated for us. We can set up our login and signup pages where our users can **create their account** and **login**. We can then protect certain pages by setting `authRequired: true` for them. This will make sure that only logged-in users can access them.
|
We would also get the [Auth UI](../auth/ui) generated for us. We can set up our login and signup pages where our users can **create their account** and **login**. We can then protect certain pages by setting `authRequired: true` for them. This will make sure that only logged-in users can access them.
|
||||||
|
|
||||||
We will also have access to the `user` object in our frontend code, so we can show different UI to logged-in and logged-out users. For example, we can show the user's name in the header alongside a **logout button** or a login button if the user is not logged in.
|
We will also have access to the `user` object in our frontend code, so we can show different UI to logged-in and logged-out users. For example, we can show the user's name in the header alongside a **logout button** or a login button if the user is not logged in.
|
||||||
|
|
||||||
@ -301,7 +301,7 @@ Since the `user` prop is only available in a page's React component: use the `us
|
|||||||
|
|
||||||
#### Using the `context.user` object
|
#### Using the `context.user` object
|
||||||
|
|
||||||
When authentication is enabled, all [queries and actions](/docs/data-model/operations/overview) have access to the `user` object through the `context` argument. `context.user` contains all User entity's fields, except for the password.
|
When authentication is enabled, all [queries and actions](../data-model/operations/overview) have access to the `user` object through the `context` argument. `context.user` contains all User entity's fields, except for the password.
|
||||||
|
|
||||||
<Tabs groupId="js-ts">
|
<Tabs groupId="js-ts">
|
||||||
<TabItem value="js" label="JavaScript">
|
<TabItem value="js" label="JavaScript">
|
||||||
@ -361,7 +361,7 @@ export const createTask: CreateTask<CreateTaskPayload, Task> = async (
|
|||||||
|
|
||||||
To implement access control in your app, each operation must check `context.user` and decide what to do. For example, if `context.user` is `undefined` inside a private operation, the user's access should be denied.
|
To implement access control in your app, each operation must check `context.user` and decide what to do. For example, if `context.user` is `undefined` inside a private operation, the user's access should be denied.
|
||||||
|
|
||||||
When using WebSockets, the `user` object is also available on the `socket.data` object. Read more in the [WebSockets section](/docs/advanced/web-sockets#websocketfn-function).
|
When using WebSockets, the `user` object is also available on the `socket.data` object. Read more in the [WebSockets section](../advanced/web-sockets#websocketfn-function).
|
||||||
|
|
||||||
## User entity
|
## User entity
|
||||||
|
|
||||||
@ -419,7 +419,7 @@ Default validations depend on the auth method you use.
|
|||||||
|
|
||||||
#### Username & password
|
#### Username & password
|
||||||
|
|
||||||
If you use [Username & password](/docs/auth/username-and-pass) authentication, the default validations are:
|
If you use [Username & password](../auth/username-and-pass) authentication, the default validations are:
|
||||||
|
|
||||||
- The `username` must not be empty
|
- The `username` must not be empty
|
||||||
- The `password` must not be empty, have at least 8 characters, and contain a number
|
- The `password` must not be empty, have at least 8 characters, and contain a number
|
||||||
@ -428,7 +428,7 @@ Note that `username`s are stored in a **case-sensitive** manner.
|
|||||||
|
|
||||||
#### Email
|
#### Email
|
||||||
|
|
||||||
If you use [Email](/docs/auth/email) authentication, the default validations are:
|
If you use [Email](../auth/email) authentication, the default validations are:
|
||||||
|
|
||||||
- The `email` must not be empty and a valid email address
|
- The `email` must not be empty and a valid email address
|
||||||
- The `password` must not be empty, have at least 8 characters, and contain a number
|
- The `password` must not be empty, have at least 8 characters, and contain a number
|
||||||
@ -726,7 +726,7 @@ Now that we defined the fields, Wasp knows how to:
|
|||||||
1. Validate the data sent from the client
|
1. Validate the data sent from the client
|
||||||
2. Save the data to the database
|
2. Save the data to the database
|
||||||
|
|
||||||
Next, let's see how to customize [Auth UI](/docs/auth/ui) to include those fields.
|
Next, let's see how to customize [Auth UI](../auth/ui) to include those fields.
|
||||||
|
|
||||||
### 2. Customizing the Signup Component
|
### 2. Customizing the Signup Component
|
||||||
|
|
||||||
@ -736,8 +736,8 @@ If you are not using Wasp's Auth UI, you can skip this section. Just make sure t
|
|||||||
|
|
||||||
Read more about using the signup actions for:
|
Read more about using the signup actions for:
|
||||||
|
|
||||||
- email auth [here](/docs/auth/email#fields-in-the-email-dict) <!-- TODO: these docs are not great at explaining using signup and login actions: https://github.com/wasp-lang/wasp/issues/1438 -->
|
- email auth [here](../auth/email#fields-in-the-email-dict) <!-- TODO: these docs are not great at explaining using signup and login actions: https://github.com/wasp-lang/wasp/issues/1438 -->
|
||||||
- username & password auth [here](/docs/auth/username-and-pass#customizing-the-auth-flow)
|
- username & password auth [here](../auth/username-and-pass#customizing-the-auth-flow)
|
||||||
:::
|
:::
|
||||||
|
|
||||||
If you are using Wasp's Auth UI, you can customize the `SignupForm` component by passing the `additionalFields` prop to it. It can be either a list of extra fields or a render function.
|
If you are using Wasp's Auth UI, you can customize the `SignupForm` component by passing the `additionalFields` prop to it. It can be either a list of extra fields or a render function.
|
||||||
@ -1046,7 +1046,7 @@ psl=}
|
|||||||
The same `externalAuthEntity` can be used across different social login providers (e.g., both GitHub and Google can use the same entity).
|
The same `externalAuthEntity` can be used across different social login providers (e.g., both GitHub and Google can use the same entity).
|
||||||
:::
|
:::
|
||||||
|
|
||||||
See [Google docs](/docs/auth/social-auth/google) and [GitHub docs](/docs/auth/social-auth/github) for more details.
|
See [Google docs](../auth/social-auth/google) and [GitHub docs](../auth/social-auth/github) for more details.
|
||||||
|
|
||||||
#### `methods: dict` <Required />
|
#### `methods: dict` <Required />
|
||||||
|
|
||||||
@ -1057,7 +1057,7 @@ A dictionary of auth methods enabled for the app.
|
|||||||
#### `onAuthFailedRedirectTo: String` <Required />
|
#### `onAuthFailedRedirectTo: String` <Required />
|
||||||
|
|
||||||
The route to which Wasp should redirect unauthenticated user when they try to access a private page (i.e., a page that has `authRequired: true`).
|
The route to which Wasp should redirect unauthenticated user when they try to access a private page (i.e., a page that has `authRequired: true`).
|
||||||
Check out these [essentials docs on auth](/docs/tutorial/auth#adding-auth-to-the-project) to see an example of usage.
|
Check out these [essentials docs on auth](../tutorial/auth#adding-auth-to-the-project) to see an example of usage.
|
||||||
|
|
||||||
#### `onAuthSucceededRedirectTo: String`
|
#### `onAuthSucceededRedirectTo: String`
|
||||||
|
|
||||||
@ -1065,7 +1065,7 @@ The route to which Wasp will send a successfully authenticated after a successfu
|
|||||||
The default value is `"/"`.
|
The default value is `"/"`.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
Automatic redirect on successful login only works when using the Wasp-provided [Auth UI](/docs/auth/ui).
|
Automatic redirect on successful login only works when using the Wasp-provided [Auth UI](../auth/ui).
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### `signup: SignupOptions`
|
#### `signup: SignupOptions`
|
||||||
|
@ -5,6 +5,6 @@ Provider-specific behavior comes down to implementing two functions.
|
|||||||
|
|
||||||
The reference shows how to define both.
|
The reference shows how to define both.
|
||||||
|
|
||||||
For behavior common to all providers, check the general [API Reference](/docs/auth/overview.md#api-reference).
|
For behavior common to all providers, check the general [API Reference](../../auth/overview.md#api-reference).
|
||||||
|
|
||||||
<!-- This snippet is used in google.md and github.md -->
|
<!-- This snippet is used in google.md and github.md -->
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
To read more about how to set up the logout button and get access to the logged-in user in both client and server code, read the docs on [using auth](/docs/auth/overview).
|
To read more about how to set up the logout button and get access to the logged-in user in both client and server code, read the docs on [using auth](../../auth/overview).
|
||||||
|
|
||||||
<!-- This snippet is used in google.md and github.md -->
|
<!-- This snippet is used in google.md and github.md -->
|
||||||
|
@ -159,7 +159,7 @@ psl=}
|
|||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
`externalAuthEntity` and `userEntity` are explained in [the social auth overview](/docs/auth/social-auth/overview#social-login-entity).
|
`externalAuthEntity` and `userEntity` are explained in [the social auth overview](../../auth/social-auth/overview#social-login-entity).
|
||||||
|
|
||||||
### 3. Creating a GitHub OAuth App
|
### 3. Creating a GitHub OAuth App
|
||||||
|
|
||||||
@ -231,7 +231,7 @@ We'll define the React components for these pages in the `client/pages/auth.{jsx
|
|||||||
### 6. Creating the Client Pages
|
### 6. Creating the Client Pages
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](/docs/project/css-frameworks).
|
We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](../../project/css-frameworks).
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Let's create a `auth.{jsx,tsx}` file in the `client/pages` folder and add the following to it:
|
Let's create a `auth.{jsx,tsx}` file in the `client/pages` folder and add the following to it:
|
||||||
@ -295,7 +295,7 @@ export function Layout({ children }: { children: React.ReactNode }) {
|
|||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
We imported the generated Auth UI component and used them in our pages. Read more about the Auth UI components [here](/docs/auth/ui).
|
We imported the generated Auth UI component and used them in our pages. Read more about the Auth UI components [here](../../auth/ui).
|
||||||
|
|
||||||
### Conclusion
|
### Conclusion
|
||||||
|
|
||||||
@ -304,7 +304,7 @@ Yay, we've successfully set up Github Auth! 🎉
|
|||||||
![Github Auth](/img/auth/github.png)
|
![Github Auth](/img/auth/github.png)
|
||||||
|
|
||||||
Running `wasp db migrate-dev` and `wasp start` should now give you a working app with authentication.
|
Running `wasp db migrate-dev` and `wasp start` should now give you a working app with authentication.
|
||||||
To see how to protect specific pages (i.e., hide them from non-authenticated users), read the docs on [using auth](/docs/auth/overview).
|
To see how to protect specific pages (i.e., hide them from non-authenticated users), read the docs on [using auth](../../auth/overview).
|
||||||
|
|
||||||
## Default Behaviour
|
## Default Behaviour
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ app myApp {
|
|||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
`externalAuthEntity` and `userEntity` are explained in [the social auth overview](/docs/auth/social-auth/overview#social-login-entity).
|
`externalAuthEntity` and `userEntity` are explained in [the social auth overview](../../auth/social-auth/overview#social-login-entity).
|
||||||
|
|
||||||
### 2. Adding the Entities
|
### 2. Adding the Entities
|
||||||
|
|
||||||
@ -271,7 +271,7 @@ We'll define the React components for these pages in the `client/pages/auth.{jsx
|
|||||||
### 6. Create the Client Pages
|
### 6. Create the Client Pages
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](/docs/project/css-frameworks).
|
We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](../../project/css-frameworks).
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Let's now create a `auth.{jsx,tsx}` file in the `client/pages`.
|
Let's now create a `auth.{jsx,tsx}` file in the `client/pages`.
|
||||||
@ -337,7 +337,7 @@ export function Layout({ children }: { children: React.ReactNode }) {
|
|||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
:::info Auth UI
|
:::info Auth UI
|
||||||
Our pages use an automatically-generated Auth UI component. Read more about Auth UI components [here](/docs/auth/ui).
|
Our pages use an automatically-generated Auth UI component. Read more about Auth UI components [here](../../auth/ui).
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### Conclusion
|
### Conclusion
|
||||||
@ -347,7 +347,7 @@ Yay, we've successfully set up Google Auth! 🎉
|
|||||||
![Google Auth](/img/auth/google.png)
|
![Google Auth](/img/auth/google.png)
|
||||||
|
|
||||||
Running `wasp db migrate-dev` and `wasp start` should now give you a working app with authentication.
|
Running `wasp db migrate-dev` and `wasp start` should now give you a working app with authentication.
|
||||||
To see how to protect specific pages (i.e., hide them from non-authenticated users), read the docs on [using auth](/docs/auth/overview).
|
To see how to protect specific pages (i.e., hide them from non-authenticated users), read the docs on [using auth](../../auth/overview).
|
||||||
|
|
||||||
## Default Behaviour
|
## Default Behaviour
|
||||||
|
|
||||||
|
@ -258,7 +258,7 @@ export const getUserFields: GetUserFieldsFn = async (_context, _args) => {
|
|||||||
|
|
||||||
#### 3. Showing the Correct State on the Client
|
#### 3. Showing the Correct State on the Client
|
||||||
|
|
||||||
You can query the user's `isSignupComplete` flag on the client with the [`useAuth()`](/docs/auth/overview) hook.
|
You can query the user's `isSignupComplete` flag on the client with the [`useAuth()`](../../auth/overview) hook.
|
||||||
Depending on the flag's value, you can redirect users to the appropriate signup step.
|
Depending on the flag's value, you can redirect users to the appropriate signup step.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
@ -317,7 +317,7 @@ Each provider has their own rules for defining the `getUserFieldsFn` and `config
|
|||||||
## UI Helpers
|
## UI Helpers
|
||||||
|
|
||||||
:::tip Use Auth UI
|
:::tip Use Auth UI
|
||||||
[Auth UI](/docs/auth/ui) is a common name for all high-level auth forms that come with Wasp.
|
[Auth UI](../../auth/ui) is a common name for all high-level auth forms that come with Wasp.
|
||||||
|
|
||||||
These include fully functional auto-generated login and signup forms with working social login buttons.
|
These include fully functional auto-generated login and signup forms with working social login buttons.
|
||||||
If you're looking for the fastest way to get your auth up and running, that's where you should look.
|
If you're looking for the fastest way to get your auth up and running, that's where you should look.
|
||||||
|
@ -218,7 +218,7 @@ export function SignupPage() {
|
|||||||
|
|
||||||
It will automatically show the correct authentication providers based on your `main.wasp` file.
|
It will automatically show the correct authentication providers based on your `main.wasp` file.
|
||||||
|
|
||||||
Read more about customizing the signup process like adding additional fields or extra UI in the [Using Auth](/docs/auth/overview#customizing-the-signup-process) section.
|
Read more about customizing the signup process like adding additional fields or extra UI in the [Using Auth](../auth/overview#customizing-the-signup-process) section.
|
||||||
|
|
||||||
### Forgot Password Form
|
### Forgot Password Form
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ We'll define the React components for these pages in the `client/pages/auth.{jsx
|
|||||||
### 4. Create the Client Pages
|
### 4. Create the Client Pages
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](/docs/project/css-frameworks).
|
We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](../project/css-frameworks).
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Let's create a `auth.{jsx,tsx}` file in the `client/pages` folder and add the following to it:
|
Let's create a `auth.{jsx,tsx}` file in the `client/pages` folder and add the following to it:
|
||||||
@ -255,19 +255,19 @@ export function Layout({ children }: { children: React.ReactNode }) {
|
|||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
We imported the generated Auth UI components and used them in our pages. Read more about the Auth UI components [here](/docs/auth/ui).
|
We imported the generated Auth UI components and used them in our pages. Read more about the Auth UI components [here](../auth/ui).
|
||||||
|
|
||||||
### Conclusion
|
### Conclusion
|
||||||
|
|
||||||
That's it! We have set up username authentication in our app. 🎉
|
That's it! We have set up username authentication in our app. 🎉
|
||||||
|
|
||||||
Running `wasp db migrate-dev` and then `wasp start` should give you a working app with username authentication. If you want to put some of the pages behind authentication, read the [using auth docs](/docs/auth/overview).
|
Running `wasp db migrate-dev` and then `wasp start` should give you a working app with username authentication. If you want to put some of the pages behind authentication, read the [using auth docs](../auth/overview).
|
||||||
|
|
||||||
## Customizing the Auth Flow
|
## Customizing the Auth Flow
|
||||||
|
|
||||||
The login and signup flows are pretty standard: they allow the user to sign up and then log in with their username and password. The signup flow validates the username and password and then creates a new user entity in the database.
|
The login and signup flows are pretty standard: they allow the user to sign up and then log in with their username and password. The signup flow validates the username and password and then creates a new user entity in the database.
|
||||||
|
|
||||||
Read more about the default username and password validation rules and how to override them in the [using auth docs](/docs/auth/overview).
|
Read more about the default username and password validation rules and how to override them in the [using auth docs](../auth/overview).
|
||||||
|
|
||||||
If you require more control in your authentication flow, you can achieve that in the following ways:
|
If you require more control in your authentication flow, you can achieve that in the following ways:
|
||||||
1. Create your UI and use `signup` and `login` actions.
|
1. Create your UI and use `signup` and `login` actions.
|
||||||
@ -538,7 +538,7 @@ export const signUp: SignupUser<SignupPayload, User> = async (args, context) =>
|
|||||||
|
|
||||||
## Using Auth
|
## Using Auth
|
||||||
|
|
||||||
To read more about how to set up the logout button and how to get access to the logged-in user in our client and server code, read the [using auth docs](/docs/auth/overview).
|
To read more about how to set up the logout button and how to get access to the logged-in user in our client and server code, read the [using auth docs](../auth/overview).
|
||||||
|
|
||||||
## API Reference
|
## API Reference
|
||||||
|
|
||||||
@ -649,4 +649,4 @@ app myApp {
|
|||||||
`usernameAndPassword` dict doesn't have any options at the moment.
|
`usernameAndPassword` dict doesn't have any options at the moment.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
You can read about the rest of the `auth` options in the [using auth](/docs/auth/overview) section of the docs.
|
You can read about the rest of the `auth` options in the [using auth](../auth/overview) section of the docs.
|
||||||
|
@ -4,7 +4,7 @@ title: Databases
|
|||||||
|
|
||||||
import { Required } from '@site/src/components/Required'
|
import { Required } from '@site/src/components/Required'
|
||||||
|
|
||||||
[Entities](/docs/data-model/entities.md), [Operations](/docs/data-model/operations/overview) and [Automatic CRUD](/docs/data-model/crud.md) together make a high-level interface for working with your app's data. Still, all that data has to live somewhere, so let's see how Wasp deals with databases.
|
[Entities](../data-model/entities.md), [Operations](../data-model/operations/overview) and [Automatic CRUD](../data-model/crud.md) together make a high-level interface for working with your app's data. Still, all that data has to live somewhere, so let's see how Wasp deals with databases.
|
||||||
|
|
||||||
## Supported Database Backends
|
## Supported Database Backends
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ Also, make sure that:
|
|||||||
|
|
||||||
If you want to spin up your own dev database (or connect to an external one), you can tell Wasp about it using the `DATABASE_URL` environment variable. Wasp will use the value of `DATABASE_URL` as a connection string.
|
If you want to spin up your own dev database (or connect to an external one), you can tell Wasp about it using the `DATABASE_URL` environment variable. Wasp will use the value of `DATABASE_URL` as a connection string.
|
||||||
|
|
||||||
The easiest way to set the necessary `DATABASE_URL` environment variable is by adding it to the [.env.server](/docs/project/env-vars) file in the root dir of your Wasp project (if that file doesn't yet exist, create it).
|
The easiest way to set the necessary `DATABASE_URL` environment variable is by adding it to the [.env.server](../project/env-vars) file in the root dir of your Wasp project (if that file doesn't yet exist, create it).
|
||||||
|
|
||||||
Alternatively, you can set it inline when running `wasp` (this applies to all environment variables):
|
Alternatively, you can set it inline when running `wasp` (this applies to all environment variables):
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ If you have a lot of experience writing full-stack apps, you probably ended up d
|
|||||||
|
|
||||||
Wasp makes handling these boring bits easy by offering a higher-level concept called Automatic CRUD.
|
Wasp makes handling these boring bits easy by offering a higher-level concept called Automatic CRUD.
|
||||||
|
|
||||||
With a single declaration, you can tell Wasp to automatically generate server-side logic (i.e., Queries and Actions) for creating, reading, updating and deleting [Entities](/docs/data-model/entities). As you update definitions for your Entities, Wasp automatically regenerates the backend logic.
|
With a single declaration, you can tell Wasp to automatically generate server-side logic (i.e., Queries and Actions) for creating, reading, updating and deleting [Entities](../data-model/entities). As you update definitions for your Entities, Wasp automatically regenerates the backend logic.
|
||||||
|
|
||||||
:::caution Early preview
|
:::caution Early preview
|
||||||
This feature is currently in early preview and we are actively working on it. Read more about [our plans](#future-of-crud-operations-in-wasp) for CRUD operations.
|
This feature is currently in early preview and we are actively working on it. Read more about [our plans](#future-of-crud-operations-in-wasp) for CRUD operations.
|
||||||
@ -62,7 +62,7 @@ Keep reading for an example of Automatic CRUD in action, or skip ahead for the [
|
|||||||
|
|
||||||
## Example: A Simple TODO App
|
## Example: A Simple TODO App
|
||||||
|
|
||||||
Let's create a full-app example that uses automatic CRUD. We'll stick to using the `Task` entity from the previous example, but we'll add a `User` entity and enable [username and password](/docs/auth/username-and-pass) based auth.
|
Let's create a full-app example that uses automatic CRUD. We'll stick to using the `Task` entity from the previous example, but we'll add a `User` entity and enable [username and password](../auth/username-and-pass) based auth.
|
||||||
|
|
||||||
<ImgWithCaption alt="Automatic CRUD with Wasp" source="img/crud-guide.gif" caption="We are building a simple tasks app with username based auth"/>
|
<ImgWithCaption alt="Automatic CRUD with Wasp" source="img/crud-guide.gif" caption="We are building a simple tasks app with username based auth"/>
|
||||||
|
|
||||||
@ -328,7 +328,7 @@ export const MainPage = () => {
|
|||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
And here are the login and signup pages, where we are using Wasp's [Auth UI](/docs/auth/ui) components:
|
And here are the login and signup pages, where we are using Wasp's [Auth UI](../auth/ui) components:
|
||||||
|
|
||||||
<Tabs groupId="js-ts">
|
<Tabs groupId="js-ts">
|
||||||
<TabItem value="js" label="JavaScript">
|
<TabItem value="js" label="JavaScript">
|
||||||
@ -692,7 +692,7 @@ export const getAllOverride: GetAllQuery<Input, Output> = async (
|
|||||||
|
|
||||||
</ShowForTs>
|
</ShowForTs>
|
||||||
|
|
||||||
For a usage example, check the [example guide](/docs/data-model/crud#adding-crud-to-the-task-entity-).
|
For a usage example, check the [example guide](../data-model/crud#adding-crud-to-the-task-entity-).
|
||||||
|
|
||||||
#### Using the CRUD operations in client code
|
#### Using the CRUD operations in client code
|
||||||
|
|
||||||
@ -742,7 +742,7 @@ const deleteAction = Tasks.delete.useAction()
|
|||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
All CRUD operations are implemented with [Queries and Actions](/docs/data-model/operations/overview) under the hood, which means they come with all the features you'd expect (e.g., automatic SuperJSON serialization, full-stack type safety when using TypeScript)
|
All CRUD operations are implemented with [Queries and Actions](../data-model/operations/overview) under the hood, which means they come with all the features you'd expect (e.g., automatic SuperJSON serialization, full-stack type safety when using TypeScript)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -62,11 +62,11 @@ Let's see how you can define and work with Wasp Entities:
|
|||||||
1. Create/update some Entities in your `.wasp` file.
|
1. Create/update some Entities in your `.wasp` file.
|
||||||
2. Run `wasp db migrate-dev`. This command syncs the database model with the Entity definitions in your `.wasp` file. It does this by creating migration scripts.
|
2. Run `wasp db migrate-dev`. This command syncs the database model with the Entity definitions in your `.wasp` file. It does this by creating migration scripts.
|
||||||
3. Migration scripts are automatically placed in the `migrations/` folder. Make sure to commit this folder into version control.
|
3. Migration scripts are automatically placed in the `migrations/` folder. Make sure to commit this folder into version control.
|
||||||
4. Use Wasp's JavasScript API to work with the database when implementing Operations (we'll cover this in detail when we talk about [operations](/docs/data-model/operations/overview)).
|
4. Use Wasp's JavasScript API to work with the database when implementing Operations (we'll cover this in detail when we talk about [operations](../data-model/operations/overview)).
|
||||||
|
|
||||||
#### Using Entities in Operations
|
#### Using Entities in Operations
|
||||||
|
|
||||||
Most of the time, you will be working with Entities within the context of [Operations (Queries & Actions)](/docs/data-model/operations/overview). We'll see how that's done on the next page.
|
Most of the time, you will be working with Entities within the context of [Operations (Queries & Actions)](../data-model/operations/overview). We'll see how that's done on the next page.
|
||||||
|
|
||||||
#### Using Entities directly
|
#### Using Entities directly
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import SuperjsonNote from './\_superjson-note.md';
|
|||||||
|
|
||||||
We'll explain what Actions are and how to use them. If you're looking for a detailed API specification, skip ahead to the [API Reference](#api-reference).
|
We'll explain what Actions are and how to use them. If you're looking for a detailed API specification, skip ahead to the [API Reference](#api-reference).
|
||||||
|
|
||||||
Actions are quite similar to [Queries](/docs/data-model/operations/queries.md), but with a key distinction: Actions are designed to modify and add data, while Queries are solely for reading data. Examples of Actions include adding a comment to a blog post, liking a video, or updating a product's price.
|
Actions are quite similar to [Queries](../../data-model/operations/queries.md), but with a key distinction: Actions are designed to modify and add data, while Queries are solely for reading data. Examples of Actions include adding a comment to a blog post, liking a video, or updating a product's price.
|
||||||
|
|
||||||
Actions and Queries work together to keep data caches up-to-date.
|
Actions and Queries work together to keep data caches up-to-date.
|
||||||
|
|
||||||
@ -373,7 +373,7 @@ export const createTask: CreateTask = async (args, context) => {
|
|||||||
|
|
||||||
### Using Entities in Actions
|
### Using Entities in Actions
|
||||||
|
|
||||||
In most cases, resources used in Actions will be [Entities](/docs/data-model/entities.md).
|
In most cases, resources used in Actions will be [Entities](../../data-model/entities.md).
|
||||||
To use an Entity in your Action, add it to the `action` declaration in Wasp:
|
To use an Entity in your Action, add it to the `action` declaration in Wasp:
|
||||||
|
|
||||||
<Tabs groupId="js-ts">
|
<Tabs groupId="js-ts">
|
||||||
@ -626,7 +626,7 @@ Since both arguments are positional, you can name the parameters however you wan
|
|||||||
|
|
||||||
2. `context` (type depends on the Action)
|
2. `context` (type depends on the Action)
|
||||||
|
|
||||||
An additional context object **passed into the Action by Wasp**. This object contains user session information, as well as information about entities. Check the [section about using entities in Actions](#using-entities-in-actions) to see how to use the entities field on the `context` object, or the [auth section](/docs/auth/overview#using-the-contextuser-object) to see how to use the `user` object.
|
An additional context object **passed into the Action by Wasp**. This object contains user session information, as well as information about entities. Check the [section about using entities in Actions](#using-entities-in-actions) to see how to use the entities field on the `context` object, or the [auth section](../../auth/overview#using-the-contextuser-object) to see how to use the `user` object.
|
||||||
|
|
||||||
<ShowForTs>
|
<ShowForTs>
|
||||||
|
|
||||||
@ -704,7 +704,7 @@ In this case, the Action expects to receive an object with a `bar` field of type
|
|||||||
|
|
||||||
### The `useAction` Hook and Optimistic Updates
|
### The `useAction` Hook and Optimistic Updates
|
||||||
|
|
||||||
Make sure you understand how [Queries](/docs/data-model/operations/queries.md) and [Cache Invalidation](#cache-invalidation) work before reading this chapter.
|
Make sure you understand how [Queries](../../data-model/operations/queries.md) and [Cache Invalidation](#cache-invalidation) work before reading this chapter.
|
||||||
|
|
||||||
When using Actions in components, you can enhance them with the help of the `useAction` hook. This hook comes bundled with Wasp, and is used for decorating Wasp Actions.
|
When using Actions in components, you can enhance them with the help of the `useAction` hook. This hook comes bundled with Wasp, and is used for decorating Wasp Actions.
|
||||||
In other words, the hook returns a function whose API matches the original Action while also doing something extra under the hood (depending on how you configure it).
|
In other words, the hook returns a function whose API matches the original Action while also doing something extra under the hood (depending on how you configure it).
|
||||||
|
@ -6,7 +6,7 @@ import { Required } from '@site/src/components/Required';
|
|||||||
|
|
||||||
While Entities enable help you define your app's data model and relationships, Operations are all about working with this data.
|
While Entities enable help you define your app's data model and relationships, Operations are all about working with this data.
|
||||||
|
|
||||||
There are two kinds of Operations: [Queries](/docs/data-model/operations/queries.md) and [Actions](/docs/data-model/operations/actions.md). As their names suggest,
|
There are two kinds of Operations: [Queries](../../data-model/operations/queries.md) and [Actions](../../data-model/operations/actions.md). As their names suggest,
|
||||||
Queries are meant for reading data, and Actions are meant for changing it (either by updating existing entries or creating new ones).
|
Queries are meant for reading data, and Actions are meant for changing it (either by updating existing entries or creating new ones).
|
||||||
|
|
||||||
Keep reading to find out all there is to know about Operations in Wasp.
|
Keep reading to find out all there is to know about Operations in Wasp.
|
||||||
|
@ -15,7 +15,7 @@ Fetching all comments on a blog post, a list of users that liked a video, inform
|
|||||||
Queries are fairly similar to Actions in terms of their API.
|
Queries are fairly similar to Actions in terms of their API.
|
||||||
Therefore, if you're already familiar with Actions, you might find reading the entire guide repetitive.
|
Therefore, if you're already familiar with Actions, you might find reading the entire guide repetitive.
|
||||||
|
|
||||||
We instead recommend skipping ahead and only reading [the differences between Queries and Actions](/docs/data-model/operations/actions#differences-between-queries-and-actions), and consulting the [API Reference](#api-reference) as needed.
|
We instead recommend skipping ahead and only reading [the differences between Queries and Actions](../../data-model/operations/actions#differences-between-queries-and-actions), and consulting the [API Reference](#api-reference) as needed.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
## Working with Queries
|
## Working with Queries
|
||||||
@ -395,7 +395,7 @@ To prevent information leakage, the server won't forward these fields for any ot
|
|||||||
|
|
||||||
### Using Entities in Queries
|
### Using Entities in Queries
|
||||||
|
|
||||||
In most cases, resources used in Queries will be [Entities](/docs/data-model/entities.md).
|
In most cases, resources used in Queries will be [Entities](../../data-model/entities.md).
|
||||||
To use an Entity in your Query, add it to the `query` declaration in Wasp:
|
To use an Entity in your Query, add it to the `query` declaration in Wasp:
|
||||||
|
|
||||||
<Tabs groupId="js-ts">
|
<Tabs groupId="js-ts">
|
||||||
@ -552,7 +552,7 @@ Since both arguments are positional, you can name the parameters however you wan
|
|||||||
|
|
||||||
2. `context` (type depends on the Query)
|
2. `context` (type depends on the Query)
|
||||||
|
|
||||||
An additional context object **passed into the Query by Wasp**. This object contains user session information, as well as information about entities. Check the [section about using entities in Queries](#using-entities-in-queries) to see how to use the entities field on the `context` object, or the [auth section](/docs/auth/overview#using-the-contextuser-object) to see how to use the `user` object.
|
An additional context object **passed into the Query by Wasp**. This object contains user session information, as well as information about entities. Check the [section about using entities in Queries](#using-entities-in-queries) to see how to use the entities field on the `context` object, or the [auth section](../../auth/overview#using-the-contextuser-object) to see how to use the `user` object.
|
||||||
|
|
||||||
<ShowForTs>
|
<ShowForTs>
|
||||||
|
|
||||||
@ -651,6 +651,6 @@ Wasp's `useQuery` hook accepts three arguments:
|
|||||||
[the default
|
[the default
|
||||||
behavior](https://react-query.tanstack.com/guides/important-defaults) for
|
behavior](https://react-query.tanstack.com/guides/important-defaults) for
|
||||||
this particular Query. If you want to change the global defaults, you can do
|
this particular Query. If you want to change the global defaults, you can do
|
||||||
so in the [client setup function](/docs/project/client-config.md#overriding-default-behaviour-for-queries).
|
so in the [client setup function](../../project/client-config.md#overriding-default-behaviour-for-queries).
|
||||||
|
|
||||||
For an example of usage, check [this section](#the-usequery-hook).
|
For an example of usage, check [this section](#the-usequery-hook).
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
---
|
|
||||||
title: Examples
|
|
||||||
---
|
|
||||||
|
|
||||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
|
||||||
|
|
||||||
We have a constantly growing collection of fully-functioning example apps, which you can use to learn more about Wasp's features.
|
|
||||||
|
|
||||||
The full list of examples can be found [here](https://github.com/wasp-lang/wasp/tree/release/examples/). Here is a few of them:
|
|
||||||
|
|
||||||
## Todo App
|
|
||||||
- **Features**: Auth ([username/password](language/features#authentication--authorization)), [Queries & Actions](language/features#queries-and-actions-aka-operations), [Entities](language/features#entity), [Routes](language/features#route)
|
|
||||||
- JS source code: [GitHub](https://github.com/wasp-lang/wasp/tree/release/examples/tutorials/TodoApp)
|
|
||||||
- TS source code: [GitHub](https://github.com/wasp-lang/wasp/tree/release/examples/todo-typescript)
|
|
||||||
- in-browser dev environment: [GitPod](https://gitpod.io/#https://github.com/wasp-lang/gitpod-template)
|
|
||||||
|
|
||||||
## Waspello (Trello Clone)
|
|
||||||
- **Features**: Auth ([Google](language/features#social-login-providers-oauth-20), [username/password](language/features#authentication--authorization)), [Optimistic Updates](language/features#the-useaction-hook), [Tailwind CSS integration](/docs/project/css-frameworks)
|
|
||||||
- Source code: [GitHub](https://github.com/wasp-lang/wasp/tree/main/examples/waspello)
|
|
||||||
- Hosted at [https://waspello-demo.netlify.app](https://waspello-demo.netlify.app/login)
|
|
||||||
<p align='center'>
|
|
||||||
<img src={useBaseUrl('img/wespello-new.png')} width='75%'/>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
## Waspleau (Realtime Statistics Dashboard)
|
|
||||||
- **Features**: Cron [Jobs](language/features#jobs), [Server Setup](language/features#server-configuration)
|
|
||||||
- Source code: [GitHub](https://github.com/wasp-lang/wasp/tree/main/examples/waspleau)
|
|
||||||
- Hosted at [https://waspleau-app-client.fly.dev/](https://waspleau-app-client.fly.dev/)
|
|
||||||
<p align='center'>
|
|
||||||
<img src={useBaseUrl('img/waspleau.png')} width='75%'/>
|
|
||||||
</p>
|
|
@ -5,7 +5,7 @@ This guide provides an overview of the Wasp CLI commands, arguments, and options
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
Once [installed](/docs/quick-start), you can use the wasp command from your command line.
|
Once [installed](../quick-start), you can use the wasp command from your command line.
|
||||||
|
|
||||||
If you run the `wasp` command without any arguments, it will show you a list of available commands and their descriptions:
|
If you run the `wasp` command without any arguments, it will show you a list of available commands and their descriptions:
|
||||||
|
|
||||||
@ -96,13 +96,13 @@ Newsletter: https://wasp-lang.dev/#signup
|
|||||||
Deleted .wasp/ directory.
|
Deleted .wasp/ directory.
|
||||||
```
|
```
|
||||||
|
|
||||||
- `wasp build` generates the complete web app code, which is ready for [deployment](/docs/advanced/deployment/overview). Use this command when you're deploying or ejecting. The generated code is stored in the `.wasp/build` folder.
|
- `wasp build` generates the complete web app code, which is ready for [deployment](../advanced/deployment/overview). Use this command when you're deploying or ejecting. The generated code is stored in the `.wasp/build` folder.
|
||||||
|
|
||||||
- `wasp deploy` makes it easy to get your app hosted on the web.
|
- `wasp deploy` makes it easy to get your app hosted on the web.
|
||||||
|
|
||||||
Currently, Wasp offers support for [Fly.io](https://fly.io). If you prefer a different hosting provider, feel free to let us know on Discord or submit a PR by updating [this TypeScript app](https://github.com/wasp-lang/wasp/tree/main/waspc/packages/deploy).
|
Currently, Wasp offers support for [Fly.io](https://fly.io). If you prefer a different hosting provider, feel free to let us know on Discord or submit a PR by updating [this TypeScript app](https://github.com/wasp-lang/wasp/tree/main/waspc/packages/deploy).
|
||||||
|
|
||||||
Read more about automatic deployment [here](/docs/advanced/deployment/cli).
|
Read more about automatic deployment [here](../advanced/deployment/cli).
|
||||||
|
|
||||||
- `wasp telemetry` displays the status of [telemetry](https://wasp-lang.dev/docs/telemetry).
|
- `wasp telemetry` displays the status of [telemetry](https://wasp-lang.dev/docs/telemetry).
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ slug: /editor-setup
|
|||||||
---
|
---
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
This page assumes you have already installed Wasp. If you do not have Wasp installed yet, check out the [Quick Start](/docs/quick-start) guide.
|
This page assumes you have already installed Wasp. If you do not have Wasp installed yet, check out the [Quick Start](./quick-start.md) guide.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Wasp comes with the Wasp language server, which gives supported editors powerful support and integration with the language.
|
Wasp comes with the Wasp language server, which gives supported editors powerful support and integration with the language.
|
||||||
|
@ -6,7 +6,7 @@ slug: /
|
|||||||
import ImgWithCaption from '@site/blog/components/ImgWithCaption'
|
import ImgWithCaption from '@site/blog/components/ImgWithCaption'
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
If you are looking for the installation instructions, check out the [Quick Start](/docs/quick-start) section.
|
If you are looking for the installation instructions, check out the [Quick Start](./quick-start.md) section.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
We will give a brief overview of what Wasp is, how it works on a high level and when to use it.
|
We will give a brief overview of what Wasp is, how it works on a high level and when to use it.
|
||||||
@ -170,7 +170,7 @@ export function HomePage({ user }: { user: User }) {
|
|||||||
|
|
||||||
And voila! We are listing all the recipes in our app 🎉
|
And voila! We are listing all the recipes in our app 🎉
|
||||||
|
|
||||||
This was just a quick example to give you a taste of what Wasp is. For step by step tour through the most important Wasp features, check out the [Todo app tutorial](/docs/tutorial/create).
|
This was just a quick example to give you a taste of what Wasp is. For step by step tour through the most important Wasp features, check out the [Todo app tutorial](../tutorial/01-create.md).
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
Above we skipped defining /login and /signup pages to keep the example a bit shorter, but those are very simple to do by using Wasp's Auth UI feature.
|
Above we skipped defining /login and /signup pages to keep the example a bit shorter, but those are very simple to do by using Wasp's Auth UI feature.
|
@ -43,8 +43,8 @@ Check [More Details](#more-details) section below if anything went wrong, or if
|
|||||||
|
|
||||||
### What next?
|
### What next?
|
||||||
|
|
||||||
- [ ] 👉 **Check out the [Todo App tutorial](/docs/tutorial/create), which will take you through all the core features of Wasp!** 👈
|
- [ ] 👉 **Check out the [Todo App tutorial](../tutorial/01-create.md), which will take you through all the core features of Wasp!** 👈
|
||||||
- [ ] [Setup your editor](/docs/editor-setup) for working with Wasp.
|
- [ ] [Setup your editor](./editor-setup.md) for working with Wasp.
|
||||||
- [ ] Join us on [Discord](https://discord.gg/rzdnErX)! Any feedback or questions you have, we are there for you.
|
- [ ] Join us on [Discord](https://discord.gg/rzdnErX)! Any feedback or questions you have, we are there for you.
|
||||||
- [ ] Follow Wasp development by subscribing to our newsletter: https://wasp-lang.dev/#signup . We usually send 1 per month, and Matija does his best to unleash his creativity to make them engaging and fun to read :D!
|
- [ ] Follow Wasp development by subscribing to our newsletter: https://wasp-lang.dev/#signup . We usually send 1 per month, and Matija does his best to unleash his creativity to make them engaging and fun to read :D!
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -211,7 +211,7 @@ export default async function mySetupFunction(): Promise<void> {
|
|||||||
### Overriding Default Behaviour for Queries
|
### Overriding Default Behaviour for Queries
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
You can change the options for a **single** Query using the `options` object, as described [here](/docs/data-model/operations/queries#the-usequery-hook-1).
|
You can change the options for a **single** Query using the `options` object, as described [here](../data-model/operations/queries#the-usequery-hook-1).
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Wasp's `useQuery` hook uses `react-query`'s `useQuery` hook under the hood. Since `react-query` comes configured with aggressive but sane default options, you most likely won't have to change those defaults for all Queries.
|
Wasp's `useQuery` hook uses `react-query`'s `useQuery` hook under the hood. Since `react-query` comes configured with aggressive but sane default options, you most likely won't have to change those defaults for all Queries.
|
||||||
|
@ -85,7 +85,7 @@ Make sure to use the `.cjs` extension for these config files, if you name them w
|
|||||||
|
|
||||||
### Adding Tailwind Plugins
|
### Adding Tailwind Plugins
|
||||||
|
|
||||||
To add Tailwind plugins, add it to [dependencies](/docs/project/dependencies) in your `main.wasp` file and to the plugins list in your `tailwind.config.cjs` file:
|
To add Tailwind plugins, add it to [dependencies](../project/dependencies) in your `main.wasp` file and to the plugins list in your `tailwind.config.cjs` file:
|
||||||
|
|
||||||
```wasp title="./main.wasp" {4-5}
|
```wasp title="./main.wasp" {4-5}
|
||||||
app todoApp {
|
app todoApp {
|
||||||
|
@ -113,28 +113,28 @@ The rest of the fields are covered in dedicated sections of the docs:
|
|||||||
|
|
||||||
- `auth: dict`
|
- `auth: dict`
|
||||||
|
|
||||||
Authentication configuration. Read more in the [authentication section](/docs/auth/overview) of the docs.
|
Authentication configuration. Read more in the [authentication section](../auth/overview) of the docs.
|
||||||
|
|
||||||
- `client: dict`
|
- `client: dict`
|
||||||
|
|
||||||
Configuration for the client side of your app. Read more in the [client configuration section](/docs/project/client-config) of the docs.
|
Configuration for the client side of your app. Read more in the [client configuration section](../project/client-config) of the docs.
|
||||||
|
|
||||||
- `server: dict`
|
- `server: dict`
|
||||||
|
|
||||||
Configuration for the server side of your app. Read more in the [server configuration section](/docs/project/server-config) of the docs.
|
Configuration for the server side of your app. Read more in the [server configuration section](../project/server-config) of the docs.
|
||||||
|
|
||||||
- `db: dict`
|
- `db: dict`
|
||||||
|
|
||||||
Database configuration. Read more in the [database configuration section](/docs/data-model/backends) of the docs.
|
Database configuration. Read more in the [database configuration section](../data-model/backends) of the docs.
|
||||||
|
|
||||||
- `dependencies: [(string, string)]`
|
- `dependencies: [(string, string)]`
|
||||||
|
|
||||||
List of npm dependencies for your app. Read more in the [dependencies section](/docs/project/dependencies) of the docs.
|
List of npm dependencies for your app. Read more in the [dependencies section](../project/dependencies) of the docs.
|
||||||
|
|
||||||
- `emailSender: dict`
|
- `emailSender: dict`
|
||||||
|
|
||||||
Email sender configuration. Read more in the [email sending section](/docs/advanced/email) of the docs.
|
Email sender configuration. Read more in the [email sending section](../advanced/email) of the docs.
|
||||||
|
|
||||||
- `webSocket: dict`
|
- `webSocket: dict`
|
||||||
|
|
||||||
WebSocket configuration. Read more in the [WebSocket section](/docs/advanced/web-sockets) of the docs.
|
WebSocket configuration. Read more in the [WebSocket section](../advanced/web-sockets) of the docs.
|
||||||
|
@ -131,4 +131,4 @@ The way you provide env vars to your Wasp project in production depends on where
|
|||||||
flyctl secrets set SOME_VAR_NAME=somevalue
|
flyctl secrets set SOME_VAR_NAME=somevalue
|
||||||
```
|
```
|
||||||
|
|
||||||
You can read a lot more details in the [deployment section](/docs/advanced/deployment/manually) of the docs. We go into detail on how to define env vars for each deployment option.
|
You can read a lot more details in the [deployment section](../advanced/deployment/manually) of the docs. We go into detail on how to define env vars for each deployment option.
|
||||||
|
@ -90,7 +90,7 @@ function addCustomRoute(app: Application) {
|
|||||||
|
|
||||||
### Storing Some Values for Later Use
|
### Storing Some Values for Later Use
|
||||||
|
|
||||||
In case you want to store some values for later use, or to be accessed by the [Operations](/docs/data-model/operations/overview) you do that in the `setupFn` function.
|
In case you want to store some values for later use, or to be accessed by the [Operations](../data-model/operations/overview) you do that in the `setupFn` function.
|
||||||
|
|
||||||
Dummy example of such function and its usage:
|
Dummy example of such function and its usage:
|
||||||
|
|
||||||
@ -247,4 +247,4 @@ app MyApp {
|
|||||||
|
|
||||||
- #### `middlewareConfigFn: ServerImport`
|
- #### `middlewareConfigFn: ServerImport`
|
||||||
|
|
||||||
The import statement to an Express middleware config function. This is a global modification affecting all operations and APIs. See more in the [configuring middleware section](/docs/advanced/middleware-config#1-customize-global-middleware).
|
The import statement to an Express middleware config function. This is a global modification affecting all operations and APIs. See more in the [configuring middleware section](../advanced/middleware-config#1-customize-global-middleware).
|
||||||
|
@ -69,7 +69,7 @@ Wasp provides several functions to help you write React tests:
|
|||||||
const { mockQuery, mockApi } = mockServer();
|
const { mockQuery, mockApi } = mockServer();
|
||||||
```
|
```
|
||||||
|
|
||||||
- `mockQuery`: Takes a Wasp [query](/docs/data-model/operations/queries) to mock and the JSON data it should return.
|
- `mockQuery`: Takes a Wasp [query](../data-model/operations/queries) to mock and the JSON data it should return.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import getTasks from "@wasp/queries/getTasks";
|
import getTasks from "@wasp/queries/getTasks";
|
||||||
@ -81,7 +81,7 @@ Wasp provides several functions to help you write React tests:
|
|||||||
- Behind the scenes, Wasp uses [`msw`](https://npmjs.com/package/msw) to create a server request handle that responds with the specified data.
|
- Behind the scenes, Wasp uses [`msw`](https://npmjs.com/package/msw) to create a server request handle that responds with the specified data.
|
||||||
- Mock are cleared between each test.
|
- Mock are cleared between each test.
|
||||||
|
|
||||||
- `mockApi`: Similar to `mockQuery`, but for [APIs](/docs/advanced/apis). Instead of a Wasp query, it takes a route containing an HTTP method and a path.
|
- `mockApi`: Similar to `mockQuery`, but for [APIs](../advanced/apis). Instead of a Wasp query, it takes a route containing an HTTP method and a path.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import { HttpMethod } from "@wasp/types";
|
import { HttpMethod } from "@wasp/types";
|
||||||
|
@ -5,7 +5,7 @@ title: 1. Creating a New Project
|
|||||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
You'll need to have the latest version of Wasp installed locally to follow this tutorial. If you haven't installed it yet, check out the [QuickStart](/docs/quick-start) guide!
|
You'll need to have the latest version of Wasp installed locally to follow this tutorial. If you haven't installed it yet, check out the [QuickStart](../quick-start) guide!
|
||||||
:::
|
:::
|
||||||
|
|
||||||
In this section, we'll guide you through the process of creating a simple Todo app with Wasp. In the process, we'll take you through the most important and useful features of Wasp.
|
In this section, we'll guide you through the process of creating a simple Todo app with Wasp. In the process, we'll take you through the most important and useful features of Wasp.
|
||||||
|
@ -35,7 +35,7 @@ By _your code_, we mean the _"the code you write"_, as opposed to the code gener
|
|||||||
|
|
||||||
Many of the other files (`tsconfig.json`, `vite-env.d.ts`, etc.) are used by your IDE to improve your development experience with tools like autocompletion, intellisense, and error reporting.
|
Many of the other files (`tsconfig.json`, `vite-env.d.ts`, etc.) are used by your IDE to improve your development experience with tools like autocompletion, intellisense, and error reporting.
|
||||||
The file `vite.config.ts` is used to configure [Vite](https://vitejs.dev/guide/), Wasp's build tool of choice.
|
The file `vite.config.ts` is used to configure [Vite](https://vitejs.dev/guide/), Wasp's build tool of choice.
|
||||||
We won't be configuring Vite in this tutorial, so you can safely ignore the file. Still, if you ever end up wanting more control over Vite, you'll find everything you need to know in [custom Vite config docs](/docs/project/custom-vite-config.md).
|
We won't be configuring Vite in this tutorial, so you can safely ignore the file. Still, if you ever end up wanting more control over Vite, you'll find everything you need to know in [custom Vite config docs](../project/custom-vite-config.md).
|
||||||
|
|
||||||
:::note TypeScript Support
|
:::note TypeScript Support
|
||||||
Wasp supports TypeScript out of the box, but you are free to choose between or mix JavaScript and TypeScript as you see fit.
|
Wasp supports TypeScript out of the box, but you are free to choose between or mix JavaScript and TypeScript as you see fit.
|
||||||
|
@ -142,7 +142,7 @@ Now you can visit `/hello/johnny` and see "Here's johnny!"
|
|||||||
<ShowForTs>
|
<ShowForTs>
|
||||||
|
|
||||||
:::tip Type-safe links
|
:::tip Type-safe links
|
||||||
Since you are using Typescript, you can benefit from using Wasp's type-safe `Link` component and the `routes` object. Check out the [type-safe links docs](/docs/advanced/links) for more details.
|
Since you are using Typescript, you can benefit from using Wasp's type-safe `Link` component and the `routes` object. Check out the [type-safe links docs](../advanced/links) for more details.
|
||||||
:::
|
:::
|
||||||
</ShowForTs>
|
</ShowForTs>
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ psl=}
|
|||||||
:::note
|
:::note
|
||||||
Wasp uses [Prisma](https://www.prisma.io) as a way to talk to the database. You define entities by defining [Prisma models](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-schema/data-model/) using the Prisma Schema Language (PSL) between the `{=psl psl=}` tags.
|
Wasp uses [Prisma](https://www.prisma.io) as a way to talk to the database. You define entities by defining [Prisma models](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-schema/data-model/) using the Prisma Schema Language (PSL) between the `{=psl psl=}` tags.
|
||||||
|
|
||||||
Read more in the [Entities](/docs/data-model/entities) section of the docs.
|
Read more in the [Entities](../data-model/entities) section of the docs.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
To update the database schema to include this entity, stop the `wasp start` process, if its running, and run:
|
To update the database schema to include this entity, stop the `wasp start` process, if its running, and run:
|
||||||
|
@ -5,7 +5,7 @@ title: 5. Querying the Database
|
|||||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
import { ShowForTs, ShowForJs } from '@site/src/components/TsJsHelpers';
|
import { ShowForTs, ShowForJs } from '@site/src/components/TsJsHelpers';
|
||||||
|
|
||||||
We want to know which tasks we need to do, so let's list them! The primary way of interacting with entities in Wasp is by using [queries and actions](/docs/data-model/operations/overview), collectively known as _operations_.
|
We want to know which tasks we need to do, so let's list them! The primary way of interacting with entities in Wasp is by using [queries and actions](../data-model/operations/overview), collectively known as _operations_.
|
||||||
|
|
||||||
Queries are used to read an entity, while actions are used to create, modify, and delete entities. Since we want to list the tasks, we'll want to use a query.
|
Queries are used to read an entity, while actions are used to create, modify, and delete entities. Since we want to list the tasks, we'll want to use a query.
|
||||||
|
|
||||||
@ -225,14 +225,14 @@ Most of this code is regular React, the only exception being the <ShowForJs>two<
|
|||||||
<ShowForJs>
|
<ShowForJs>
|
||||||
|
|
||||||
- `import getTasks from '@wasp/queries/getTasks'` - Imports the client-side query function.
|
- `import getTasks from '@wasp/queries/getTasks'` - Imports the client-side query function.
|
||||||
- `import { useQuery } from '@wasp/queries'` - Imports Wasp's [useQuery](/docs/data-model/operations/queries#the-usequery-hook-1) React hook, which is based on [react-query](https://github.com/tannerlinsley/react-query)'s hook with the same name.
|
- `import { useQuery } from '@wasp/queries'` - Imports Wasp's [useQuery](../data-model/operations/queries#the-usequery-hook-1) React hook, which is based on [react-query](https://github.com/tannerlinsley/react-query)'s hook with the same name.
|
||||||
|
|
||||||
</ShowForJs>
|
</ShowForJs>
|
||||||
|
|
||||||
<ShowForTs>
|
<ShowForTs>
|
||||||
|
|
||||||
- `import getTasks from '@wasp/queries/getTasks'` - Imports the client-side query function.
|
- `import getTasks from '@wasp/queries/getTasks'` - Imports the client-side query function.
|
||||||
- `import { useQuery } from '@wasp/queries'` - Imports Wasp's [useQuery](/docs/data-model/operations/queries#the-usequery-hook-1) React hook, which is based on [react-query](https://github.com/tannerlinsley/react-query)'s hook with the same name.
|
- `import { useQuery } from '@wasp/queries'` - Imports Wasp's [useQuery](../data-model/operations/queries#the-usequery-hook-1) React hook, which is based on [react-query](https://github.com/tannerlinsley/react-query)'s hook with the same name.
|
||||||
- `import { Task } from '@wasp/entities'` - The type for the task entity we defined in `main.wasp`.
|
- `import { Task } from '@wasp/entities'` - The type for the task entity we defined in `main.wasp`.
|
||||||
|
|
||||||
Notice how you don't need to annotate the type of the query's return value: Wasp uses the types you defined while implementing the query for the generated client-side function. This is **full-stack type safety**: the types on the client always match the types on the server.
|
Notice how you don't need to annotate the type of the query's return value: Wasp uses the types you defined while implementing the query for the generated client-side function. This is **full-stack type safety**: the types on the client always match the types on the server.
|
||||||
|
@ -39,7 +39,7 @@ wasp db migrate-dev
|
|||||||
|
|
||||||
## Adding Auth to the Project
|
## Adding Auth to the Project
|
||||||
|
|
||||||
Next, we want to tell Wasp that we want to use full-stack [authentication](/docs/auth/overview) in our app:
|
Next, we want to tell Wasp that we want to use full-stack [authentication](../auth/overview) in our app:
|
||||||
|
|
||||||
```wasp {7-16} title="main.wasp"
|
```wasp {7-16} title="main.wasp"
|
||||||
app TodoApp {
|
app TodoApp {
|
||||||
@ -65,13 +65,13 @@ app TodoApp {
|
|||||||
|
|
||||||
By doing this, Wasp will create:
|
By doing this, Wasp will create:
|
||||||
|
|
||||||
- [Auth UI](/docs/auth/ui) with login and signup forms.
|
- [Auth UI](../auth/ui) with login and signup forms.
|
||||||
- A `logout()` action.
|
- A `logout()` action.
|
||||||
- A React hook `useAuth()`.
|
- A React hook `useAuth()`.
|
||||||
- `context.user` for use in Queries and Actions.
|
- `context.user` for use in Queries and Actions.
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
Wasp also supports authentication using [Google](/docs/auth/social-auth/google), [GitHub](/docs/auth/social-auth/github), and [email](/docs/auth/email), with more on the way!
|
Wasp also supports authentication using [Google](../auth/social-auth/google), [GitHub](../auth/social-auth/github), and [email](../auth/email), with more on the way!
|
||||||
:::
|
:::
|
||||||
|
|
||||||
## Adding Login and Signup Pages
|
## Adding Login and Signup Pages
|
||||||
@ -216,7 +216,7 @@ export default SignupPage
|
|||||||
<ShowForTs>
|
<ShowForTs>
|
||||||
|
|
||||||
:::tip Type-safe links
|
:::tip Type-safe links
|
||||||
Since you are using Typescript, you can benefit from using Wasp's type-safe `Link` component and the `routes` object. Check out the [type-safe links docs](/docs/advanced/links) for more details.
|
Since you are using Typescript, you can benefit from using Wasp's type-safe `Link` component and the `routes` object. Check out the [type-safe links docs](../advanced/links) for more details.
|
||||||
:::
|
:::
|
||||||
</ShowForTs>
|
</ShowForTs>
|
||||||
|
|
||||||
@ -515,8 +515,8 @@ You should be ready to learn about more complicated features and go more in-dept
|
|||||||
|
|
||||||
Looking for inspiration?
|
Looking for inspiration?
|
||||||
|
|
||||||
- Get a jump start on your next project with [Starter Templates](/docs/project/starter-templates)
|
- Get a jump start on your next project with [Starter Templates](../project/starter-templates)
|
||||||
- Make a real-time app with [Web Sockets](/docs/advanced/web-sockets)
|
- Make a real-time app with [Web Sockets](../advanced/web-sockets)
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
If you notice that some of the features you'd like to have are missing, or have any other kind of feedback, please write to us on [Discord](https://discord.gg/rzdnErX) or create an issue on [Github](https://github.com/wasp-lang/wasp), so we can learn which features to add/improve next 🙏
|
If you notice that some of the features you'd like to have are missing, or have any other kind of feedback, please write to us on [Discord](https://discord.gg/rzdnErX) or create an issue on [Github](https://github.com/wasp-lang/wasp), so we can learn which features to add/improve next 🙏
|
||||||
|
@ -1,521 +0,0 @@
|
|||||||
---
|
|
||||||
title: TypeScript Support
|
|
||||||
---
|
|
||||||
|
|
||||||
import OldDocsNote from '@site/docs/OldDocsNote'
|
|
||||||
|
|
||||||
# Using Wasp with TypeScript
|
|
||||||
|
|
||||||
<OldDocsNote />
|
|
||||||
|
|
||||||
TypeScript is a programming language that brings static type analysis to JavaScript. It is a superset of JavaScript (i.e., all valid JavaScript programs are valid TypeScript programs) and compiles to JavaScript before running. TypeScript's type system detects common errors at build time (reducing the chance of runtime errors in production) and enables type-based auto-completion in IDEs.
|
|
||||||
|
|
||||||
This document assumes you are familiar with TypeScript and primarily focuses on how to use it with Wasp. To learn more about TypeScript itself, we recommend reading [the official docs](https://www.typescriptlang.org/docs/).
|
|
||||||
|
|
||||||
The document also assumes a basic understanding of core Wasp features (e.g., Queries, Actions, Entities). You can read more about these features in [our feature docs](/docs/language/features).
|
|
||||||
|
|
||||||
Besides allowing you to write your code in TypeScript, Wasp also supports:
|
|
||||||
|
|
||||||
- Importing and using Wasp Entity types (on both the server and the client).
|
|
||||||
- Automatic full-stack type support for Queries and Actions - frontend types are automatically inferred from backend definitions.
|
|
||||||
- Type-safe generic hooks (`useQuery` and `useAction`) with the accompanying type inference.
|
|
||||||
- Type-safe optimistic update definitions.
|
|
||||||
|
|
||||||
We'll dig into the details of each feature in the following sections. But first, let's see how you can introduce TypeScript to an existing Wasp project.
|
|
||||||
|
|
||||||
:::info
|
|
||||||
To get the best IDE experience, make sure to leave `wasp start` running in the background. Wasp will track the working directory and ensure the generated code/types are up to date with your changes.
|
|
||||||
|
|
||||||
Your editor may sometimes report type and import errors even while `wasp start` is running. This happens when the TypeScript Language Server gets out of sync with the current code. If you're using VS Code, you can manually restart the language server by opening the command palette and selecting _"TypeScript: Restart TS Server."_
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Migrating your project to TypeScript
|
|
||||||
|
|
||||||
Wasp supports TypeScript out of the box!
|
|
||||||
|
|
||||||
Our scaffolding already includes TypeScript, so migrating your project to TypeScript is as simple as changing file extensions and using the language. This approach allows you to gradually migrate your project on a file-by-file basis.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
Let's first assume your Wasp file contains the following definitions:
|
|
||||||
|
|
||||||
```wasp title=main.wasp
|
|
||||||
entity Task {=psl
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
description String
|
|
||||||
isDone Boolean @default(false)
|
|
||||||
psl=}
|
|
||||||
|
|
||||||
query getTaskInfo {
|
|
||||||
fn: import { getTaskInfo } from "@server/queries.js",
|
|
||||||
entities: [Task]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Let's now assume that your `queries.js` file looks something like this:
|
|
||||||
|
|
||||||
```javascript title="src/server/queries.js"
|
|
||||||
import HttpError from "@wasp/core/HttpError.js"
|
|
||||||
|
|
||||||
function getInfoMessage(task) {
|
|
||||||
const isDoneText = task.isDone ? "is done" : "is not done"
|
|
||||||
return `Task '${task.description}' is ${isDoneText}.`
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getTaskInfo = async ({ id }, context) => {
|
|
||||||
const Task = context.entities.Task
|
|
||||||
const task = await Task.findUnique({ where: { id } })
|
|
||||||
if (!task) {
|
|
||||||
throw new HttpError(404)
|
|
||||||
}
|
|
||||||
return getInfoMessage(task)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
To migrate this file to TypeScript, all you have to do is:
|
|
||||||
|
|
||||||
1. Change the filename from `queries.js` to `queries.ts`.
|
|
||||||
2. Write some types.
|
|
||||||
|
|
||||||
Let's start by only providing a basic `getInfoMessage` function. We'll see how to properly type the rest of the file in the following sections.
|
|
||||||
|
|
||||||
```typescript title=src/server/queries.ts
|
|
||||||
import HttpError from "@wasp/core/HttpError.js"
|
|
||||||
|
|
||||||
// highlight-next-line
|
|
||||||
function getInfoMessage(task: {
|
|
||||||
isDone: boolean
|
|
||||||
description: string
|
|
||||||
}): string {
|
|
||||||
const isDoneText = task.isDone ? "is done" : "is not done"
|
|
||||||
return `Task '${task.description}' is ${isDoneText}.`
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getTaskInfo = async ({ id }, context) => {
|
|
||||||
const Task = context.entities.Task
|
|
||||||
const task = await Task.findUnique({ where: { id } })
|
|
||||||
if (!task) {
|
|
||||||
throw new HttpError(404)
|
|
||||||
}
|
|
||||||
return getInfoMessage(task)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You don't need to change anything inside the `.wasp` file.
|
|
||||||
:::caution
|
|
||||||
|
|
||||||
<!-- This block is mostly duplicated in 03-listing-tasks.md -->
|
|
||||||
|
|
||||||
Even when you use TypeScript, and your file is called `queries.ts`, you still need to import it using the `.js` extension:
|
|
||||||
|
|
||||||
```wasp
|
|
||||||
query getTaskInfo {
|
|
||||||
fn: import { getTaskInfo } from "@server/queries.js",
|
|
||||||
entities: [Task]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Wasp internally uses `esnext` module resolution, which always requires specifying the extension as `.js` (i.e., the extension used in the emitted JS file). This applies to all `@server` imports (and files on the server in general). This quirk does not apply to client files (the transpiler takes care of it).
|
|
||||||
|
|
||||||
Read more about ES modules in TypeScript [here](https://www.typescriptlang.org/docs/handbook/esm-node.html). If you're interested in the discussion and the reasoning behind this, read about it [in this GitHub issue](https://github.com/microsoft/TypeScript/issues/33588).
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Entity Types
|
|
||||||
|
|
||||||
Instead of manually specifying the types for `isDone` and `description`, we can get them from the `Task` entity type. Wasp will generate types for all entities and let you import them from `"@wasp/entities"`:
|
|
||||||
|
|
||||||
```typescript title=src/server/queries.ts
|
|
||||||
import HttpError from "@wasp/core/HttpError.js"
|
|
||||||
// highlight-next-line
|
|
||||||
import { Task } from "@wasp/entities"
|
|
||||||
|
|
||||||
// highlight-next-line
|
|
||||||
function getInfoMessage(task: Pick<Task, "isDone" | "description">): string {
|
|
||||||
const isDoneText = task.isDone ? "is done" : "is not done"
|
|
||||||
return `Task '${task.description}' is ${isDoneText}.`
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getTaskInfo = async ({ id }, context) => {
|
|
||||||
const Task = context.entities.Task
|
|
||||||
const task = await Task.findUnique({ where: { id } })
|
|
||||||
if (!task) {
|
|
||||||
throw new HttpError(404)
|
|
||||||
}
|
|
||||||
return getInfoMessage(task)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
By doing this, we've connected the argument type of the `getInfoMessage` function with the `Task` entity. This coupling removes duplication and ensures the function keeps the correct signature even if we change the entity. Of course, the function might throw type errors depending on how we change the entity, but that's precisely what we want!
|
|
||||||
|
|
||||||
Don't worry about typing the query function for now. We'll see how to handle this in the next section.
|
|
||||||
|
|
||||||
Entity types are also available on the client under the same import:
|
|
||||||
|
|
||||||
```tsx title=src/client/Main.jsx
|
|
||||||
import { Task } from "@wasp/entities"
|
|
||||||
|
|
||||||
export function ExamplePage() {}
|
|
||||||
const task: Task = {
|
|
||||||
id: 123,
|
|
||||||
description: "Some random task",
|
|
||||||
isDone: false,
|
|
||||||
}
|
|
||||||
return <div>{task.description}</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
The mentioned type safety mechanisms also apply here: changing the task entity in our `.wasp` file changes the imported type, which might throw a type error and warn us that our task definition is outdated.
|
|
||||||
|
|
||||||
## Backend type support for Queries and Actions
|
|
||||||
|
|
||||||
Wasp automatically generates the appropriate types for all Operations (i.e., Actions and Queries) you define inside your `.wasp` file. Assuming your `.wasp` file contains the following definition:
|
|
||||||
|
|
||||||
```wasp title=main.wasp
|
|
||||||
// ...
|
|
||||||
|
|
||||||
query GetTaskInfo {
|
|
||||||
fn: import { getTaskInfo } from "@server/queries.js",
|
|
||||||
entities: [Task]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Wasp will generate a type called `GetTaskInfo`, which you can use to type the Query's implementation. By assigning the `GetTaskInfo` type to your function, you get the type information for its context. In this case, TypeScript will know the `context.entities` object must include the `Task` entity. If the Query had auth enabled, it would also know that `context` includes user information.
|
|
||||||
|
|
||||||
`GetTaskInfo` can is a generic type that takes two (optional) type arguments:
|
|
||||||
|
|
||||||
1. `Input` - The argument (i.e., payload) received by the query function.
|
|
||||||
2. `Output` - The query function's return type.
|
|
||||||
|
|
||||||
Suppose you don't care about typing the Query's inputs and outputs. In that case, you can omit both type arguments, and TypeScript will infer the most general types (i.e., `never` for the input, `unknown` for the output.).
|
|
||||||
|
|
||||||
```typescript title=src/server/queries.ts
|
|
||||||
import HttpError from "@wasp/core/HttpError.js"
|
|
||||||
import { Task } from "@wasp/entities"
|
|
||||||
// highlight-next-line
|
|
||||||
import { GetTaskInfo } from "@wasp/queries/types"
|
|
||||||
|
|
||||||
function getInfoMessage(task: Pick<Task, "isDone" | "description">): string {
|
|
||||||
const isDoneText = task.isDone ? "is done" : "is not done"
|
|
||||||
return `Task '${task.description}' is ${isDoneText}.`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the type parameters to specify the Query's argument and return types.
|
|
||||||
// highlight-next-line
|
|
||||||
export const getTaskInfo: GetTaskInfo<Pick<Task, "id">, string> = async ({ id }, context) => {
|
|
||||||
// Thanks to the definition in your .wasp file, the compiler knows the type of
|
|
||||||
// `context` (and that it contains the `Task` entity).
|
|
||||||
const Task = context.entities.Task
|
|
||||||
|
|
||||||
// Thanks to the first type argument in `GetTaskInfo`, the compiler knows `args`
|
|
||||||
// is of type `Pick<Task, "id">`.
|
|
||||||
const task = await Task.findUnique({ where: { id } })
|
|
||||||
if (!task) {
|
|
||||||
throw new HttpError(404)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Thanks to the second type argument in `GetTaskInfo`, the compiler knows the
|
|
||||||
// function must return a value of type `string`.
|
|
||||||
return getInfoMessage(task)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
Everything described above applies to Actions as well.
|
|
||||||
:::tip
|
|
||||||
|
|
||||||
If don't want to define a new type for the Query's return value, the new `satisfies` keyword will allow TypeScript to infer it automatically:
|
|
||||||
```typescript
|
|
||||||
const getFoo = (async (_args, context) => {
|
|
||||||
const foos = await context.entities.Foo.findMany()
|
|
||||||
return {
|
|
||||||
foos,
|
|
||||||
message: "Here are some foos!",
|
|
||||||
queriedAt: new Date(),
|
|
||||||
}
|
|
||||||
}) satisfies GetFoo
|
|
||||||
```
|
|
||||||
From the snippet above, TypeScript knows:
|
|
||||||
1. The correct type for `context`.
|
|
||||||
2. The Query's return type is `{ foos: Foo[], message: string, queriedAt: Date }`.
|
|
||||||
|
|
||||||
If you don't need the context, you can skip specifying the Query's type (and arguments):
|
|
||||||
```typescript
|
|
||||||
const getFoo = () => {{ name: 'Foo', date: new Date() }}
|
|
||||||
```
|
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Frontend type support for Queries and Actions
|
|
||||||
|
|
||||||
Wasp supports automatic full-stack type safety à la tRPC. You only need to define the Operation's type on the backend, and the frontend will automatically know how to call it.
|
|
||||||
|
|
||||||
### Frontend type support for Queries
|
|
||||||
The examples assume you've defined the Query `getTaskInfo` from the previous sections:
|
|
||||||
|
|
||||||
```typescript title="src/server/queries.ts"
|
|
||||||
export const getTaskInfo: GetTaskInfo<Pick<Task, "id">, string> =
|
|
||||||
async ({ id }, context) => {
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Wasp will use the type of `getTaskInfo` to infer the Query's types on the frontend:
|
|
||||||
|
|
||||||
```tsx title="src/client/TaskInfo.tsx"
|
|
||||||
import { useQuery } from "@wasp/queries"
|
|
||||||
// Wasp knows the type of `getTaskInfo` thanks to your backend definition.
|
|
||||||
// highlight-next-line
|
|
||||||
import getTaskInfo from "@wasp/queries/getTaskInfo"
|
|
||||||
|
|
||||||
export const TaskInfo = () => {
|
|
||||||
const {
|
|
||||||
// TypeScript knows `taskInfo` is a `string | undefined` thanks to the
|
|
||||||
// backend definition.
|
|
||||||
data: taskInfo,
|
|
||||||
// TypeScript also knows `isError` is a `boolean`.
|
|
||||||
isError,
|
|
||||||
// TypeScript knows `error` is of type `Error`.
|
|
||||||
error,
|
|
||||||
// TypeScript knows `id` must be a `Task["id"]` (i.e., a number) thanks to
|
|
||||||
// your backend definition.
|
|
||||||
// highlight-next-line
|
|
||||||
} = useQuery(getTaskInfo, { id: 1 })
|
|
||||||
|
|
||||||
if (isError) {
|
|
||||||
return <div> Error during fetching tasks: {error.message || "unknown"}</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeScript forces you to perform this check.
|
|
||||||
return taskInfo === undefined ? (
|
|
||||||
<div>Waiting for info...</div>
|
|
||||||
) : (
|
|
||||||
<div>{taskInfo}</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Frontend type support for Actions
|
|
||||||
|
|
||||||
Assuming the following action definition in your `.wasp` file
|
|
||||||
|
|
||||||
```wasp title=main.wasp
|
|
||||||
action addTask {
|
|
||||||
fn: import { addTask } from "@server/actions.js"
|
|
||||||
entities: [Task]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
And its corresponding implementation in `src/server/actions.ts`:
|
|
||||||
|
|
||||||
```typescript title=src/server/actions.ts
|
|
||||||
import { AddTask } from "@wasp/actions/types"
|
|
||||||
|
|
||||||
type TaskPayload = Pick<Task, "description" | "isDone">
|
|
||||||
|
|
||||||
const addTask: AddTask<TaskPayload, Task> = async (args, context) => {
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Here's how to use it on the frontend:
|
|
||||||
```tsx title=src/client/AddTask.tsx
|
|
||||||
import { useAction } from "@wasp/actions"
|
|
||||||
// TypeScript knows `addTask` is a function that expects a value of type
|
|
||||||
// `TaskPayload` and returns a value of type `Promise<Task>`.
|
|
||||||
import addTask from "@wasp/queries/addTask"
|
|
||||||
|
|
||||||
const AddTask = ({ description }: Pick<Task, "description">) => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<button onClick={() => addTask({ description, isDone: false })}>
|
|
||||||
Add unfinished task
|
|
||||||
</button>
|
|
||||||
<button onClick={() => addTask({ description, isDone: true })}>
|
|
||||||
Add finished task
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
#### Type support for the `useAction` hook
|
|
||||||
Type inference also works if you decide to use the action via the `useAction` hook:
|
|
||||||
```typescript
|
|
||||||
// addTaskFn is of type (args: TaskPayload) => Task
|
|
||||||
const addTaskFn = useAction(addTask)
|
|
||||||
```
|
|
||||||
|
|
||||||
The `useAction` hook also includes support for optimistic updates. Read [the feature docs](/docs/language/features#the-useaction-hook) to understand more about optimistic updates and how to define them in Wasp.
|
|
||||||
|
|
||||||
Here's an example that shows how you can use static type checking in their definitions (the example assumes an appropriate action defined in the `.wasp` file and implemented on the server):
|
|
||||||
|
|
||||||
```tsx title=Task.tsx
|
|
||||||
import { useQuery } from "@wasp/queries"
|
|
||||||
import { OptimisticUpdateDefinition, useAction } from "@wasp/actions"
|
|
||||||
import updateTaskIsDone from "@wasp/actions/updateTaskIsDone"
|
|
||||||
|
|
||||||
type TaskPayload = Pick<Task, "id" | "isDone">
|
|
||||||
|
|
||||||
const Task = ({ taskId }: Pick<Task, "id">) => {
|
|
||||||
const updateTaskIsDoneOptimistically = useAction(
|
|
||||||
updateTaskIsDone,
|
|
||||||
{
|
|
||||||
optimisticUpdates: [
|
|
||||||
{
|
|
||||||
getQuerySpecifier: () => [getTask, { id: taskId }],
|
|
||||||
// This query's cache should should never be empty
|
|
||||||
updateQuery: ({ isDone }, oldTask) => ({ ...oldTask!, isDone }),
|
|
||||||
// highlight-next-line
|
|
||||||
} as OptimisticUpdateDefinition<TaskPayload, Task>,
|
|
||||||
{
|
|
||||||
getQuerySpecifier: () => [getTasks],
|
|
||||||
updateQuery: (updatedTask, oldTasks) =>
|
|
||||||
oldTasks &&
|
|
||||||
oldTasks.map((task) =>
|
|
||||||
task.id === updatedTask.id ? { ...task, ...updatedTask } : task
|
|
||||||
),
|
|
||||||
// highlight-next-line
|
|
||||||
} as OptimisticUpdateDefinition<TaskPayload, Task[]>,
|
|
||||||
],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Database seeding
|
|
||||||
|
|
||||||
When implementing a seed function in TypeScript, you can import a `DbSeedFn` type via
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import type { DbSeedFn } from "@wasp/dbSeed/types.js"
|
|
||||||
```
|
|
||||||
|
|
||||||
and use it to type your seed function like this:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
export const devSeedSimple: DbSeedFn = async (prismaClient) => { ... }
|
|
||||||
```
|
|
||||||
|
|
||||||
## CRUD operations on entities
|
|
||||||
|
|
||||||
For a specific [Entity](/docs/language/features#entity), you can tell Wasp to automatically instantiate server-side logic ([Queries](/docs/language/features#query) and [Actions](/docs/language/features#action)) for creating, reading, updating and deleting such entities.
|
|
||||||
|
|
||||||
Read more about CRUD operations in Wasp [here](/docs/language/features#crud-operations).
|
|
||||||
|
|
||||||
### Using types for CRUD operations overrides
|
|
||||||
|
|
||||||
If you writing the override implementation in Typescript, you'll have access to generated types. The overrides are functions that take the following arguments:
|
|
||||||
- `args` - The arguments of the operation i.e. the data that's sent from the client.
|
|
||||||
- `context` - Context containing the `user` making the request and the `entities` object containing the entity that's being operated on.
|
|
||||||
|
|
||||||
You can types for each of the functions you want to override from `@wasp/crud/{crud name}`. The types that are available are:
|
|
||||||
- `GetAllQuery`
|
|
||||||
- `GetQuery`
|
|
||||||
- `CreateAction`
|
|
||||||
- `UpdateAction`
|
|
||||||
- `DeleteAction`
|
|
||||||
|
|
||||||
If you have a CRUD named `Tasks`, you would import the types like this:
|
|
||||||
```ts
|
|
||||||
import type { GetAllQuery, GetQuery, CreateAction, UpdateAction, DeleteAction } from '@wasp/crud/Tasks'
|
|
||||||
|
|
||||||
// Each of the types is a generic type, so you can use it like this:
|
|
||||||
export const getAllOverride: GetAllQuery<Input, Output> = async (args, context) => {
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## WebSocket full-stack type support
|
|
||||||
|
|
||||||
|
|
||||||
Defining event names with the matching payload types on the server makes those types exposed automatically on the client. This helps you avoid mistakes when emitting events or handling them.
|
|
||||||
|
|
||||||
### Defining the events handler
|
|
||||||
On the server, you will get Socket.IO `io: Server` argument and `context` for your WebSocket function, which contains all entities you defined in your Wasp app. You can type the `webSocketFn` function like this:
|
|
||||||
|
|
||||||
```ts title=src/server/webSocket.ts
|
|
||||||
import type { WebSocketDefinition, WaspSocketData } from '@wasp/webSocket'
|
|
||||||
|
|
||||||
// Using the generic WebSocketDefinition type to define the WebSocket function.
|
|
||||||
type WebSocketFn = WebSocketDefinition<
|
|
||||||
ClientToServerEvents,
|
|
||||||
ServerToClientEvents,
|
|
||||||
InterServerEvents,
|
|
||||||
SocketData
|
|
||||||
>
|
|
||||||
|
|
||||||
interface ServerToClientEvents {
|
|
||||||
// The type for the payload of the "chatMessage" event.
|
|
||||||
chatMessage: (msg: { id: string, username: string, text: string }) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ClientToServerEvents {
|
|
||||||
// The type for the payload of the "chatMessage" event.
|
|
||||||
chatMessage: (msg: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface InterServerEvents {}
|
|
||||||
|
|
||||||
interface SocketData extends WaspSocketData {}
|
|
||||||
|
|
||||||
// Use the WebSocketFn to type the webSocketFn function.
|
|
||||||
export const webSocketFn: WebSocketFn = (io, context) => {
|
|
||||||
io.on('connection', (socket) => {
|
|
||||||
socket.on('chatMessage', async (msg) => {
|
|
||||||
io.emit('chatMessage', { ... })
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Using the WebSocket on the client
|
|
||||||
|
|
||||||
After you have defined the WebSocket function on the server, you can use it on the client. The `useSocket` hook will give you the `socket` instance and the `isConnected` boolean. The `socket` instance is typed with the types you defined on the server.
|
|
||||||
|
|
||||||
The `useSocketListener` hook will give you a type-safe event handler. The event name and its payload type are defined on the server.
|
|
||||||
|
|
||||||
You can additonally use the `ClientToServerPayload` and `ServerToClientPayload` helper types to get the payload type for a specific event.
|
|
||||||
|
|
||||||
```tsx title=src/client/ChatPage.tsx
|
|
||||||
import React, { useState } from 'react'
|
|
||||||
import {
|
|
||||||
useSocket,
|
|
||||||
useSocketListener,
|
|
||||||
ServerToClientPayload,
|
|
||||||
ClientToServerPayload,
|
|
||||||
} from '@wasp/webSocket'
|
|
||||||
|
|
||||||
export const ChatPage = () => {
|
|
||||||
const [messageText, setMessageText] = useState<
|
|
||||||
// We are using a helper type to get the payload type for the "chatMessage" event.
|
|
||||||
ClientToServerPayload<'chatMessage'>
|
|
||||||
>('')
|
|
||||||
|
|
||||||
const [messages, setMessages] = useState<
|
|
||||||
// We are using a helper type to get the payload type for the "chatMessage" event.
|
|
||||||
ServerToClientPayload<'chatMessage'>[]
|
|
||||||
>([])
|
|
||||||
|
|
||||||
// The "socket" instance is typed with the types you defined on the server.
|
|
||||||
const { socket, isConnected } = useSocket()
|
|
||||||
|
|
||||||
// This is a type-safe event handler: "chatMessage" event and its payload type
|
|
||||||
// are defined on the server.
|
|
||||||
useSocketListener('chatMessage', logMessage)
|
|
||||||
|
|
||||||
function logMessage(msg: ServerToClientPayload<'chatMessage'>) {
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
|
|
||||||
e.preventDefault()
|
|
||||||
// This is a type-safe event emitter: "chatMessage" event and its payload type
|
|
||||||
// are defined on the server.
|
|
||||||
socket.emit('chatMessage', messageText)
|
|
||||||
setMessageText('')
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
...
|
|
||||||
)
|
|
||||||
}
|
|
||||||
```
|
|
@ -6,8 +6,8 @@
|
|||||||
"collapsed": false,
|
"collapsed": false,
|
||||||
"collapsible": false,
|
"collapsible": false,
|
||||||
"items": [
|
"items": [
|
||||||
"introduction/what-is-wasp",
|
"introduction/introduction",
|
||||||
"introduction/getting-started",
|
"introduction/quick-start",
|
||||||
"introduction/editor-setup"
|
"introduction/editor-setup"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user