Skip to content
This repository was archived by the owner on Sep 24, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions backend/functions/helloworld.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Request, Response } from "express";

export default (req: Request, res: Response) => {
// if accept is not set or set to text/plain, return plain text
if (!req.headers.accept || req.headers.accept === "text/plain") {
res.setHeader("Content-Type", "text/plain");
return res.status(200).send("Hello, World!");
}

// if accept is set to application/json, return JSON
if (req.headers.accept === "application/json") {
res.setHeader("Content-Type", "application/json");
return res.status(200).json({ message: "Hello, World!" });
}

// fail with 400
res.setHeader("Content-Type", "text/plain");
res.status(400).send("Unsupported Accept Header");
};
16 changes: 16 additions & 0 deletions backend/nhost/metadata/databases/default/tables/public_movies.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
table:
name: movies
schema: public
select_permissions:
- role: public
permission:
columns:
- id
- title
- director
- release_year
- genre
- rating
- created_at
- updated_at
filter: {}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- "!include auth_users.yaml"
- "!include public_attachments.yaml"
- "!include public_comments.yaml"
- "!include public_movies.yaml"
- "!include public_ninja_turtles.yaml"
- "!include public_tasks.yaml"
- "!include storage_buckets.yaml"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE IF EXISTS movies CASCADE;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
CREATE TABLE movies (id UUID PRIMARY KEY DEFAULT gen_random_uuid(), title TEXT NOT NULL, director TEXT, release_year INTEGER, genre TEXT, rating DECIMAL(3,1), created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW());
INSERT INTO movies (id, title, director, release_year, genre, rating) VALUES ('3d67a6d0-bfb5-444a-9152-aea543ebd171', 'The Matrix', 'Lana Wachowski, Lilly Wachowski', 1999, 'Sci-Fi', 8.7), ('90f374db-16c1-4db5-ba55-643bf38953d3', 'Inception', 'Christopher Nolan', 2010, 'Sci-Fi', 8.8), ('900fa76c-fc79-470d-817b-4dc4412a79e8', 'The Godfather', 'Francis Ford Coppola', 1972, 'Crime', 9.2), ('2867cadd-2904-482f-b43c-f77ce8412a93', 'Pulp Fiction', 'Quentin Tarantino', 1994, 'Crime', 8.9), ('8c06c70a-872e-49a7-8770-29355dcd05c6', 'The Dark Knight', 'Christopher Nolan', 2008, 'Action', 9.0);
2 changes: 1 addition & 1 deletion backend/nhost/nhost.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ httpPoolSize = 100
version = 20

[auth]
version = '0.38.1'
version = '0.40.1'

[auth.elevatedPrivileges]
mode = 'disabled'
Expand Down
1 change: 1 addition & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## main

- 20250704 feat (packages/nhost-js): added functions.post method and improve documentation #43
- 20250627 feat (packages/nhost-js): graphql.post -> graphql.request #41
- 20250624 feat (packages/nhost-js): add decoded token to session storage #37
- 20250623 fix (packages/nhost-js): added missing endpoints (storage) and baseURL (functions) #35
Expand Down
8 changes: 4 additions & 4 deletions docs/reference/javascript/nhost-js/.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

