├── .env ├── .gitignore ├── .vscode └── launch.json ├── CHANGELOG.md ├── Dockerfile ├── LICENSE ├── README.md ├── analysis_options.yaml ├── bin └── server.dart ├── docker-compose.yml ├── lib ├── app │ ├── http │ │ ├── controllers │ │ │ ├── auth │ │ │ │ └── auth_controller.dart │ │ │ ├── post │ │ │ │ └── post_controller.dart │ │ │ └── user │ │ │ │ └── user_controller.dart │ │ └── middleware │ │ │ ├── authenticate.dart │ │ │ ├── error_response_middleware.dart │ │ │ └── home_middleware.dart │ ├── models │ │ ├── post.dart │ │ └── user.dart │ └── providers │ │ └── route_service_povider.dart ├── config │ ├── app.dart │ ├── auth.dart │ ├── cros.dart │ └── database.dart ├── database │ └── migrations │ │ ├── create_personal_access_tokens_table.dart │ │ ├── create_posts_table.dart │ │ ├── create_user_table.dart │ │ └── migrate.dart └── route │ ├── api_route.dart │ └── vesion │ └── version1.dart ├── public └── .gitkeep ├── pubspec.lock ├── pubspec.yaml ├── storage └── app │ └── .gitkeep └── swagger.yaml /.env: -------------------------------------------------------------------------------- 1 | APP_NAME='example' 2 | APP_ENV=local 3 | APP_KEY='eMfNAw9L3BtUZ0C5GwI_BCK4wSOU_oSdbsHGU5NdVOI=' 4 | APP_HOST=127.0.0.1 5 | APP_PORT=8000 6 | APP_SHARED=true 7 | APP_DEBUG=true 8 | APP_URL='http://localhost:8000' 9 | APP_SECURE=false 10 | APP_CERTIFICATE=null 11 | APP_PRIVATE_KEY=null 12 | APP_PRIVATE_KEY_PASSWORD=null 13 | APP_WEBSOCKET=false 14 | 15 | 16 | ISOLATE=false 17 | ISOLATE_NUMBER=1 18 | 19 | 20 | DB_CONNECTION=mysql 21 | DB_HOST=localhost 22 | DB_PORT=3306 23 | DB_DATABASE=vania 24 | DB_USERNAME=root 25 | DB_PASSWORD=passord 26 | DB_SSLMODE=false 27 | 28 | 29 | MAIL_MAILER=smtp 30 | MAIL_HOST=127.0.0.1 31 | MAIL_PORT=465 32 | MAIL_ENCRYPTION=ssl 33 | MAIL_USERNAME=username@local.com 34 | MAIL_PASSWORD=password 35 | MAIL_FROM_ADDRESS=username@local.com 36 | MAIL_FROM_NAME="blog" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # https://dart.dev/guides/libraries/private-files 2 | # Created by `dart pub` 3 | .dart_tool/ 4 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "example", 9 | "request": "launch", 10 | "type": "dart" 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.0 2 | 3 | - Initial version. 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Use latest stable channel SDK. 2 | FROM dart:stable AS build 3 | 4 | 5 | # Install the Vania cli from pub.dev 6 | RUN dart pub global activate vania_cli 7 | 8 | # Resolve app dependencies. 9 | WORKDIR /www 10 | 11 | 12 | # Copy app source code (except anything in .dockerignore) and AOT compile app. 13 | COPY . . 14 | 15 | 16 | # Get dependencies 17 | RUN dart pub get 18 | 19 | # 📦 Create a production build 20 | RUN vania build 21 | 22 | # Build minimal serving image from AOT-compiled `/server` 23 | # and the pre-built AOT-runtime in the `/runtime/` directory of the base image. 24 | FROM scratch 25 | COPY --from=build /runtime/ / 26 | COPY --from=build /www/bin/server /bin/ 27 | 28 | # Expose the server port (useful for binding) 29 | EXPOSE 8000 30 | 31 | # Start server. 32 | CMD ["/bin/server"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Vania 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vania Example Project 2 | 3 | ## Getting Started 4 | 5 | Clone this repository: 6 | 7 | ```shell 8 | git clone https://github.com/vania-dart/example.git 9 | ``` 10 | 11 | ### Configure Your Database 12 | 13 | In `config/database.dart`, replace your database credentials: 14 | 15 | ```dart 16 | DatabaseConfig databaseConfig = DatabaseConfig( 17 | driver: MysqlDriver(), 18 | host: '127.0.0.1', // Your server address 19 | database: 'MyDb', // Database name 20 | username: 'root', // Username 21 | password: 'Password', // Password 22 | port: 3306, 23 | sslmode: false, 24 | ); 25 | ``` 26 | 27 | ## Migrate Your Tables 28 | 29 | Run `vania migrate`. 30 | 31 | ## Serve 32 | 33 | Run `vania serve`. 34 | 35 | Enjoy! 36 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the static analysis results for your project (errors, 2 | # warnings, and lints). 3 | # 4 | # This enables the 'recommended' set of lints from `package:lints`. 5 | # This set helps identify many issues that may lead to problems when running 6 | # or consuming Dart code, and enforces writing Dart using a single, idiomatic 7 | # style and format. 8 | # 9 | # If you want a smaller set of lints you can change this to specify 10 | # 'package:lints/core.yaml'. These are just the most critical lints 11 | # (the recommended set includes the core lints). 12 | # The core lints are also what is used by pub.dev for scoring packages. 13 | 14 | include: package:lints/recommended.yaml 15 | 16 | # Uncomment the following section to specify additional rules. 17 | 18 | # linter: 19 | # rules: 20 | # - camel_case_types 21 | 22 | # analyzer: 23 | # exclude: 24 | # - path/to/excluded/files/** 25 | 26 | # For more information about the core and recommended set of lints, see 27 | # https://dart.dev/go/core-lints 28 | 29 | # For additional information about configuring this file, see 30 | # https://dart.dev/guides/language/analysis-options 31 | -------------------------------------------------------------------------------- /bin/server.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/config/app.dart'; 2 | import 'package:vania/vania.dart'; 3 | 4 | void main() async { 5 | Application().initialize(config: config); 6 | } 7 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | app: 5 | build: . 6 | image: app 7 | container_name: app 8 | restart: always 9 | working_dir: /www 10 | volumes: 11 | - .:/www 12 | ports: 13 | - 8000:8000 14 | 15 | 16 | mysql: 17 | image: mysql:latest 18 | restart: always 19 | environment: 20 | - MYSQL_ROOT_PASSWORD=123456 #Database root password 21 | - MYSQL_DATABASE=MyDB #Database name 22 | - MYSQL_USER=DBUser #Database user 23 | - MYSQL_PASSWORD=123456 #Database password 24 | ports: 25 | - 3306:3306 26 | volumes: 27 | - $PWD/mysql:/var/lib/mysql -------------------------------------------------------------------------------- /lib/app/http/controllers/auth/auth_controller.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:example/app/models/user.dart'; 4 | import 'package:vania/vania.dart'; 5 | 6 | class AuthController extends Controller { 7 | /// Login 8 | Future login(Request request) async { 9 | request.validate({ 10 | 'email': 'required|email', 11 | 'password': 'required', 12 | }, { 13 | 'email.required': 'The email is required', 14 | 'email.email': 'The email is not valid', 15 | 'password.required': 'The password is required', 16 | }); 17 | 18 | String email = request.input('email'); 19 | String password = request.input('password').toString(); 20 | 21 | final user = await User().query().where('email', email).first(); 22 | 23 | if (user == null) { 24 | return Response.json({'message': 'User not found'}); 25 | } 26 | 27 | if (!Hash().passwordVerify(password, user['password'])) { 28 | return Response.json({'message': 'Wrong password'}); 29 | } 30 | 31 | // If you have guard and multi access like user and admin you can pass the guard Auth().guard('admin') 32 | Map token = await Auth() 33 | .login(user) 34 | .createToken(expiresIn: Duration(hours: 24), withRefreshToken: true); 35 | 36 | return Response.json(token); 37 | } 38 | 39 | /// Creating new user 40 | Future signUp(Request request) async { 41 | request.validate({ 42 | 'first_name': 'required|max_length:20|min_length:2', 43 | 'last_name': 'required|max_length:20', 44 | 'email': 'required|email', 45 | 'password': 'required', 46 | }, { 47 | 'first_name.required': 'The first name is required', 48 | 'first_name.max_length': 'The first name must be less than 20 characters', 49 | 'first_name.min_length': 'The first name must be at least 2 characters', 50 | 'last_name.required': 'The last name is required', 51 | 'last_name.max_length': 'The last name must be less than 20 characters', 52 | 'email.required': 'The email is required', 53 | 'email.email': 'The email is not valid', 54 | 'password.required': 'The password is required', 55 | }); 56 | 57 | /// Checking if the user already exists 58 | Map? user = await User() 59 | .query() 60 | .where('email', '=', request.input('email')) 61 | .first(); 62 | if (user != null) { 63 | return Response.json({'message': 'User already exists'}); 64 | } 65 | 66 | await User().query().insert({ 67 | 'first_name': request.input('first_name'), 68 | 'last_name': request.input('last_name'), 69 | 'email': request.input('email'), 70 | 'password': Hash().passwordHash(request.input('password').toString()), 71 | 'created_at': DateTime.now(), 72 | 'updated_at': DateTime.now(), 73 | }); 74 | 75 | return Response.json({'message': 'User created successfully'}); 76 | } 77 | 78 | Future otp(Request request) { 79 | Random rnd = Random(); 80 | int otp = rnd.nextInt(999999 - 111111); 81 | 82 | Cache.put('otp', otp.toString(), duration: Duration(minutes: 3)); 83 | 84 | return Response.json({'message': 'OTP sent successfully'}); 85 | } 86 | 87 | Future verifyOTO(Request request) async { 88 | String otp = request.input('otp'); 89 | final otpValue = Cache.get('otp'); 90 | 91 | if (otpValue == otp) { 92 | Cache.delete('otp'); 93 | return Response.json({'message': 'OTP verified successfully'}); 94 | } else { 95 | return Response.json( 96 | {'message': 'Invalid OTP'}, 97 | 400, 98 | ); 99 | } 100 | } 101 | 102 | /// Generating a new token if the accessToken is expired 103 | Future refreshToken(Request request) { 104 | final newToken = Auth().createTokenByRefreshToken( 105 | request.header('Authorization')!, 106 | expiresIn: Duration(hours: 24)); 107 | return Response.json(newToken); 108 | } 109 | } 110 | 111 | final AuthController authController = AuthController(); 112 | -------------------------------------------------------------------------------- /lib/app/http/controllers/post/post_controller.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/app/models/post.dart'; 2 | import 'package:vania/vania.dart'; 3 | 4 | class PostController extends Controller { 5 | // Fetch all posts 6 | Future index() async { 7 | List> posts = await Post() 8 | .query() 9 | .select([ 10 | 'users.first_name', 11 | 'users.last_name', 12 | 'posts.text', 13 | 'posts.id', 14 | ]) 15 | .join('users', 'users.id', '=', 'posts.user_id') 16 | .get(); 17 | 18 | return Response.json({'data': posts}); 19 | } 20 | 21 | /// Create new post 22 | Future create(Request request) async { 23 | request.validate({ 24 | 'text': 'required', 25 | }, { 26 | 'text.required': 'The text is required', 27 | }); 28 | 29 | await Post().query().insert({ 30 | 'text': request.input('text'), 31 | 'user_id': Auth().id(), 32 | }); 33 | 34 | return Response.json({'message': 'Post created successfully'}); 35 | } 36 | } 37 | 38 | final PostController postController = PostController(); 39 | -------------------------------------------------------------------------------- /lib/app/http/controllers/user/user_controller.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:vania/vania.dart'; 4 | 5 | import '../../../models/user.dart'; 6 | 7 | class UserController extends Controller { 8 | /// Fetch user details 9 | Future index() async { 10 | Map? details = 11 | await User().query().where('id', '=', Auth().id()).first(); 12 | 13 | return Response.json(details); 14 | } 15 | 16 | /// Update curent user details 17 | Future update(Request request) async { 18 | request.validate({ 19 | 'first_name': 'required|max_length:20|min_length:2', 20 | 'last_name': 'required|max_length:20', 21 | 'email': 'required|email', 22 | 'avatar': 'file:jpg,jpeg,png', 23 | }, { 24 | 'first_name.required': 'The first name is required', 25 | 'first_name.max_length': 'The first name must be less than 20 characters', 26 | 'first_name.min_length': 'The first name must be at least 2 characters', 27 | 'last_name.required': 'The last name is required', 28 | 'last_name.max_length': 'The last name must be less than 20 characters', 29 | 'email.required': 'The email is required', 30 | 'email.email': 'The email is not valid', 31 | 'avatar.file': 'The avatar must be an image file', 32 | }); 33 | 34 | /// Upload avtar if is sent 35 | RequestFile? avatar = request.file('avatar'); 36 | String avatarPath = ''; 37 | 38 | // If you have guard you can get user id by guard ex: Auth().guard('admin').id() 39 | if (avatar != null) { 40 | /// The file will be stored in the storage/app/public/user/user_id folder 41 | avatarPath = await avatar.store( 42 | path: 'users/${Auth().id()}', filename: avatar.filename); 43 | } 44 | 45 | await User().query().where('id', '=', Auth().id()).update({ 46 | 'first_name': request.input('first_name'), 47 | 'last_name': request.input('last_name'), 48 | 'email': request.input('email'), 49 | 'avatar': avatarPath, 50 | }); 51 | 52 | return Response.json({'message': 'User updated successfully'}); 53 | } 54 | } 55 | 56 | final UserController userController = UserController(); 57 | -------------------------------------------------------------------------------- /lib/app/http/middleware/authenticate.dart: -------------------------------------------------------------------------------- 1 | import 'package:vania/vania.dart'; 2 | 3 | class AuthenticateMiddleware extends Authenticate {} 4 | -------------------------------------------------------------------------------- /lib/app/http/middleware/error_response_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'package:vania/vania.dart'; 2 | 3 | class ErrorResponseMiddleware extends Middleware { 4 | @override 5 | handle(Request req) async { 6 | if(req.header('content-type') != 'application/json') { 7 | abort(400,'Your request is not valid'); 8 | } 9 | next?.handle(req); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lib/app/http/middleware/home_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'package:vania/vania.dart'; 2 | 3 | class HomeMiddleware extends Middleware { 4 | @override 5 | handle(Request req) async { 6 | next?.handle(req); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lib/app/models/post.dart: -------------------------------------------------------------------------------- 1 | import 'package:vania/vania.dart'; 2 | 3 | class Post extends Model { 4 | Post() { 5 | super.table('posts'); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /lib/app/models/user.dart: -------------------------------------------------------------------------------- 1 | import 'package:vania/vania.dart'; 2 | 3 | class User extends Model { 4 | User() { 5 | super.table('users'); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /lib/app/providers/route_service_povider.dart: -------------------------------------------------------------------------------- 1 | import 'package:vania/vania.dart'; 2 | import 'package:example/route/api_route.dart'; 3 | 4 | class RouteServiceProvider extends ServiceProvider { 5 | @override 6 | Future boot() async {} 7 | 8 | @override 9 | Future register() async { 10 | ApiRoute().register(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/config/app.dart: -------------------------------------------------------------------------------- 1 | import 'package:vania/vania.dart'; 2 | import 'package:example/app/providers/route_service_povider.dart'; 3 | 4 | import 'auth.dart'; 5 | import 'cros.dart'; 6 | import 'database.dart'; 7 | 8 | Map config = { 9 | 'name': env('APP_NAME'), 10 | 'url': env('APP_URL'), 11 | 'timezone': '', 12 | 'websocket': false, 13 | 'isolate': false, 14 | 'isolateCount': 4, 15 | 'cors': cors, 16 | 'database': null, //databaseConfig, Put Your Databse config here 17 | 'cache': CacheConfig(), 18 | 'auth': authConfig, 19 | 'storage': FileStorageConfig(), 20 | 'mail': { 21 | 'driver': env('MAIL_MAILER'), 22 | 'host': env('MAIL_HOST'), 23 | 'port': env('MAIL_PORT'), 24 | 'username': env('MAIL_USERNAME'), 25 | 'password': env('MAIL_PASSWORD'), 26 | 'encryption': env('MAIL_ENCRYPTION'), 27 | 'from_name': env('MAIL_FROM_NAME'), 28 | 'from_address': env('MAIL_FROM_ADDRESS'), 29 | }, 30 | 'providers': [ 31 | RouteServiceProvider(), 32 | ], 33 | }; 34 | -------------------------------------------------------------------------------- /lib/config/auth.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/app/models/user.dart'; 2 | 3 | Map authConfig = { 4 | 'guards': { 5 | 'default': { 6 | 'provider': User(), 7 | } 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /lib/config/cros.dart: -------------------------------------------------------------------------------- 1 | import 'package:vania/vania.dart'; 2 | 3 | CORSConfig cors = CORSConfig( 4 | /// Enabled 5 | /// ------------------------------- 6 | /// A boolean to enable or disable CORS integration. 7 | /// Setting to true will enable the CORS for all HTTP request. 8 | enabled: true, 9 | 10 | /// Origin 11 | /// ------------------------------- 12 | /// Set a list of origins to be allowed for `Access-Control-Allow-Origin`. 13 | /// The value can be one of the following: 14 | /// Array : An array of allowed origins. 15 | /// String : Comma separated list of allowed origins. 16 | /// String (*) : A wildcard (*) to allow all request origins. 17 | origin: '*', 18 | 19 | /// Methods 20 | /// ------------------------------- 21 | /// Set a list of origins to be allowed for `Access-Control-Request-Method`. 22 | /// The value can be one of the following: 23 | /// Array : An array of request methods. 24 | /// String : Comma separated list of request methods. 25 | /// String (*) : A wildcard (*) to allow all request methods. 26 | methods: '*', 27 | 28 | /// Headers 29 | /// ------------------------------- 30 | /// Set a list of origins to be allowed for `Access-Control-Allow-Headers`. 31 | /// The value can be one of the following: 32 | /// Array : An array of allowed headers. 33 | /// String : Comma separated list of allowed headers. 34 | /// String (*) : A wildcard (*) to allow all request headers. 35 | headers: '*', 36 | 37 | /// Expose Headers 38 | /// ------------------------------- 39 | /// Set a list of origins to be allowed for `Access-Control-Expose-Headers`. 40 | /// The value can be one of the following: 41 | /// Array : An array of expose headers. 42 | /// String : Comma separated list of expose headers. 43 | exposeHeaders: [ 44 | 'cache-control', 45 | 'content-language', 46 | 'content-type', 47 | 'expires', 48 | 'last-modified', 49 | 'pragma', 50 | ], 51 | 52 | /// Credentials 53 | /// ------------------------------- 54 | /// Toggle `Access-Control-Allow-Credentials` header. 55 | credentials: true, 56 | 57 | /// MaxAge 58 | /// ------------------------------- 59 | /// Define `Access-Control-Max-Age` header in seconds. 60 | maxAge: 90, 61 | ); 62 | -------------------------------------------------------------------------------- /lib/config/database.dart: -------------------------------------------------------------------------------- 1 | import 'package:vania/vania.dart'; 2 | 3 | DatabaseConfig databaseConfig = DatabaseConfig( 4 | driver: MysqlDriver(), 5 | host: env('DB_HOST'), 6 | port: env('DB_PORT'), 7 | database: env('DB_DATABASE'), 8 | username: env('DB_USERNAME'), 9 | password: env('DB_PASSWORD'), 10 | sslmode: env('DB_SSLMODE',false), 11 | ); 12 | -------------------------------------------------------------------------------- /lib/database/migrations/create_personal_access_tokens_table.dart: -------------------------------------------------------------------------------- 1 | import 'package:vania/vania.dart'; 2 | 3 | class CreatePersonalAccessTokensTable extends Migration { 4 | @override 5 | Future up() async { 6 | super.up(); 7 | await createTableNotExists('personal_access_tokens', () { 8 | id(); 9 | tinyText('name'); 10 | bigInt('tokenable_id'); 11 | string('token'); 12 | timeStamp('last_used_at', nullable: true); 13 | timeStamp('created_at', nullable: true); 14 | timeStamp('deleted_at', nullable: true); 15 | 16 | index(ColumnIndex.unique, 'token', ['token']); 17 | }); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/database/migrations/create_posts_table.dart: -------------------------------------------------------------------------------- 1 | import 'package:vania/vania.dart'; 2 | 3 | class CreatePostsTable extends Migration { 4 | @override 5 | Future up() async { 6 | super.up(); 7 | await createTable('posts', () { 8 | id(); 9 | bigInt('user_id', unsigned: true); 10 | longText('text', nullable: true); 11 | timeStamp('created_at', nullable: true); 12 | timeStamp('updated_at', nullable: true); 13 | timeStamp('deleted_at', nullable: true); 14 | foreign('user_id', 'users', 'id', constrained: true, onDelete: 'CASCADE'); 15 | }); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/database/migrations/create_user_table.dart: -------------------------------------------------------------------------------- 1 | import 'package:vania/vania.dart'; 2 | 3 | class CreateUserTable extends Migration { 4 | @override 5 | Future up() async { 6 | super.up(); 7 | await createTable('users', () { 8 | id(); 9 | string('first_name', length: 20); 10 | string('last_name', length: 20); 11 | string('email', length: 50); 12 | string('password'); 13 | string('avatar', nullable: true); 14 | timeStamp('created_at', nullable: true); 15 | timeStamp('updated_at', nullable: true); 16 | timeStamp('deleted_at', nullable: true); 17 | 18 | index(ColumnIndex.unique, 'email', ['email']); 19 | }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/database/migrations/migrate.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:vania/vania.dart'; 3 | import '../../config/database.dart'; 4 | import 'create_user_table.dart'; 5 | import 'create_posts_table.dart'; 6 | import 'create_personal_access_tokens_table.dart'; 7 | 8 | void main() async { 9 | Env().load(); 10 | await Migrate().registry(); 11 | await MigrationConnection().closeConnection(); 12 | exit(0); 13 | } 14 | 15 | class Migrate { 16 | registry() async{ 17 | await MigrationConnection().setup(databaseConfig); 18 | await CreateUserTable().up(); 19 | await CreatePostsTable().up(); 20 | await CreatePersonalAccessTokensTable().up(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/route/api_route.dart: -------------------------------------------------------------------------------- 1 | import 'package:vania/vania.dart'; 2 | 3 | import 'vesion/version1.dart'; 4 | 5 | class ApiRoute implements Route { 6 | @override 7 | void register() { 8 | Version1().register(); 9 | 10 | Router.get('/', () { 11 | return Response.html( 12 | 'Hello World, welcome to Fullstack development with Vania'); 13 | }); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/route/vesion/version1.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/app/http/controllers/post/post_controller.dart'; 2 | import 'package:example/app/http/middleware/authenticate.dart'; 3 | import 'package:example/app/http/middleware/error_response_middleware.dart'; 4 | import 'package:vania/vania.dart'; 5 | 6 | import '../../app/http/controllers/auth/auth_controller.dart'; 7 | import '../../app/http/controllers/user/user_controller.dart'; 8 | 9 | class Version1 extends Route { 10 | @override 11 | void register() { 12 | Router.basePrefix('api/v1'); 13 | 14 | /// Authentication Routes 15 | Router.post('login', authController.login); 16 | Router.post('sign-up', authController.signUp); 17 | Router.post('refresh-token', authController.refreshToken); 18 | 19 | Router.get('wrong-request', () => Response.json({})).middleware([ErrorResponseMiddleware()]); 20 | 21 | Router.group( 22 | () { 23 | Router.get('details', userController.index); 24 | Router.patch('update', userController.update); 25 | }, 26 | prefix: 'user', 27 | middleware: [AuthenticateMiddleware()], 28 | ); 29 | 30 | Router.group( 31 | () { 32 | Router.get('all', postController.index); 33 | Router.post('create', postController.create); 34 | }, 35 | prefix: 'post', 36 | middleware: [AuthenticateMiddleware()], 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /public/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vania-dart/example/20a985b24ca160e60ef3ce72835d0cf0ba13caa2/public/.gitkeep -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | _fe_analyzer_shared: 5 | dependency: transitive 6 | description: 7 | name: _fe_analyzer_shared 8 | sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" 9 | url: "https://pub.flutter-io.cn" 10 | source: hosted 11 | version: "67.0.0" 12 | adaptive_number: 13 | dependency: transitive 14 | description: 15 | name: adaptive_number 16 | sha256: "3a567544e9b5c9c803006f51140ad544aedc79604fd4f3f2c1380003f97c1d77" 17 | url: "https://pub.flutter-io.cn" 18 | source: hosted 19 | version: "1.0.0" 20 | analyzer: 21 | dependency: transitive 22 | description: 23 | name: analyzer 24 | sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" 25 | url: "https://pub.flutter-io.cn" 26 | source: hosted 27 | version: "6.4.1" 28 | args: 29 | dependency: transitive 30 | description: 31 | name: args 32 | sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 33 | url: "https://pub.flutter-io.cn" 34 | source: hosted 35 | version: "2.4.2" 36 | async: 37 | dependency: transitive 38 | description: 39 | name: async 40 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 41 | url: "https://pub.flutter-io.cn" 42 | source: hosted 43 | version: "2.11.0" 44 | boolean_selector: 45 | dependency: transitive 46 | description: 47 | name: boolean_selector 48 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 49 | url: "https://pub.flutter-io.cn" 50 | source: hosted 51 | version: "2.1.1" 52 | buffer: 53 | dependency: transitive 54 | description: 55 | name: buffer 56 | sha256: "94f60815065a8f0fd4f05be51faf86cf86519327e039d5c2aac72e1d1cc1dad4" 57 | url: "https://pub.flutter-io.cn" 58 | source: hosted 59 | version: "1.2.2" 60 | charcode: 61 | dependency: transitive 62 | description: 63 | name: charcode 64 | sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306 65 | url: "https://pub.flutter-io.cn" 66 | source: hosted 67 | version: "1.3.1" 68 | clock: 69 | dependency: transitive 70 | description: 71 | name: clock 72 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 73 | url: "https://pub.flutter-io.cn" 74 | source: hosted 75 | version: "1.1.1" 76 | collection: 77 | dependency: transitive 78 | description: 79 | name: collection 80 | sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a 81 | url: "https://pub.flutter-io.cn" 82 | source: hosted 83 | version: "1.18.0" 84 | convert: 85 | dependency: transitive 86 | description: 87 | name: convert 88 | sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" 89 | url: "https://pub.flutter-io.cn" 90 | source: hosted 91 | version: "3.1.1" 92 | coverage: 93 | dependency: transitive 94 | description: 95 | name: coverage 96 | sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76" 97 | url: "https://pub.flutter-io.cn" 98 | source: hosted 99 | version: "1.7.2" 100 | crypto: 101 | dependency: transitive 102 | description: 103 | name: crypto 104 | sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab 105 | url: "https://pub.flutter-io.cn" 106 | source: hosted 107 | version: "3.0.3" 108 | dargres: 109 | dependency: transitive 110 | description: 111 | name: dargres 112 | sha256: a7a6e21c5cebb183bc1b94035e1078dfd5f6bfa2ceb8c12b0e668fa679b755e1 113 | url: "https://pub.flutter-io.cn" 114 | source: hosted 115 | version: "3.0.2" 116 | dart_jsonwebtoken: 117 | dependency: transitive 118 | description: 119 | name: dart_jsonwebtoken 120 | sha256: "40dc3a4788c02a44bc97ea0c8c4a078ae58c9a45acc2312ee6a689b0e8f5b5b9" 121 | url: "https://pub.flutter-io.cn" 122 | source: hosted 123 | version: "2.13.0" 124 | ed25519_edwards: 125 | dependency: transitive 126 | description: 127 | name: ed25519_edwards 128 | sha256: "6ce0112d131327ec6d42beede1e5dfd526069b18ad45dcf654f15074ad9276cd" 129 | url: "https://pub.flutter-io.cn" 130 | source: hosted 131 | version: "0.3.1" 132 | eloquent: 133 | dependency: transitive 134 | description: 135 | name: eloquent 136 | sha256: b827e5d33ebf18b9ecb8e011253174a456a444fab945da4cde7c63aeed9c39a8 137 | url: "https://pub.flutter-io.cn" 138 | source: hosted 139 | version: "3.1.2" 140 | enough_convert: 141 | dependency: transitive 142 | description: 143 | name: enough_convert 144 | sha256: c67d85ca21aaa0648f155907362430701db41f7ec8e6501a58ad9cd9d8569d01 145 | url: "https://pub.flutter-io.cn" 146 | source: hosted 147 | version: "1.6.0" 148 | file: 149 | dependency: transitive 150 | description: 151 | name: file 152 | sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" 153 | url: "https://pub.flutter-io.cn" 154 | source: hosted 155 | version: "7.0.0" 156 | fixnum: 157 | dependency: transitive 158 | description: 159 | name: fixnum 160 | sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" 161 | url: "https://pub.flutter-io.cn" 162 | source: hosted 163 | version: "1.1.0" 164 | frontend_server_client: 165 | dependency: transitive 166 | description: 167 | name: frontend_server_client 168 | sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" 169 | url: "https://pub.flutter-io.cn" 170 | source: hosted 171 | version: "3.2.0" 172 | glob: 173 | dependency: transitive 174 | description: 175 | name: glob 176 | sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" 177 | url: "https://pub.flutter-io.cn" 178 | source: hosted 179 | version: "2.1.2" 180 | http_multi_server: 181 | dependency: transitive 182 | description: 183 | name: http_multi_server 184 | sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" 185 | url: "https://pub.flutter-io.cn" 186 | source: hosted 187 | version: "3.2.1" 188 | http_parser: 189 | dependency: transitive 190 | description: 191 | name: http_parser 192 | sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" 193 | url: "https://pub.flutter-io.cn" 194 | source: hosted 195 | version: "4.0.2" 196 | intl: 197 | dependency: transitive 198 | description: 199 | name: intl 200 | sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf 201 | url: "https://pub.flutter-io.cn" 202 | source: hosted 203 | version: "0.19.0" 204 | io: 205 | dependency: transitive 206 | description: 207 | name: io 208 | sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" 209 | url: "https://pub.flutter-io.cn" 210 | source: hosted 211 | version: "1.0.4" 212 | js: 213 | dependency: transitive 214 | description: 215 | name: js 216 | sha256: "4186c61b32f99e60f011f7160e32c89a758ae9b1d0c6d28e2c02ef0382300e2b" 217 | url: "https://pub.flutter-io.cn" 218 | source: hosted 219 | version: "0.7.0" 220 | lints: 221 | dependency: "direct dev" 222 | description: 223 | name: lints 224 | sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" 225 | url: "https://pub.flutter-io.cn" 226 | source: hosted 227 | version: "2.1.1" 228 | logging: 229 | dependency: transitive 230 | description: 231 | name: logging 232 | sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" 233 | url: "https://pub.flutter-io.cn" 234 | source: hosted 235 | version: "1.2.0" 236 | mailer: 237 | dependency: transitive 238 | description: 239 | name: mailer 240 | sha256: d25d89555c1031abacb448f07b801d7c01b4c21d4558e944b12b64394c84a3cb 241 | url: "https://pub.flutter-io.cn" 242 | source: hosted 243 | version: "6.1.0" 244 | matcher: 245 | dependency: transitive 246 | description: 247 | name: matcher 248 | sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb 249 | url: "https://pub.flutter-io.cn" 250 | source: hosted 251 | version: "0.12.16+1" 252 | meta: 253 | dependency: transitive 254 | description: 255 | name: meta 256 | sha256: "25dfcaf170a0190f47ca6355bdd4552cb8924b430512ff0cafb8db9bd41fe33b" 257 | url: "https://pub.flutter-io.cn" 258 | source: hosted 259 | version: "1.14.0" 260 | mime: 261 | dependency: transitive 262 | description: 263 | name: mime 264 | sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" 265 | url: "https://pub.flutter-io.cn" 266 | source: hosted 267 | version: "1.0.5" 268 | mysql_client: 269 | dependency: transitive 270 | description: 271 | name: mysql_client 272 | sha256: "6a0fdcbe3e0721c637f97ad24649be2f70dbce2b21ede8f962910e640f753fc2" 273 | url: "https://pub.flutter-io.cn" 274 | source: hosted 275 | version: "0.0.27" 276 | node_preamble: 277 | dependency: transitive 278 | description: 279 | name: node_preamble 280 | sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" 281 | url: "https://pub.flutter-io.cn" 282 | source: hosted 283 | version: "2.0.2" 284 | package_config: 285 | dependency: transitive 286 | description: 287 | name: package_config 288 | sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" 289 | url: "https://pub.flutter-io.cn" 290 | source: hosted 291 | version: "2.1.0" 292 | path: 293 | dependency: transitive 294 | description: 295 | name: path 296 | sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" 297 | url: "https://pub.flutter-io.cn" 298 | source: hosted 299 | version: "1.9.0" 300 | pedantic: 301 | dependency: transitive 302 | description: 303 | name: pedantic 304 | sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602" 305 | url: "https://pub.flutter-io.cn" 306 | source: hosted 307 | version: "1.11.1" 308 | pointycastle: 309 | dependency: transitive 310 | description: 311 | name: pointycastle 312 | sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" 313 | url: "https://pub.flutter-io.cn" 314 | source: hosted 315 | version: "3.7.4" 316 | pool: 317 | dependency: transitive 318 | description: 319 | name: pool 320 | sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" 321 | url: "https://pub.flutter-io.cn" 322 | source: hosted 323 | version: "1.5.1" 324 | postgres: 325 | dependency: transitive 326 | description: 327 | name: postgres 328 | sha256: bd1df6d2f4ad71aef92dc59e867e3ba9ec22cf2212a81cf9d35aa061ce80b1ae 329 | url: "https://pub.flutter-io.cn" 330 | source: hosted 331 | version: "3.2.0" 332 | postgres_fork: 333 | dependency: transitive 334 | description: 335 | name: postgres_fork 336 | sha256: "22106441d56d298b902b49b041e2ee6bb053f31d5ef0a7a022bc52f371bb8607" 337 | url: "https://pub.flutter-io.cn" 338 | source: hosted 339 | version: "2.7.0" 340 | pub_semver: 341 | dependency: transitive 342 | description: 343 | name: pub_semver 344 | sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" 345 | url: "https://pub.flutter-io.cn" 346 | source: hosted 347 | version: "2.1.4" 348 | sasl_scram: 349 | dependency: transitive 350 | description: 351 | name: sasl_scram 352 | sha256: a47207a436eb650f8fdcf54a2e2587b850dc3caef9973ce01f332b07a6fc9cb9 353 | url: "https://pub.flutter-io.cn" 354 | source: hosted 355 | version: "0.1.1" 356 | saslprep: 357 | dependency: transitive 358 | description: 359 | name: saslprep 360 | sha256: "79c9e163a82f55da542feaf0f7a59031e74493299c92008b2b404cd88d639bb4" 361 | url: "https://pub.flutter-io.cn" 362 | source: hosted 363 | version: "1.0.2" 364 | shelf: 365 | dependency: transitive 366 | description: 367 | name: shelf 368 | sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 369 | url: "https://pub.flutter-io.cn" 370 | source: hosted 371 | version: "1.4.1" 372 | shelf_packages_handler: 373 | dependency: transitive 374 | description: 375 | name: shelf_packages_handler 376 | sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" 377 | url: "https://pub.flutter-io.cn" 378 | source: hosted 379 | version: "3.0.2" 380 | shelf_static: 381 | dependency: transitive 382 | description: 383 | name: shelf_static 384 | sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e 385 | url: "https://pub.flutter-io.cn" 386 | source: hosted 387 | version: "1.1.2" 388 | shelf_web_socket: 389 | dependency: transitive 390 | description: 391 | name: shelf_web_socket 392 | sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" 393 | url: "https://pub.flutter-io.cn" 394 | source: hosted 395 | version: "1.0.4" 396 | source_map_stack_trace: 397 | dependency: transitive 398 | description: 399 | name: source_map_stack_trace 400 | sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" 401 | url: "https://pub.flutter-io.cn" 402 | source: hosted 403 | version: "2.1.1" 404 | source_maps: 405 | dependency: transitive 406 | description: 407 | name: source_maps 408 | sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" 409 | url: "https://pub.flutter-io.cn" 410 | source: hosted 411 | version: "0.10.12" 412 | source_span: 413 | dependency: transitive 414 | description: 415 | name: source_span 416 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 417 | url: "https://pub.flutter-io.cn" 418 | source: hosted 419 | version: "1.10.0" 420 | sprintf: 421 | dependency: transitive 422 | description: 423 | name: sprintf 424 | sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" 425 | url: "https://pub.flutter-io.cn" 426 | source: hosted 427 | version: "7.0.0" 428 | stack_trace: 429 | dependency: transitive 430 | description: 431 | name: stack_trace 432 | sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" 433 | url: "https://pub.flutter-io.cn" 434 | source: hosted 435 | version: "1.11.1" 436 | stream_channel: 437 | dependency: transitive 438 | description: 439 | name: stream_channel 440 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 441 | url: "https://pub.flutter-io.cn" 442 | source: hosted 443 | version: "2.1.2" 444 | string_scanner: 445 | dependency: transitive 446 | description: 447 | name: string_scanner 448 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 449 | url: "https://pub.flutter-io.cn" 450 | source: hosted 451 | version: "1.2.0" 452 | term_glyph: 453 | dependency: transitive 454 | description: 455 | name: term_glyph 456 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 457 | url: "https://pub.flutter-io.cn" 458 | source: hosted 459 | version: "1.2.1" 460 | test: 461 | dependency: "direct dev" 462 | description: 463 | name: test 464 | sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073" 465 | url: "https://pub.flutter-io.cn" 466 | source: hosted 467 | version: "1.25.2" 468 | test_api: 469 | dependency: transitive 470 | description: 471 | name: test_api 472 | sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" 473 | url: "https://pub.flutter-io.cn" 474 | source: hosted 475 | version: "0.7.0" 476 | test_core: 477 | dependency: transitive 478 | description: 479 | name: test_core 480 | sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4" 481 | url: "https://pub.flutter-io.cn" 482 | source: hosted 483 | version: "0.6.0" 484 | tuple: 485 | dependency: transitive 486 | description: 487 | name: tuple 488 | sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 489 | url: "https://pub.flutter-io.cn" 490 | source: hosted 491 | version: "2.0.2" 492 | typed_data: 493 | dependency: transitive 494 | description: 495 | name: typed_data 496 | sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c 497 | url: "https://pub.flutter-io.cn" 498 | source: hosted 499 | version: "1.3.2" 500 | unorm_dart: 501 | dependency: transitive 502 | description: 503 | name: unorm_dart 504 | sha256: "5b35bff83fce4d76467641438f9e867dc9bcfdb8c1694854f230579d68cd8f4b" 505 | url: "https://pub.flutter-io.cn" 506 | source: hosted 507 | version: "0.2.0" 508 | uuid: 509 | dependency: transitive 510 | description: 511 | name: uuid 512 | sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8" 513 | url: "https://pub.flutter-io.cn" 514 | source: hosted 515 | version: "4.4.0" 516 | vania: 517 | dependency: "direct main" 518 | description: 519 | name: vania 520 | sha256: "4ecc74c20e2e72e40864333e298e3866a11b4e932982305bdfcfdd3075dab5f4" 521 | url: "https://pub.flutter-io.cn" 522 | source: hosted 523 | version: "0.1.7+2" 524 | vm_service: 525 | dependency: transitive 526 | description: 527 | name: vm_service 528 | sha256: a2662fb1f114f4296cf3f5a50786a2d888268d7776cf681aa17d660ffa23b246 529 | url: "https://pub.flutter-io.cn" 530 | source: hosted 531 | version: "14.0.0" 532 | watcher: 533 | dependency: transitive 534 | description: 535 | name: watcher 536 | sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" 537 | url: "https://pub.flutter-io.cn" 538 | source: hosted 539 | version: "1.1.0" 540 | web: 541 | dependency: transitive 542 | description: 543 | name: web 544 | sha256: "4188706108906f002b3a293509234588823c8c979dc83304e229ff400c996b05" 545 | url: "https://pub.flutter-io.cn" 546 | source: hosted 547 | version: "0.4.2" 548 | web_socket_channel: 549 | dependency: transitive 550 | description: 551 | name: web_socket_channel 552 | sha256: "939ab60734a4f8fa95feacb55804fa278de28bdeef38e616dc08e44a84adea23" 553 | url: "https://pub.flutter-io.cn" 554 | source: hosted 555 | version: "2.4.3" 556 | webkit_inspection_protocol: 557 | dependency: transitive 558 | description: 559 | name: webkit_inspection_protocol 560 | sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" 561 | url: "https://pub.flutter-io.cn" 562 | source: hosted 563 | version: "1.2.1" 564 | yaml: 565 | dependency: transitive 566 | description: 567 | name: yaml 568 | sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" 569 | url: "https://pub.flutter-io.cn" 570 | source: hosted 571 | version: "3.1.2" 572 | sdks: 573 | dart: ">=3.2.3 <4.0.0" 574 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 2 | description: Sample Vania backend web application framework 3 | version: 1.0.0 4 | 5 | environment: 6 | sdk: ^3.2.3 7 | 8 | # Add regular dependencies here. 9 | dependencies: 10 | vania: ^0.1.7+3 11 | 12 | 13 | dev_dependencies: 14 | lints: ^2.1.0 15 | test: ^1.24.0 16 | -------------------------------------------------------------------------------- /storage/app/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vania-dart/example/20a985b24ca160e60ef3ce72835d0cf0ba13caa2/storage/app/.gitkeep -------------------------------------------------------------------------------- /swagger.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.3 2 | info: 3 | title: Vania Example 4 | description: API documentation for Vania Example 5 | version: 1.0.0 6 | servers: 7 | - url: http://localhost:8000/api/v1 8 | paths: 9 | /sign-up: 10 | post: 11 | summary: Register a new user 12 | requestBody: 13 | content: 14 | application/json: 15 | schema: 16 | type: object 17 | properties: 18 | first_name: 19 | type: string 20 | last_name: 21 | type: string 22 | email: 23 | type: string 24 | password: 25 | type: string 26 | required: true 27 | responses: 28 | '200': 29 | description: User created successfully 30 | content: 31 | application/json: 32 | schema: 33 | type: object 34 | properties: 35 | message: 36 | type: string 37 | /login: 38 | post: 39 | summary: Log in with existing credentials 40 | requestBody: 41 | content: 42 | application/json: 43 | schema: 44 | type: object 45 | properties: 46 | email: 47 | type: string 48 | password: 49 | type: string 50 | required: true 51 | responses: 52 | '200': 53 | description: User logged in successfully 54 | content: 55 | application/json: 56 | schema: 57 | type: object 58 | properties: 59 | access_token: 60 | type: string 61 | refresh_token: 62 | type: string 63 | expires_in: 64 | type: string 65 | /refresh-token: 66 | post: 67 | summary: Refresh access token 68 | requestBody: 69 | content: 70 | application/json: 71 | schema: 72 | required: true 73 | type: string 74 | responses: 75 | '200': 76 | description: Access token refreshed successfully 77 | content: 78 | application/json: 79 | schema: 80 | type: object 81 | properties: 82 | access_token: 83 | type: string 84 | refresh_token: 85 | type: string 86 | expires_in: 87 | type: string 88 | /user/details: 89 | get: 90 | summary: Get user details 91 | parameters: 92 | - in: header 93 | name: Authorization 94 | schema: 95 | type: string 96 | required: true 97 | responses: 98 | '200': 99 | description: User details retrieved successfully 100 | content: 101 | application/json: 102 | schema: 103 | type: object 104 | properties: 105 | id: 106 | type: integer 107 | first_name: 108 | type: string 109 | last_name: 110 | type: string 111 | email: 112 | type: string 113 | password: 114 | type: string 115 | avatar: 116 | type: string 117 | created_at: 118 | type: string 119 | updated_at: 120 | type: string 121 | deleted_at: 122 | type: string 123 | /user/update: 124 | post: 125 | summary: Update user details 126 | requestBody: 127 | content: 128 | application/json: 129 | schema: 130 | type: object 131 | properties: 132 | first_name: 133 | type: string 134 | last_name: 135 | type: string 136 | email: 137 | type: string 138 | avatar: 139 | type: string 140 | required: true 141 | parameters: 142 | - in: header 143 | name: Authorization 144 | schema: 145 | type: string 146 | required: true 147 | responses: 148 | '200': 149 | description: User updated successfully 150 | content: 151 | application/json: 152 | schema: 153 | type: object 154 | properties: 155 | message: 156 | type: string 157 | /post/all: 158 | get: 159 | summary: Get all posts 160 | parameters: 161 | - in: header 162 | name: Authorization 163 | schema: 164 | type: string 165 | required: true 166 | responses: 167 | '200': 168 | description: Posts retrieved successfully 169 | content: 170 | application/json: 171 | schema: 172 | type: object 173 | properties: 174 | data: 175 | type: array 176 | items: 177 | type: object 178 | properties: 179 | first_name: 180 | type: string 181 | last_name: 182 | type: string 183 | text: 184 | type: string 185 | id: 186 | type: integer 187 | /post/create: 188 | post: 189 | summary: Create a new post 190 | requestBody: 191 | content: 192 | application/json: 193 | schema: 194 | type: object 195 | properties: 196 | text: 197 | type: string 198 | required: true 199 | parameters: 200 | - in: header 201 | name: Authorization 202 | schema: 203 | type: string 204 | required: true 205 | responses: 206 | '200': 207 | description: Post created successfully 208 | content: 209 | application/json: 210 | schema: 211 | type: object 212 | properties: 213 | message: 214 | type: string --------------------------------------------------------------------------------