Build a RESTful tasks API with Functions and SQL Database
Create a database in SQL Database, write CRUD routes with Hono, and deploy a task API that runs as a function.
In this tutorial, you will build a RESTful tasks API that runs as a function and keeps its records in SQL Database. You will create the database and its table, write the data layer and the Hono routes, deploy the project with Azion CLI, and call every endpoint.
The finished project is the restful-tasks example on GitHub.
Prerequisites
- An Azion account. To create one, refer to How to create an account on Azion.
- Azion CLI installed. Refer to Azion CLI.
- A personal token for the API requests. To create one, refer to Personal tokens.
- Node.js version 18 or higher.
1. Create the database
The data layer addresses the database by name, and it falls back to tasks when no name is configured. Name the database tasks so that fallback resolves.
Send a POST request to the databases endpoint, replacing [TOKEN VALUE] with your personal token:
The response carries the identifier of the database and its status:
Record the id. Every request that follows addresses the database by that value.
2. Create the tasks table
The API stores one row per task, with a title, a completion flag, and two timestamps.
Both requests send a POST to the query endpoint. Replace <your-database-id> with the id of your database:
The response reports one result object per statement:
The endpoints need rows to return:
Three statements return three result objects:
The database holds the tasks table and three rows.
3. Create the project
Azion CLI scaffolds the project from a Hono template.
Run the login command and follow the prompts:
The CLI stores the credentials locally and authorizes every later command against your account.
Run the init command:
Accept the suggested name, or enter your own:
The CLI creates the project directory with the template source. The build, dev, and deploy commands run from inside it.
4. Write the data layer
The data layer calls useQuery and useExecute from the azion/sql library. Both take the database name first and an array of SQL statements second. For the full library surface, refer to Azion SQL library.
Replace the contents of src/db.ts:
The file exports one function per operation: getTasks, getTask, createTask, updateTask, and deleteTask. DATABASE_NAME falls back to tasks. To read a database under another name, set DATABASE_NAME in the .env file of the project.
5. Write the API routes
Hono binds each HTTP method and path to a handler. Every handler wraps its data call in a try block and returns 500 with a JSON error when the call throws.
Replace the contents of src/app.ts:
The file covers five routes:
| Method and path | Result |
|---|---|
GET /tasks | Returns every task as a JSON array. |
GET /tasks/:id | Returns one task, or 404 with { "error": "Task not found" }. |
POST /tasks | Creates a task from title and completed, and returns it with 201. |
PUT /tasks/:id | Updates title and completed, and returns the stored task. |
DELETE /tasks/:id | Removes the task and returns { "message": "Task deleted" }. |
6. Export the function handler
Azion runs the ES Modules handler: an object with a fetch method, exported as the default of the entry file. Hono supplies that method on the app instance. For the pattern and the legacy alternative it replaces, refer to Migrate handler patterns in Functions.
Replace the contents of src/index.ts:
The entry file exports the app, so every request reaches the Hono router, which matches it against the five routes.
7. Deploy the project
Run the deploy command from the project directory:
Azion opens Azion Console in the browser, where the deployment logs run until the build finishes. If the browser does not open, follow the link the CLI prints.
Azion builds the project and deploys it to the Azion Web Platform. The deployment returns a workload domain in the format https://xxxxxxx.map.azionedge.net. Propagation takes a few minutes, so wait before you send the first request.
8. Verify the endpoints
Replace <your-azion-domain> with the workload domain of the deployment.
The response carries the three rows inserted into the table:
The response carries a single object:
The response returns 201 with the stored task and the identifier the database assigned:
The response carries the task with the new values:
The response confirms the removal:
The API creates, reads, updates, and deletes tasks from the deployed function, and every write reaches the database.