| Module | Description |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [auth](auth) | This is the main module to interact with Nhost's Auth service. Typically you would use this modula via the main [Nhost client](main#createclient) but you can also use it directly if you have a specific use case. |
| [auth](auth) | This is the main module to interact with Nhost's Auth service. Typically you would use this module via the main [Nhost client](main#createclient) but you can also use it directly if you have a specific use case. |
| [fetch](fetch) | Enhanced fetch implementation with middleware support. |
| [functions](functions) | This is the main module to interact with Nhost's Functions service. Typically you would use this modula via the main [Nhost client](main#createclient) but you can also use it directly if you have a specific use case. |
| [graphql](graphql) | This is the main module to interact with Nhost's GraphQL service. Typically you would use this modula via the main [Nhost client](main#createclient) but you can also use it directly if you have a specific use case. |
| [functions](functions) | This is the main module to interact with Nhost's Functions service. Typically you would use this module via the main [Nhost client](main#createclient) but you can also use it directly if you have a specific use case. |
| [graphql](graphql) | This is the main module to interact with Nhost's GraphQL service. Typically you would use this module via the main [Nhost client](main#createclient) but you can also use it directly if you have a specific use case. |
| [index](index) | Main entry point for the Nhost JavaScript SDK. |
| [session](session) | Session management module for Nhost authentication |
| [storage](storage) | This is the main module to interact with Nhost's Storage service. Typically you would use this modula via the main [Nhost client](main#createclient) but you can also use it directly if you have a specific use case. |
| [storage](storage) | This is the main module to interact with Nhost's Storage service. Typically you would use this module via the main [Nhost client](main#createclient) but you can also use it directly if you have a specific use case. |
80 changes: 64 additions & 16 deletions docs/reference/javascript/nhost-js/auth.mdx
Original file line number Diff line number Diff line change
@@ -1,36 +1,56 @@
This is the main module to interact with Nhost's Auth service.
Typically you would use this modula via the main [Nhost client](main#createclient)
Typically you would use this module via the main [Nhost client](main#createclient)
but you can also use it directly if you have a specific use case.

## Import

You can import and use this package with:

```ts
import { createClient } from "@nhost/nhost-js/auth";
```

## Usage

```ts
import { createClient } from "@nhost/nhost-js";

const nhost = createClient({
subdomain,
region,
});

await nhost.auth.signUpEmailPassword({
email,
password,
});
```

## Error handling

The SDK will throw errors in most operations if the request return a status >=400 or
if the request fails entirely (i.e., due to network errors). A continuation you can see
how you can handle errors thrown by the SDK when the status is >=400.
The SDK will throw errors in most operations if the request returns a status >=300 or
if the request fails entirely (i.e., due to network errors). The type of the error
will be a `FetchError<ErrorResponse>`:

```ts
// Needs the following imports:
//
// import {
// type ErrorResponse,
// } from "@nhost/nhost-js/auth";
// import {
// type FetchError,
// } from "@nhost/nhost-js/fetch";
//
import { createClient } from "@nhost/nhost-js";
import { FetchError } from "@nhost/nhost-js/fetch";

const nhost = createClient({
subdomain,
region,
});

try {
await nhost.auth.signInEmailPassword({
email,
password,
});
} catch (err) {
if (!(err instanceof FetchError)) {
throw err; // Re-throw if it's not a FetchError
}

expect(true).toBe(false); // This should not be reached
} catch (error) {
const err = error as FetchError<ErrorResponse>;
console.log("Error:", err);
// Error: {
// body: {
Expand All @@ -47,6 +67,34 @@ try {
// }

// error handling...
}
```

This type extends the standard `Error` type so if you want to just log the error you can
do so like this:

```ts
import { createClient } from "@nhost/nhost-js";
import { FetchError } from "@nhost/nhost-js/fetch";

const nhost = createClient({
subdomain,
region,
});

try {
await nhost.auth.signInEmailPassword({
email,
password,
});
} catch (err) {
if (!(err instanceof Error)) {
throw err; // Re-throw if it's not an Error
}

console.log("Error:", err.message);
// Error: Incorrect email or password
}
```

## Interfaces
Expand Down
168 changes: 137 additions & 31 deletions docs/reference/javascript/nhost-js/functions.mdx
Original file line number Diff line number Diff line change
@@ -1,56 +1,125 @@
This is the main module to interact with Nhost's Functions service.
Typically you would use this modula via the main [Nhost client](main#createclient)
Typically you would use this module via the main [Nhost client](main#createclient)
but you can also use it directly if you have a specific use case.

## Import

You can import and use this package with:

```ts
import { createClient } from "@nhost/nhost-js/functions";
```

## Usage

You can use this library by passing the path to the function you want to call and any body
or fetch options you want to apply (optional):

```ts
import { createClient } from "@nhost/nhost-js";

const nhost = createClient({
subdomain,
region,
});

const funcResp = await nhost.functions.post("/helloworld", {
message: "Hello, World!",
});
console.log(JSON.stringify(funcResp.body, null, 2));
// {
// "message": "Hello, World!"
// }
```

The post method above is a convenience method for executing a POST request with a JSON body.
For more generic requests, you can use the `fetch` method instead:

```ts
import { createClient } from "@nhost/nhost-js";

const nhost = createClient({
subdomain,
region,
});

const funcResp = await nhost.functions.fetch("/helloworld", {
method: "GET",
headers: {
Accept: "text/plain",
ContentType: "application/json",
},
});
console.log(funcResp.body);
// "Hello, World!"
```

## Error handling

The SDK will throw errors in most operations if the request return a status >=400 or
if the request fails entirely (i.e., due to network errors). A continuation you can see
how you can handle errors thrown by the SDK when the status is >=400.
The SDK will throw errors in most operations if the request returns a status >=300 or
if the request fails entirely (i.e., due to network errors). The type of the error
will be a `FetchError<T>`:

```ts
// Needs the following imports:
//
// import { FetchError } from "@nhost/nhost-js/fetch";
//
import { createClient } from "@nhost/nhost-js";
import { FetchError } from "@nhost/nhost-js/fetch";

const nhost = createClient({
subdomain,
region,
});

try {
await nhost.functions.fetch("/crash", {
method: "POST",
await nhost.functions.fetch("/helloworld", {
method: "GET",
headers: {
Accept: "application/json",
Accept: "application/octet-stream",
},
});
} catch (error) {
const resp = error as FetchError<string>;
console.log("Error:", resp);
if (!(error instanceof FetchError)) {
throw error; // Re-throw if it's not a FetchError
}

console.log("Error:", JSON.stringify(error, null, 2));
// Error: {
// status: 500,
// body: '<!DOCTYPE html>\n' +
// '<html lang="en">\n' +
// '<head>\n' +
// '<meta charset="utf-8">\n' +
// '<title>Error</title>\n' +
// '</head>\n' +
// '<body>\n' +
// '<pre>Error: This is an unhandled error<br> &nbsp; &nbsp;at default (/opt/project/functions/crash.ts:4:11)<br> &nbsp; &nbsp;at Layer.handle [as handle_request] (/usr/local/lib/node_modules/express/lib/router/layer.js:95:5)<br> &nbsp; &nbsp;at next (/usr/local/lib/node_modules/express/lib/router/route.js:144:13)<br> &nbsp; &nbsp;at next (/usr/local/lib/node_modules/express/lib/router/route.js:140:7)<br> &nbsp; &nbsp;at next (/usr/local/lib/node_modules/express/lib/router/route.js:140:7)<br> &nbsp; &nbsp;at next (/usr/local/lib/node_modules/express/lib/router/route.js:140:7)<br> &nbsp; &nbsp;at next (/usr/local/lib/node_modules/express/lib/router/route.js:140:7)<br> &nbsp; &nbsp;at next (/usr/local/lib/node_modules/express/lib/router/route.js:140:7)<br> &nbsp; &nbsp;at next (/usr/local/lib/node_modules/express/lib/router/route.js:140:7)<br> &nbsp; &nbsp;at next (/usr/local/lib/node_modules/express/lib/router/route.js:140:7)</pre>\n' +
// '</body>\n' +
// '</html>\n',
// headers: Headers {
// 'content-length': '1055',
// 'content-security-policy': "default-src 'none'",
// 'content-type': 'text/html; charset=utf-8',
// date: 'Tue, 13 May 2025 11:20:04 GMT',
// 'x-content-type-options': 'nosniff'
// }
// "body": "Unsupported Accept Header",
// "status": 400,
// "headers": {...}
// }
//
// error handling...
}
```

This type extends the standard `Error` type so if you want to just log the error you can
do so like this:

```ts
import { createClient } from "@nhost/nhost-js";
import { FetchError } from "@nhost/nhost-js/fetch";

const nhost = createClient({
subdomain,
region,
});

try {
await nhost.functions.fetch("/helloworld", {
method: "GET",
headers: {
Accept: "application/octet-stream",
},
});
} catch (error) {
if (!(error instanceof Error)) {
throw error; // Re-throw if it's not a FetchError
}

console.log("Error:", error.message);
// Error: Unsupported Accept Header
// error handling...
}
```

## Interfaces
Expand Down Expand Up @@ -101,6 +170,43 @@ The response body will be automatically parsed based on the content type into th

Promise with the function response and metadata.

##### post()

```ts
post<T>(
path: string,
body?: unknown,
options?: RequestInit): Promise<FetchResponse<T>>;
```

Executes a POST request to a serverless function with a JSON body

This is a convenience method assuming the request is a POST with JSON body
setting the `Content-Type` and 'Accept' headers to `application/json` and
automatically stringifying the body.

For a more generic request, use the `fetch` method instead.

###### Type Parameters

| Type Parameter | Default type |
| -------------- | ------------ |
| `T` | `any` |

###### Parameters

| Parameter | Type | Description |
| ---------- | ------------- | ------------------------------------------------ |
| `path` | `string` | The path to the serverless function |
| `body?` | `unknown` | The JSON body to send in the request |
| `options?` | `RequestInit` | Additional fetch options to apply to the request |

###### Returns

`Promise`&lt;[`FetchResponse`](fetch#fetchresponse)&lt;`T`&gt;&gt;

Promise with the function response and metadata

## Functions

### createAPIClient()
Expand Down
Loading