- 전체
- 게임 일반 (make game basics)
- 모바일 기획 및 디자인
- GameMaker Studio
- Unity3D
- Cocos2D
- 3D Engine OGRE
- 3D Engine irrlicht
- copperCube
- corona SDK
- Windows Basic Game
- BaaS (Mobile Backend)
- phnegap & cordova
- ionic & anguler
- parse (backend)
- firebase (backend)
- Game Backend Server / Opt
- web assembly
- Smart Makers
- pyGame & Ren'Py
- 머드(MUD) 게임 만들기
- Xamarin(자마린)
- flutter (플루터 앱 개발)
- construct 2 / 3
- pocketbase
- RPG Maker 시리즈
- godot engine
- playmaker(unity)
- react native
pocketbase [pocketbase] Flutter 및 Dart용 PocketBase 백엔드 : A PocketBase backend for Flutter and Dart
2024.08.18 22:54
[pocketbase] Flutter 및 Dart용 PocketBase 백엔드 : A PocketBase backend for Flutter and Dart
https://github.com/suragch/flutter_pocketbase_tutorial?tab=readme-ov-file
A PocketBase backend for Flutter and Dart
A step-by-step tutorial

Updated February 14, 2024.
https://github.com/suragch/flutter_pocketbase_tutorial?tab=readme-ov-file
I’ve been looking into solutions for self-hosting a backend server for my Flutter app. In addition to performing normal read-write operations, it also needs to support user authentication. To that end, I’ve been experimenting with Shelf, Supabase, and SuperTokens.
Then I discovered PocketBase.
Look at what this Backend as a Service (BaaS) offers:
- Open source.
- 30k stars on GitHub and under active development.
- Has a Dart SDK.
- Email-password or social auth (Google, Apple, etc).
- SQLite database, configurable with rules and user roles.
- Realtime updates.
- File storage.
- Admin dashboard.
- Super easy deployment with a single file.
And that’s just a partial list.
The article that follows will walk you through the steps of connecting your Flutter app to PocketBase. I wrote it partly to teach myself how to do it and partly to teach you. If you still have any questions when you’re finished, please leave a comment. I’ll include some of my own thoughts at the end of the article as well as some reasons you might not choose PocketBase.
Note: This is an intermediate-level tutorial. I’ll assume you already know how to do basic Flutter tasks like building a UI and adding packages.
Getting started
Start by creating a new Flutter project.
Then build a UI like the one in the image below. It should include a Text widget to display the user’s logged-in status and eight buttons titled Sign up, Sign in, Refresh token, Sign out, Create, Read, Update, and Delete:

You’ll use the buttons to learn how to authenticate a user and perform CRUD operations with PocketBase.
Running PocketBase locally
During development, it will be more convenient to have the PocketBase server running on your local machine than on a remote one.
Go to the PocketBase documentation page and download the version for your local machine.
Extract the folder and run the following to start the server:
./pocketbase serve
Note: On Mac, you need to open the folder in Finder, right-click the pocketbase file, and choose Open to bypass the security settings for downloaded files. See more here. After that, run the ./pocketbase serve command again to start the server.
PocketBase will also create a folder named pb_data where it will store the data.
Go to http://127.0.0.1:8090/ in your browser and you should get a 404 response. In this case, that good. It means the server is working.
Creating an admin user
Next, go to http://127.0.0.1:8090/_/ to set up the admin account. You’ll see the following screen:

Fill in the fields and then log in. You’ll be greeted with the following admin dashboard:

You don’t need to do anything now, but keep this browser window open. You’ll come back here later to see the result of the changes you make from your Flutter client.
Adding the PocketBase Dart SDK to Flutter
Although you could communicate with the PocketBase server using its REST API, it will be much easier to directly use the official Dart SDK.
Back in your Flutter app, add the pocketbase package to pubspec.yaml:
dependencies:
pocketbase: ^0.18.0
You’ll import PocketBase wherever you need it like so:
import 'package:pocketbase/pocketbase.dart';
You’ll also need an instance of PocketBase to connect with the server. Create it wherever it makes sense for your state management approach:
final pb = PocketBase('http://127.0.0.1:8090/');
If you’re doing development using the Android emulator, then use port 10.0.2.2:
final pb = PocketBase('http://10.0.2.2:8090/');
I use the minimalist state management approach. Since I only need a reference to PocketBase in one file for today’s tutorial, I’ll initialize it directly in my state management class. However, if I needed it in multiple places throughout the app, I’d use GetIt.
Signing up a new user
PocketBase makes it very easy to perform the various authentication flows.
Add a method to your Flutter project that will run when the Sign up button is pressed:
Future<void> signUp() async {
final body = <String, dynamic>{
"username": "Bob",
"email": "bob@example.com",
"password": "12345678",
"passwordConfirm": "12345678",
"name": "Bob Smith"
};
final record = await pb.collection('users').create(body: body);
print(record);
}
Here are some notes about that code:
pbis thePocketBaseinstance that you created in the last step.usersis the default collection (table) that PocketBase uses for authentication.createadds a new record (row) to the collection. In this case, that means a new user.- You pass the email, password, and other parameters as a map to the
createbody. You can read about the other auth record fields in the docs.
Run the code above and you should see something similar to the response below:
{
"id":"79yvk2r0lxnt6ob",
"created":"2024-01-26 03:02:11.967Z",
"updated":"2024-01-26 03:02:11.967Z",
"collectionId":"_pb_users_auth_",
"collectionName":"users",
"expand":{},
"avatar":"",
"emailVisibility":false,
"name":"Bob Smith",
"username":"Bob",
"verified":false
}
Back in the browser dashboard, press the Refresh button and you’ll see that a new user record has been added:

Signing up a new user doesn’t sign them in yet. That’s another step.
Note: I won’t cover it in this tutorial, but before you allow a new user to sign in, you’ll probably want to verify their email. Think about what might happen if you don’t. Some malicious hacker could write a script to register thousands of fake users and then use those accounts to spam your site. PocketBase supports sending email verifications. Here is a video about it. You’ll either want to set up a quality SMTP server or use a third-party email service. Otherwise, your emails will probably be flagged as spam.
Signing in
Next add the code that corresponds with the Sign in button in your app:
Future<void> signIn() async {
final authData = await pb
.collection('users')
.authWithPassword('bob@example.com', '12345678');
print(authData);
}
authWithPassword sends the email and password for PocketBase to check.
Refresh your app and press the Sign in button. You should see a result similar to the following:
{
"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2xsZWN0aW9uSWQiOiJfcGJfdXNlcnNfYXV0aF8iLCJleHAiOjE3MDc0NDk1OTIsImlkIjoiNzl5dmsycjBseG50Nm9iIiwidHlwZSI6ImF1dGhSZWNvcmQifQ.uee--OI5bagsyVjLHq0kqbrbKQfyQ9UxpVV9g6eR8vc",
"record":{
"id":"79yvk2r0lxnt6ob",
"created":"2024-01-26 03:02:11.967Z",
"updated":"2024-01-26 03:02:11.967Z",
"collectionId":"_pb_users_auth_",
"collectionName":"users",
"expand":{},
"avatar":"",
"email":"bob@example.com",
"emailVisibility":false,
"name":"Bob Smith",
"username":"Bob",
"verified":false
},
"meta":{}
}
That token is a JWT, which if you were to decode, would contain the following information in its payload:
{
"collectionId": "_pb_users_auth_",
"exp": 1707449592,
"id": "79yvk2r0lxnt6ob",
"type": "authRecord"
}
The exp field is when the token expires. The default duration is two weeks. You can change the default duration in the PocketBase dashboard under Settings > Token Options.
Note: PocketBase doesn’t use refresh tokens. It only uses long-lived access tokens. The reason is that PocketBase is a monolith. The data and the auth all happen on the same server. PocketBase also doesn’t store the token on the server. It just verifies the access tokens that it has previously issued. You can read more here.
After you’ve signed in, you can use the authStore property. This will give you access to token and methods like isValid.
It’s time to update the UI now that the user has signed in. Feel free to use setState or your own preferred state management method. With the minimalist approach, I use Flutter’s built-in ValueNotifier and ValueListenableBuilder.
final statusNotifier = ValueNotifier('Logged out');
Then I update the notifier at the end of the signIn method:
statusNotifier.value = (pb.authStore.isValid) ? 'Logged in' : 'Logged out';
pb.authStore.isValid returns true now that you’ve logged in.
Restart the app and press the Sign in button. Your status text should indicate that you’ve logged in:

Note: Rather than manually updating the notifier, another option would be to listen to the authStore.onChange stream and pair that with a StreamBuilder to update the UI. In a larger app, you could combine this with go_router to automatically redirect to the login screen.
Sign-in is great, but you don’t want to make your users enter their email and password every time they open your app. What you should do is automatically refresh the access token. You’ll learn how to do that in the next step.
Refreshing the token
When you sign in, PocketBase gives you an access token. This token is valid for two weeks by default. It’s your responsibility to manage the token on the Flutter side. If you lose the token or it expires, then you’ll have to ask the user to sign in again.
Add a method that will run when the Refresh token button is pressed:
Future<void> refresh() async {
if (!pb.authStore.isValid) {
// TODO: The token has expired. Ask the user to sign in again.
return;
}
final authData = await pb.collection('users').authRefresh();
print(authData);
}
authRefresh requests a new token with an updated expiration date from PocketBase.
Hot reload your app so that you are still logged in, and then press the Refresh token button. You should get a new JWT token back. If you decode it, you’ll see that the exp expiration timestamp has also been updated.
Persisting the token (optional)
The default AuthStore only keeps the access token in memory, so when you close the app the access token is lost. If you want the user to stay logged in the next time they open your app, you need to provide PocketBase with a custom AuthStore. You can do that with PocketBase’s AsyncAuthStore class.
I’m not going to go into the implementation details of how to store the token string in local storage, but the following code shows how to handle things on the PocketBase side.
Replace your pb instance in your state management class with the following:
late final PocketBase pb;
// 1
Future<void> init() async {
// 2
final storage = getIt<LocalStorage>();
// 3
final token = await storage.getToken();
final customAuthStore = AsyncAuthStore(
initial: token,
save: storage.setToken,
clear: storage.deleteToken,
);
// 4
pb = PocketBase(
'http://$_host:8090/',
authStore: customAuthStore,
);
if (pb.authStore.isValid) {
statusNotifier.value = 'Logged in';
// 5
final authRecord = await pb.collection('users').authRefresh();
print(authRecord);
} else {
statusNotifier.value = 'Logged out';
}
}
String get _host => (Platform.isAndroid) ? '10.0.2.2' : '127.0.0.1';
Here are a few notes:
- You should call the
initmethod when the app starts. In the demo project, I called it in theinitStatemethod of the home page. - In the demo project, I used
get_itto provide a reference to myLocalStorageservice. Feel free to useprovideror some form of dependency injection. - You can implement
LocalStorageany way you like as long as it has a way to save, read and delete the token string. Check outflutter_secure_storageas one option for encrypted storage. In the demo project for this tutorial, I usedshared_preferencesonly for its simplicity. A production app shouldn’t useshared_preferencesbecause it isn’t secure. If a hacker were to get the token, they could do anything the user can do. - Provide your custom auth store to
PocketBasewhen you initialize it. - You can also refresh the auth token when the app first starts up. As you saw earlier, this will update the expiration date, minimizing the chance that the user will need to sign in again. Your custom auth store automatically takes care of saving the token.
Close the app and restart it. You should still be logged in.
Read this and this for a few more pointers on implementing a custom AuthStore.
Signing out
The last authentication-related step this tutorial will cover is signing out. It’s just as easy as the other steps have been.
PocketBase doesn’t store a user’s session data or even their access token on the server. So, in order to log a user out, all you need to do is clear the auth data on the client side.
Add a method that will run when the user presses the Sign out button:
Future<void> signOut() async {
pb.authStore.clear();
statusNotifier.value = 'Logged out';
}
That was easy, huh?
Refresh the app and test it out:

There are other auth tasks that you may want to do in the future, such as resetting a forgotten password or requesting an email change. You can check out the PocketBase documentation for details. In fact, if you choose API Preview from the admin dashboard, it will give you code samples of how to do everything.

In the next section, you’ll add a regular collection so that you can perform CRUD operations on it from your Flutter client.
Creating a new collection
In the admin dashboard, click the New collection button:

Adding fields
A new window will pop up. Follow these directions to match the image below:
- You’ll make a collection to save user exam scores, so write scores for the collection name.
- There are three different types of collections in PocketBase. Since we want users to be able to edit the contents of this collection, choose Base from the drop-down menu in the top right. (This is the default.)
- On the Fields tab, click New field to add two new fields.
- Choose Relation and name it user. Under Select collection, choose the users collection. This will link the
userfield to theuserscollection. (It’s like adding a foreign key to a table in SQL.) - Click New field again and this time add a Number field. Call it score.

Adding API rules
For security reasons, only admin users can read and write to the collection by default. However, you want to allow the users of your Flutter app to also edit their own data. PocketBase handles this with API Rules.
Click the API Rules tab:

There are five different categories. List/Search rules are for requesting a list of records, while View rules are for requesting a single record. You only want a user to be able to see their own exam scores, not other people’s scores. So for both of these categories, add the following rule:
user = @request.auth.id
This means that the user field of your scores collection must match the authenticated user ID in the request. This effectively filters out all other users.
The same is true for Create and Update. However, you also want to enforce the exam score to be within the range of 0–100. Add the following rule to those two categories:
user = @request.auth.id &&
@request.data.score >= 0 &&
@request.data.score <= 100
This ensures that the score field of the incoming request is within the proper bounds.
Finally, users should only be allowed to delete their own scores, so add the following to the Delete rules:
user = @request.auth.id
When you’re done, save your changes by clicking the Create button in the bottom right corner of the admin dashboard.
Creating a record from Flutter
Back in your Flutter app, add a method that will be called when a user presses the Create button on your Flutter app:
Future<void> create() async {
final body = <String, dynamic>{
"user": pb.authStore.model.id,
"score": 89,
};
final record = await pb.collection('scores').create(body: body);
print(record);
}
You’re again using the create method just like when you added a new user. This time, though, you’re creating a record in the scores collection. Notice that the keys (user and score) of the body map match the field names you chose when you created the collection.
Refresh your app and press the Create button. You should see the following result for record:
{
"id":"k4oaijxf47jroc0",
"created":"2024-01-26 09:39:27.934Z",
"updated":"2024-01-26 09:39:27.934Z",
"collectionId":"0q5mu8dg1ohw7iz",
"collectionName":"scores",
"expand":{},
"score":89,
"user":"79yvk2r0lxnt6ob"
}
Great, it’s working.
You need some more user data for the future steps. Let’s create that now. Change the contents of the signUp and signIn methods to add a new user named Mary.
Future<void> signUp() async {
final body = <String, dynamic>{
"username": "Mary", // updated
"email": "mary@example.com", // updated
"password": "12345678",
"passwordConfirm": "12345678",
"name": "Mary Smith" // updated
};
final record = await pb.collection('users').create(body: body);
print(record);
}
Future<void> signIn() async {
final authData = await pb
.collection('users')
.authWithPassword('mary@example.com', '12345678'); // updated
print(authData);
statusNotifier.value = (pb.authStore.isValid) ? 'Logged in' : 'Logged out';
}
Now refresh the app and press Sign up, Sign in, and Create in that order.
Next, change the score in the create method to 92. Then refresh the app and press the Create button again.
Now you should have three records in the scores table: one from Bob and two from Mary. Go to the admin dashboard and press the Refresh button to check it out:

Nice! It worked. You’ve created three new records.
Reading a list of records
Next you’ll try to get a list of all the records for one user. You’re currently logged in as Mary so you would expect to get both of Mary’s exam scores. And if you set up the rules correctly, you shouldn’t get Bob’s score.
Add a method that will be run when the user presses the Read button:
Future<void> read() async {
final records = await pb.collection('scores').getFullList(
sort: '-score',
);
print(records);
}
Here are a few notes:
getFullListreturns all of the records in the collection (filtered by the API rules you defined). If that would be too many records, you can paginate the results usinggetList.sortdefines which field you want to sort by, in this case byscore. The-dash in front of the field name means that you want to sort in reverse order, in this case from high to low score.- There are a number of additional parameters you can include in addition to
sort. Others arebatch,filter, andfields.
Refresh your app and press the Read button. You should see Mary’s two exam scores:
[
{
"id":"m1fkfqdv8r20oif",
"created":"2024-01-26 09:51:04.343Z",
"updated":"2024-01-26 09:51:04.343Z",
"collectionId":"0q5mu8dg1ohw7iz",
"collectionName":"scores",
"expand":{},
"score":92,
"user":"eokvshdupfla4v4"
},
{
"id":"3fkk1f4sgwqgzje",
"created":"2024-01-26 09:49:07.460Z",
"updated":"2024-01-26 09:49:07.460Z",
"collectionId":"0q5mu8dg1ohw7iz",
"collectionName":"scores",
"expand":{},
"score":89,
"user":"eokvshdupfla4v4"
}
]
It’s good to see that Bob (user ID 79yvk2r0lxnt6ob) isn’t there. Your API rule worked. Also, Mary’s scores are sorted from highest to lowest.
There’s a lot more data there than you really need, though. All you want are the score IDs and the scores themselves. You can tell PocketBase which fields you want using the fields parameter of getFullList. Add the following line after sort: ‘-score’,:
fields: 'id,score',
When combining multiple field names, you split them with a comma.
Press the Read button again, and this time, this is what you see:
[
{
"id":"m1fkfqdv8r20oif",
"created":"",
"updated":"",
"collectionId":"",
"collectionName":"",
"expand":{},
"score":92
},
{
"id":"3fkk1f4sgwqgzje",
"created":"",
"updated":"",
"collectionId":"",
"collectionName":"",
"expand":{},
"score":89
}
]
I don’t know that PocketBase needed to give you all the empty fields, but at least you saved it the work of passing in useless values.
Updating a record
Mary isn’t satisfied with her score of 89. She wants a higher grade. In this step, you’ll replace the lowest score with 100.
Create a method that will be called when the Update button is pushed:
Future<void> update() async {
// Find the record with the lowest score
final recordList = await pb.collection('scores').getList(
page: 1,
perPage: 1,
skipTotal: true,
sort: 'score',
fields: 'id,score',
);
print(recordList);
final record = recordList.items.first;
// Update the record
final body = <String, dynamic>{"score": 100};
final updatedRecord = await pb.collection('scores').update(
record.id,
body: body,
);
print(updatedRecord);
}
Here are some notes:
- This time you use
getListrather thangetFullListbecause you only need one record. - For the same reason, you also only select 1
pageand 1 recordperPage. You don’t care about the total number of pages or records, so you canskipTotal. All of these are performance optimizations. - Once you have the record, you can update the
scorefield using the record ID.
Refresh the app and press the Update button. Here’s what you’ll see:
{
"page":1,
"perPage":1,
"totalItems":-1,
"totalPages":-1,
"items":[
{
"id":"3fkk1f4sgwqgzje",
"created":"",
"updated":"",
"collectionId":"",
"collectionName":"",
"expand":{},
"score":89
}
]
}
{
"id":"3fkk1f4sgwqgzje",
"created":"2024-01-26 09:49:07.460Z",
"updated":"2024-01-27 04:10:09.986Z",
"collectionId":"0q5mu8dg1ohw7iz",
"collectionName":"scores",
"expand":{},
"score":100,
"user":"eokvshdupfla4v4"
}
The score of 89 was updated to 100.
You can also see the same result by refreshing the scores collection in the dashboard:

Hmm, come to think of it, allowing students to update their own exam scores probably isn’t such a great idea. You may want to change the API rules and even introduce user roles like teacher and student.
Deleting a record
The last task you’ll implement in this tutorial is how to delete a record. The only thing you need to know is the record ID.
Add a method that will be called when the user presses the Delete button:
Future<void> delete() async {
// Find the record with the lowest score
final recordList = await pb.collection('scores').getList(
page: 1,
perPage: 1,
skipTotal: true,
sort: 'score',
fields: 'id,score',
);
final record = recordList.items.first;
// Delete the record
await pb.collection('scores').delete(record.id);
}
Refresh the app and press the Delete button. There is no return value, but you can refresh the scores collection in the dashboard to see that Mary is missing one value.

That brings you to the end of the tutorial. If you successfully followed along this far, you should have a good idea of how PocketBase works.
Going on
The tutorial didn’t implement any error handling. You can handle that by wrapping the PocketBase calls in try-catch blocks.
Read the Going to Production section of the documentation for how to deploy your server.
Final thoughts
I really like PocketBase. It’s by far the easiest way of setting up a self-hosted auth backend that I’ve found. However, there are a few caveats that I discovered along the way.
- Currently, bulk create, update, and delete operations are not supported. That means if a user wants to import a lot of data or update or delete many records at once, the only way to do it is by handling one record at a time. If you need to do that for thousands of records, it could be a deal breaker. There is an issue open on GitHub for this topic, but the solution is apparently non-trivial and currently the status is On Hold in the 1.0 roadmap.
- It’s possible to extend PocketBase and do things like define additional API routes. However, you have to use Go or JavaScript. Unfortunately, Dart isn’t an option.
Both of these drawbacks make me wonder, what if I just used PocketBase as the auth server and ran a Dart Shelf server on the same machine to handle database operations and other logic? It’s not quite as ideal, but I think it could work. To do this, the Flutter client app would first authenticate with PocketBase and get an access token. Then the client would pass the token in the Authorization header to the Dart server. The Dart server would verify the token with PocketBase and if valid would proceed to perform whatever task the user requested. This functionality isn’t designed into PocketBase, but the author acknowledges that it is possible to verify a token by calling authRefresh. Read this GitHub discussion for more.
Update: I’ve written a tutorial about using PostgreSQL on a Dart server. The only other step would be to authenticate the calls with a PocketBase access token. Read that article here: Using PostgreSQL on a Dart server.
Full code
If you’d like to support me, I’m selling the project source code as a download:
Thank you for your support!
(If you can’t afford to pay for it, though, no worries. Send me an email, and I’ll give it to you for free.)
[출처] https://suragch.medium.com/a-pocketbase-backend-for-flutter-and-dart-c962bea4e3f1
Flutter 및 Dart용 PocketBase 백엔드
단계별 튜토리얼

2024년 2월 14일에 업데이트되었습니다.
저는 Flutter 앱의 백엔드 서버를 셀프호스팅하기 위한 솔루션을 찾고 있었습니다. 일반적인 읽기-쓰기 작업을 수행하는 것 외에도 사용자 인증도 지원해야 합니다. 이를 위해 Shelf , Supabase , SuperTokens 를 실험해 왔습니다 .
그러다가 PocketBase를 발견하게 됐어요 .
이 백엔드 as a Service(BaaS)가 무엇을 제공하는지 살펴보세요.
- 오픈소스.
- GitHub에서 3만 개의 별을 받았으며 활발하게 개발 중입니다.
- Dart SDK 가 있습니다 .
- 이메일-비밀번호 또는 소셜 인증(Google, Apple 등).
- 규칙과 사용자 역할로 구성 가능한 SQLite 데이터베이스입니다.
- 실시간 업데이트.
- 파일 저장.
- 관리자 대시보드.
- 단일 파일로 매우 쉽게 배포할 수 있습니다.
그리고 이는 단지 일부 목록일 뿐입니다.
다음 글에서는 Flutter 앱을 PocketBase에 연결하는 단계를 안내해 드립니다. 저는 부분적으로는 제 스스로 방법을 배우기 위해, 부분적으로는 여러분에게 가르치기 위해 글을 썼습니다. 글을 다 읽고도 여전히 궁금한 점이 있으면 댓글을 남겨주세요. 글의 마지막에 제 생각과 PocketBase를 선택하지 않을 수 있는 몇 가지 이유를 포함하겠습니다.
참고 : 이것은 중급 수준의 튜토리얼입니다. UI를 빌드하고 패키지를 추가하는 것과 같은 기본적인 Flutter 작업을 수행하는 방법을 이미 알고 있다고 가정합니다.
시작하기
새로운 Flutter 프로젝트를 만들어서 시작하세요.
그런 다음 아래 이미지와 같은 UI를 빌드합니다. 여기에는 Text사용자의 로그인 상태를 표시하는 위젯과 가입, 로그인, 토큰 새로 고침, 로그아웃, 생성, 읽기, 업데이트, 삭제라는 제목의 8개 버튼이 포함되어야 합니다.

버튼을 사용하여 PocketBase에서 사용자를 인증하고 CRUD 작업을 수행하는 방법을 알아봅니다.
로컬에서 PocketBase 실행하기
개발 중에는 원격 컴퓨터보다 로컬 컴퓨터에서 PocketBase 서버를 실행하는 것이 더 편리합니다.
PocketBase 설명서 페이지 로 가서 로컬 머신에 맞는 버전을 다운로드하세요.
폴더를 추출하고 다음을 실행하여 서버를 시작합니다.
./포켓베이스 서브
참고 : Mac에서는 Finder에서 폴더를 열고, pocketbase 파일을 마우스 오른쪽 버튼으로 클릭하고, 열기를 선택하여 다운로드한 파일에 대한 보안 설정을 우회해야 합니다. 자세한 내용은 여기를 참조하세요 . 그런 다음 ./pocketbase serve명령을 다시 실행하여 서버를 시작합니다.
pb_dataPocketBase는 또한 데이터를 저장할 폴더를 생성합니다 .
브라우저에서 http://127.0.0.1:8090/ 으로 가면 404 응답이 나올 것입니다. 이 경우에는 좋습니다. 서버가 작동 중이라는 뜻입니다.
관리자 사용자 생성
다음으로, http://127.0.0.1:8090/_/ 로 가서 관리자 계정을 설정하세요. 다음 화면이 보일 겁니다:

필드를 채운 다음 로그인하세요. 다음 관리자 대시보드가 나타납니다.

지금은 아무것도 할 필요가 없지만, 이 브라우저 창을 열어 두세요. 나중에 다시 돌아와서 Flutter 클라이언트에서 변경한 결과를 볼 수 있습니다.
Flutter에 PocketBase Dart SDK 추가
REST API를 사용하여 PocketBase 서버와 통신할 수도 있지만 , 공식 Dart SDK를 직접 사용하는 것이 훨씬 더 쉽습니다.
Flutter 앱으로 돌아와서 pubspec.yamlpocketbase 에 패키지를 추가합니다 .
종속성:
pocketbase: ^0.18.0
다음과 같이 필요한 곳 어디든 PocketBase를 가져올 수 있습니다.
'패키지:pocketbase/pocketbase.dart'를 가져옵니다 .
서버에 연결하려면 인스턴스도 필요합니다 PocketBase. 상태 관리 방식에 적합한 위치에 인스턴스를 만드세요.
최종 pb = PocketBase( 'http://127.0.0.1:8090/' );
Android 에뮬레이터를 사용하여 개발을 진행하는 경우 포트 10.0.2.2를 사용하세요.
최종 pb = PocketBase( 'http://10.0.2.2:8090/' );
저는 미니멀리스트 상태 관리 접근 방식을 사용합니다 . 오늘의 튜토리얼에서는 PocketBase에 대한 참조가 한 파일에만 필요하므로 상태 관리 클래스에서 직접 초기화하겠습니다. 그러나 앱 전체에서 여러 곳에 필요하다면 GetIt을 사용합니다 .
새로운 사용자 등록
PocketBase를 사용하면 다양한 인증 흐름을 매우 쉽게 수행할 수 있습니다.
가입 버튼을 누르면 실행되는 Flutter 프로젝트에 메서드를 추가합니다 .
Future< void > signUp() 비동기 {
최종 본문 = < String , dynamic >{
"username" : "Bob" ,
"email" : "bob@example.com" ,
"password" : "12345678" ,
"passwordConfirm" : "12345678" ,
"name" : "Bob Smith"
};
최종 레코드 = await pb.collection( 'users' ).create(body: body);
print (record);
}
해당 코드에 대한 몇 가지 참고 사항은 다음과 같습니다.
pbPocketBase는 마지막 단계에서 생성한 인스턴스 입니다 .users는 PocketBase가 인증에 사용하는 기본 컬렉션(테이블)입니다.create컬렉션에 새 레코드(행)를 추가합니다. 이 경우 새 사용자를 의미합니다.- 이메일, 비밀번호 및 기타 매개변수를 맵으로 본문에 전달합니다 . 문서
create에서 다른 인증 레코드 필드에 대해 읽을 수 있습니다 .
위의 코드를 실행하면 아래와 비슷한 응답이 나올 것입니다.
{
"id" : "79yvk2r0lxnt6ob" ,
"created" : "2024-01-26 03:02:11.967Z" ,
"updated" : "2024-01-26 03:02:11.967Z" ,
"collectionId" : "_pb_users_auth_" ,
"collectionName" : "users" ,
"expand" : { } ,
"avatar" : "" ,
"emailVisibility" : false ,
"name" : "밥 스미스" ,
"username" : "밥" ,
"verified" : false
}
브라우저 대시보드로 돌아가서 새로 고침 버튼을 누르면 새로운 사용자 레코드가 추가된 것을 볼 수 있습니다.

새로운 사용자를 등록하는 것은 아직 로그인하지 않습니다. 그것은 또 다른 단계입니다.
참고 : 이 튜토리얼에서는 다루지 않겠지만, 새 사용자가 로그인하도록 허용하기 전에 해당 사용자의 이메일을 확인해야 할 것입니다. 이메일을 확인하지 않으면 어떤 일이 일어날지 생각해보세요. 악의적인 해커가 수천 명의 가짜 사용자를 등록한 다음 해당 계정을 사용하여 사이트에 스팸을 보내는 스크립트를 작성할 수 있습니다. PocketBase는 이메일 확인을 지원합니다. 여기에 이에 대한 비디오가 있습니다. 양질의 SMTP 서버를 설정하거나 타사 이메일 서비스를 사용해야 합니다. 그렇지 않으면 이메일이 스팸으로 표시될 수 있습니다.
로그인 중
다음으로 앱의 로그인 버튼 에 해당하는 코드를 추가합니다 .
Future< void > signIn () 비동기 {
최종 인증 데이터 = await pb
.collection( 'users' )
.authWithPassword( 'bob@example.com' , '12345678' );
print(인증 데이터);
}
authWithPasswordPocketBase에서 확인할 수 있도록 이메일과 비밀번호를 전송합니다.
앱을 새로 고침하고 로그인 버튼을 누릅니다. 다음과 비슷한 결과가 표시되어야 합니다.
{
"토큰" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2xsZWN0aW9uSWQiOiJfcGJfdXNlcnNfYXV0aF8iLCJleHAiOjE3MDc0NDk1OTIsImlkIjoiNzl5dmsycjBseG50Nm9iIiwid HlwZSI6ImF1dGhSZWNvcmQifQ.uee--OI5bagsyVjLHq0kqbrbKQfyQ9UxpVV9g6eR8vc" ,
"record" : {
"id" : "79yvk2r0lxnt6ob" ,
"created" : "2024-01-26 03:02:11.967Z" ,
"업데이트됨" : "2024-01-26 03:02:11.967Z" ,
"collectionId" : "_pb_users_auth_" ,
"collectionName" : "users" ,
"expand" : { } ,
" avatar" : "" ,
"email" : "bob@example.com" ,
"emailVisibility" : false ,
"name" : "Bob Smith" ,
"username" : "Bob" ,
"verified" : false
} ,
"meta " : { }
}
해당 토큰은 JWT이고, 이를 디코딩 하면 페이로드에 다음 정보가 포함됩니다.
{
"컬렉션ID" : "_pb_users_auth_" ,
"exp" : 1707449592 ,
"id" : "79yvk2r0lxnt6ob" ,
"유형" : "authRecord"
}
필드 exp는 토큰이 만료되는 시점입니다. 기본 기간은 2주입니다. PocketBase 대시보드의 설정 > 토큰 옵션 에서 기본 기간을 변경할 수 있습니다 .
참고 : PocketBase는 새로 고침 토큰을 사용하지 않습니다. 장기 액세스 토큰만 사용합니다. 그 이유는 PocketBase가 모놀리스이기 때문입니다. 데이터와 인증은 모두 동일한 서버에서 발생합니다. PocketBase는 또한 토큰을 서버에 저장하지 않습니다. 이전에 발급한 액세스 토큰만 확인합니다. 자세한 내용은 여기에서 읽을 수 있습니다 .
로그인한 후에는 해당 속성을 사용할 수 있습니다 . 이렇게 하면 . 과 같은 메서드 authStore에 액세스할 수 있습니다 .tokenisValid
이제 사용자가 로그인했으므로 UI를 업데이트할 시간입니다. 자유롭게 setState또는 선호하는 상태 관리 방법을 사용하세요. 미니멀리스트 접근 방식 으로 Flutter의 기본 제공 ValueNotifier및 ValueListenableBuilder.
최종 상태 알림 = ValueNotifier( '로그아웃됨' );
그런 다음 메서드의 끝에서 알림을 업데이트합니다 signIn.
statusNotifier.value = (pb.authStore.isValid) ? '로그인됨' : '로그아웃됨' ;
pb.authStore.isValidtrue이제 로그인했으므로 돌아갑니다 .
앱을 다시 시작하고 로그인 버튼을 누릅니다. 상태 텍스트에 로그인했다는 내용이 표시되어야 합니다.

참고 : 알림을 수동으로 업데이트하는 대신, 다른 옵션은 authStore.onChange스트림을 듣고 이를 StreamBuilderUI를 업데이트하기 위해 와 페어링하는 것입니다. 더 큰 앱에서는 이것을 go_router 와 결합하여 자동으로 로그인 화면으로 리디렉션할 수 있습니다.
로그인은 좋지만, 사용자가 앱을 열 때마다 이메일과 비밀번호를 입력하게 하고 싶지는 않을 겁니다. 해야 할 일은 액세스 토큰을 자동으로 새로 고침하는 것입니다. 다음 단계에서 그 방법을 배우게 될 겁니다.
토큰 새로 고침
로그인하면 PocketBase에서 액세스 토큰을 제공합니다. 이 토큰은 기본적으로 2주 동안 유효합니다. Flutter 측에서 토큰을 관리하는 것은 귀하의 책임입니다. 토큰을 분실하거나 만료되면 사용자에게 다시 로그인하도록 요청해야 합니다.
새로 고침 토큰 버튼을 누르면 실행되는 메서드를 추가합니다 .
Future< void > Refresh() async {
if (!pb.authStore.isValid) {
// TODO: 토큰이 만료되었습니다. 사용자에게 다시 로그인하도록 요청합니다.
return ;
}
final authData = await pb.collection( 'users' ).authRefresh();
print (authData);
}
authRefreshPocketBase에 업데이트된 만료일이 포함된 새 토큰을 요청합니다.
앱을 핫 리로드하여 로그인 상태를 유지한 다음 Refresh token 버튼을 누릅니다. 새 JWT 토큰을 다시 받게 됩니다. 이를 디코드 하면 exp만료 타임스탬프도 업데이트된 것을 볼 수 있습니다 .
토큰 유지(선택 사항)
기본값은 AuthStore액세스 토큰을 메모리에 보관하기만 하므로 앱을 닫으면 액세스 토큰이 손실됩니다. 다음에 앱을 열 때 사용자가 로그인 상태를 유지하도록 하려면 사용자 지정 .을 제공해야 합니다 PocketBase. AuthStorePocketBase의 클래스로 할 수 있습니다 AsyncAuthStore.
토큰 문자열을 로컬 스토리지에 저장하는 방법에 대한 구현 세부 사항은 설명하지 않겠지만, 다음 코드는 PocketBase 측에서 작업을 처리하는 방법을 보여줍니다.
pb상태 관리 클래스의 인스턴스를 다음으로 바꾸세요 .
늦은 최종 PocketBase pb;
// 1
Future<void> init () 비동기 {
// 2
최종 저장소 = getIt<LocalStorage>();
// 3
최종 토큰 = await storage.getToken();
최종 customAuthStore = AsyncAuthStore(
초기: 토큰,
저장: 저장소.setToken,
지우기: 저장소.deleteToken,
);
// 4
pb = PocketBase(
'http:// $_host :8090/' ,
authStore: customAuthStore,
);
if (pb.authStore.isValid) {
statusNotifier.value = '로그인됨' ;
// 5
최종 authRecord = await pb.collection( 'users' ).authRefresh();
print (authRecord);
} else {
statusNotifier.value = '로그아웃됨' ;
}
}
문자열 get _host => (Platform.isAndroid) ? '10.0.2.2' : '127.0.0.1' ;
몇 가지 참고 사항은 다음과 같습니다.
- 앱이 시작될 때 메서드를 호출해야 합니다 . 데모 프로젝트에서는 홈페이지 메서드
init에서 호출했습니다 .initState - 데모 프로젝트에서 저는
get_it제 서비스에 대한 참조를 제공 하곤 했습니다LocalStorage. 자유롭게provider또는 어떤 형태의 종속성 주입을 사용하세요. LocalStorage토큰 문자열을 저장, 읽기, 삭제할 수 있는 방법이 있는 한 원하는 대로 구현할 수 있습니다 .flutter_secure_storage암호화된 저장소에 대한 한 가지 옵션으로 확인하세요. 이 튜토리얼의 데모 프로젝트에서는shared_preferences단순성 때문에 사용했습니다. 프로덕션 앱은 안전하지 않기 때문에 사용하면 안 됩니다shared_preferences. 해커가 토큰을 얻으면 사용자가 할 수 있는 모든 것을 할 수 있습니다.PocketBase초기화할 때 사용자 지정 인증 저장소를 제공합니다 .- 앱이 처음 시작될 때 인증 토큰을 새로 고칠 수도 있습니다. 앞서 보았듯이, 이렇게 하면 만료 날짜가 업데이트되어 사용자가 다시 로그인해야 할 가능성이 최소화됩니다. 사용자 지정 인증 스토어가 자동으로 토큰을 저장합니다.
앱을 닫고 다시 시작하세요. 여전히 로그인되어 있어야 합니다.
사용자 정의 .을 구현하는 데 대한 몇 가지 추가 정보는 여기 와 여기를 참조하세요 AuthStore.
로그아웃
이 튜토리얼에서 다룰 마지막 인증 관련 단계는 로그아웃입니다. 다른 단계와 마찬가지로 쉽습니다.
PocketBase는 사용자의 세션 데이터나 액세스 토큰을 서버에 저장하지 않습니다. 따라서 사용자를 로그아웃하려면 클라이언트 측에서 인증 데이터를 지우기만 하면 됩니다.
사용자가 로그아웃 버튼을 누를 때 실행되는 메서드를 추가합니다 .
Future< void > signOut () async {
pb.authStore.clear(); statusNotifier.value
= ' 로그아웃됨' ; }
그거 쉬운 일이지?
앱을 새로 고침하고 테스트해 보세요.

잊어버린 비밀번호를 재설정하거나 이메일 변경을 요청하는 등 나중에 하고 싶을 수 있는 다른 인증 작업이 있습니다. 자세한 내용은 PocketBase 설명서를 확인할 수 있습니다 . 사실, 관리자 대시보드에서 API Preview를 선택하면 모든 작업을 수행하는 방법에 대한 코드 샘플이 제공됩니다.

다음 섹션에서는 Flutter 클라이언트에서 CRUD 작업을 수행할 수 있도록 일반 컬렉션을 추가해 보겠습니다.
새로운 컬렉션 만들기
관리자 대시보드에서 새 컬렉션 버튼을 클릭합니다.

필드 추가
새 창이 나타납니다. 다음 지시에 따라 아래 이미지와 일치시키세요.
- 사용자 시험 점수를 저장하는 컬렉션을 만들 테니 컬렉션 이름에 점수를 작성하세요.
- PocketBase에는 세 가지 유형의 컬렉션이 있습니다. 사용자가 이 컬렉션의 내용을 편집할 수 있게 하려고 하므로 오른쪽 상단의 드롭다운 메뉴에서 Base를 선택합니다. (이것이 기본값입니다.)
- 필드 탭 에서 새 필드를 클릭하여 두 개의 새 필드를 추가합니다.
- Relation을 선택 하고 이름을 user 로 지정합니다 . Select collection 에서 users 컬렉션을 선택합니다 . 이렇게 하면
user필드가 컬렉션에 연결됩니다users. (SQL에서 테이블에 외래 키를 추가하는 것과 같습니다.) - 새 필드를 다시 클릭 하고 이번에는 숫자 필드를 추가합니다. 점수 라고 부르세요 .

API 규칙 추가
보안상의 이유로, 기본적으로 관리자 사용자만 컬렉션을 읽고 쓸 수 있습니다. 그러나 Flutter 앱의 사용자가 자신의 데이터를 편집할 수 있도록 허용해야 합니다. PocketBase는 API 규칙으로 이를 처리합니다.
API 규칙 탭을 클릭하세요 .

다섯 가지 다른 카테고리가 있습니다. 목록/검색 규칙은 레코드 목록을 요청하는 반면, 보기 규칙은 단일 레코드를 요청하는 것입니다. 사용자는 다른 사람의 점수가 아닌 자신의 시험 점수만 볼 수 있기를 원합니다. 따라서 두 카테고리 모두에 다음 규칙을 추가합니다.
사용자 = @request.auth.id
즉, 컬렉션 user의 필드는 scores요청의 인증된 사용자 ID와 일치해야 합니다. 이렇게 하면 다른 모든 사용자를 효과적으로 걸러낼 수 있습니다.
Create 및 Update 에도 마찬가지입니다 . 그러나 시험 점수가 0~100 범위 내에 있도록 강제하고 싶을 것입니다. 다음 규칙을 두 범주에 추가합니다.
사용자 = @request.auth.id &&
@request.data.score >= 0 &&
@request.data.score <= 100
이렇게 하면 score들어오는 요청의 필드가 적절한 범위 내에 있는지 확인할 수 있습니다.
마지막으로, 사용자는 자신의 점수만 삭제할 수 있어야 하므로 삭제 규칙에 다음을 추가하세요.
사용자 = @request.auth.id
완료되면 관리자 대시보드 오른쪽 하단에 있는 '만들기' 버튼을 클릭하여 변경 사항을 저장합니다.
Flutter에서 레코드 생성
Flutter 앱으로 돌아와서 사용자가 Flutter 앱에서 생성 버튼 을 누를 때 호출되는 메서드를 추가합니다 .
Future<void> create () 비동기 {
최종 본문 = < String , 동적 >{
"user" : pb.authStore.model.id,
"score" : 89 ,
};
최종 레코드 = await pb.collection( 'scores' ).create(body: body);
print (레코드);
}
새 사용자를 추가할 때와 마찬가지로 다시 이 방법을 사용하고 있습니다 create. 하지만 이번에는 컬렉션에 레코드를 만들고 있습니다 scores. 맵의 키( user및 score)가 body컬렉션을 만들 때 선택한 필드 이름과 일치하는지 확인하세요.
앱을 새로 고침하고 Create 버튼을 누릅니다. 다음에 대한 결과가 표시되어야 합니다 record.
{
"id" : "k4oaijxf47jroc0" ,
"created" : "2024-01-26 09:39:27.934Z" ,
"updated" : "2024-01-26 09:39:27.934Z" ,
"collectionId" : "0q5mu8dg1ohw7iz" ,
"collectionName" : "scores" ,
"expand" : { } ,
"score" : 89 ,
"user" : "79yvk2r0lxnt6ob"
}
좋습니다. 잘 작동하고 있습니다.
향후 단계를 위해 더 많은 사용자 데이터가 필요합니다. 지금 만들어 보겠습니다. signUp및 signIn메서드의 내용을 변경하여 .이라는 이름의 새 사용자를 추가합니다 Mary.
Future< void > signUp() async {
final body = < String , dynamic >{
"username" : "Mary" , // 업데이트됨
"email" : "mary@example.com" , // 업데이트됨
"password" : "12345678" ,
"passwordConfirm" : "12345678" ,
"name" : "Mary Smith" // 업데이트됨
};
final record = await pb.collection( 'users' ).create(body: body);
print (record);
}
Future< void > signIn() async {
final authData = await pb
.collection( 'users' )
.authWithPassword( 'mary@example.com' , '12345678' ); // 업데이트됨
print (authData);
statusNotifier.value = (pb.authStore.isValid) ? '로그인됨' : '로그아웃됨' ;
}
이제 앱을 새로 고침하고 가입 , 로그인 , 생성을 순서대로 누르세요.
다음으로, 메서드의 를 92로 변경합니다 score. create그런 다음 앱을 새로 고친 후 만들기 버튼을 다시 누릅니다.
이제 점수 테이블에 세 개의 레코드가 있어야 합니다. 하나는 Bob의 레코드이고 두 개는 Mary의 레코드입니다. 관리자 대시보드로 가서 새로 고침 버튼을 눌러 확인하세요.

좋아요! 잘 됐어요. 새로운 레코드 3개를 만들었습니다.
레코드 목록 읽기
다음으로 한 사용자의 모든 기록 목록을 가져오려고 합니다. 현재 Mary로 로그인되어 있으므로 Mary의 시험 점수 두 개를 모두 받을 것으로 예상합니다. 그리고 규칙을 올바르게 설정하면 Bob의 점수는 받지 못할 것입니다.
사용자가 읽기 버튼 을 누를 때 실행되는 메서드를 추가합니다 .
Future< void > read () 비동기 {
최종 레코드 = await pb.collection( 'scores' ).getFullList(
sort: '-score' ,
);
print(records);
}
몇 가지 참고 사항은 다음과 같습니다.
getFullList컬렉션의 모든 레코드를 반환합니다(정의한 API 규칙에 따라 필터링). 레코드가 너무 많으면 .을 사용하여 결과를 페이지별로 나눌 수 있습니다getList.sort정렬할 필드를 정의합니다. 이 경우에는score.-필드 이름 앞에 대시가 있는 경우 역순으로 정렬하고 싶다는 의미입니다. 이 경우에는 높은 점수에서 낮은 점수 순입니다.- 추가로 포함할 수 있는 매개변수가 여러 개 있습니다
sort. 다른 매개변수는batch,filter, 및 입니다fields.
앱을 새로 고침하고 읽기 버튼을 누르세요. Mary의 두 시험 점수가 보일 것입니다.
[
{
"id" : "m1fkfqdv8r20oif" ,
"created" : "2024-01-26 09:51:04.343Z" ,
"updated" : "2024-01-26 09:51:04.343Z" ,
"collectionId" : "0q5mu8dg1ohw7iz" ,
"collectionName" : "scores" ,
"expand" : { } ,
"score" : 92 ,
"user" : "eokvshdupfla4v4"
} ,
{
"id" : "3fkk1f4sgwqgzje" ,
"created" : "2024-01-26 09:49:07.460Z" ,
"updated" : "2024-01-26 09:49:07.460Z" ,
"컬렉션ID" : "0q5mu8dg1ohw7iz" ,
"컬렉션이름" : "점수" ,
"확장" : { } ,
"점수" : 89 ,
"사용자" : "eokvshdupfla4v4"
}
]
79yvk2r0lxnt6obBob(사용자 ID )이 없는 걸 보니 다행입니다 . API 규칙이 작동했습니다. 또한 Mary의 점수는 가장 높은 것부터 가장 낮은 것까지 정렬되어 있습니다.
하지만 실제로 필요한 것보다 훨씬 많은 데이터가 있습니다. 필요한 것은 점수 ID와 점수 자체뿐입니다. . 매개변수를 사용하여 PocketBase에 원하는 필드를 알릴 수 있습니다 fields. getFullList다음 줄을 뒤에 추가합니다 sort: ‘-score’,.
필드: 'id,score' ,
여러 필드 이름을 결합할 때는 쉼표로 구분합니다.
다시 읽기 버튼을 누르면 이번에는 다음과 같은 화면이 나옵니다.
[
{
"id" : "m1fkfqdv8r20oif" ,
"생성됨" : "" ,
"업데이트됨" : "" , "컬렉션ID" : "" ,
" 컬렉션 이름 " : "" , "확장됨" : { } , "점수" : 92 } , { "id" : "3fkk1f4sgwqgzje" , "생성됨" : "" , "업데이트됨" : "" , "컬렉션ID" : "" , "컬렉션이름" : "" , "확장됨" : { } , "점수" : 89 } ]
PocketBase가 모든 빈 필드를 제공할 필요는 없었지만, 적어도 쓸모없는 값을 전달하는 작업은 생략할 수 있었습니다.
레코드 업데이트
메리는 89점이라는 점수에 만족하지 않습니다. 그녀는 더 높은 점수를 원합니다. 이 단계에서는 가장 낮은 점수를 100점으로 대체합니다.
업데이트 버튼을 누르면 호출되는 메서드를 만듭니다 .
Future< void > update () async {
// 가장 낮은 점수를 가진 레코드 찾기
final recordList = await pb.collection ( 'scores' ) .getList (
page : 1 ,
perPage : 1 ,
skipTotal : true ,
sort : 'score' ,
fields : 'id,score' ,
);
print (recordList);
final record = recordList.items.first;
// 레코드 업데이트
final body = <String, dynamic>{ "score" : 100 };
final updatedRecord = await pb.collection ( ' scores' ) .update (
record.id,
body : body,
);
print (updatedRecord);
}
다음은 몇 가지 참고 사항입니다.
- 이번에는 하나의 레코드만 필요하기 때문에
getListrather를 사용합니다.getFullList - 같은 이유로, 당신은 또한 1
page과 1개의 레코드 만 선택합니다perPage. 당신은 페이지나 레코드의 총 수에 관심이 없으므로, 할 수 있습니다skipTotal. 이 모든 것은 성능 최적화입니다. - 레코드가 있으면
score레코드 ID를 사용하여 필드를 업데이트할 수 있습니다.
앱을 새로 고침하고 업데이트 버튼을 누르세요. 다음과 같은 화면이 표시됩니다.
{
"페이지" : 1 ,
"페이지당" : 1 ,
"총항목" :- 1 ,
"총페이지" :- 1 ,
"항목" : [
{
"id" : "3fkk1f4sgwqgzje" ,
"생성됨" : "" ,
"업데이트됨" : "" ,
"컬렉션Id" : "" ,
"컬렉션이름" : "" ,
"확장" : {},
"점수" : 89
}
]
}
{
"id" : "3fkk1f4sgwqgzje" ,
"생성됨" : "2024-01-26 09:49:07.460Z" ,
"업데이트됨" : "2024-01-27 04:10:09.986Z" ,
"컬렉션Id" : "0q5mu8dg1ohw7iz" ,
"collectionName" : "점수" ,
"expand" : {},
"점수" : 100 ,
"user" : "eokvshdupfla4v4"
}
89점이었던 점수가 100점으로 업데이트되었습니다.
scores대시보드에서 컬렉션을 새로 고치면 동일한 결과를 볼 수도 있습니다 .

음, 생각해보니 학생들이 자신의 시험 점수를 업데이트하도록 허용하는 것은 그렇게 좋은 생각이 아닐 겁니다. API 규칙을 변경하고 심지어 와 같은 사용자 역할을 도입하고 싶을 수도 있습니다 .teacherstudent
레코드 삭제
이 튜토리얼에서 구현할 마지막 작업은 레코드를 삭제하는 방법입니다. 알아야 할 것은 레코드 ID뿐입니다.
사용자가 삭제 버튼 을 누를 때 호출되는 메서드를 추가합니다 .
Future< void > delete() async {
// 가장 낮은 점수를 가진 레코드 찾기
final recordList = await pb.collection( 'scores' ).getList(
page: 1 ,
perPage: 1 ,
skipTotal: true ,
sort: 'score' ,
fields: 'id,score' ,
);
final record = recordList.items.first;
// 레코드 삭제
await pb.collection( 'scores' ).delete(record.id);
}
앱을 새로 고치고 Delete 버튼을 누릅니다. 반환 값은 없지만 scores대시보드에서 컬렉션을 새로 고치면 Mary가 값 하나를 놓친 것을 볼 수 있습니다.

이제 튜토리얼의 마지막입니다. 여기까지 성공적으로 따라왔다면 PocketBase가 어떻게 작동하는지 잘 알고 계실 겁니다.
계속 진행 중
튜토리얼은 오류 처리를 구현하지 않았습니다. PocketBase 호출을 try-catch블록으로 래핑하여 처리할 수 있습니다.
서버를 배포하는 방법은 설명서의 프로덕션으로 전환 섹션을 참조하세요 .
마지막 생각
저는 PocketBase를 정말 좋아합니다. 제가 찾아본 셀프호스팅 인증 백엔드를 설정하는 가장 쉬운 방법입니다. 하지만, 제가 길을 따라 발견한 몇 가지 주의 사항이 있습니다.
- 현재 대량 생성, 업데이트 및 삭제 작업은 지원되지 않습니다. 즉, 사용자가 많은 데이터를 가져오거나 한 번에 여러 레코드를 업데이트 또는 삭제하려는 경우 이를 수행하는 유일한 방법은 한 번에 한 레코드를 처리하는 것입니다. 수천 개의 레코드에 대해 이를 수행해야 하는 경우 거래 차단이 될 수 있습니다. 이 주제에 대한 GitHub에 이슈가 열려 있지만 해결책은 사소하지 않은 것으로 보이며 현재 1.0 로드맵 에서 상태는 보류 중입니다 .
- PocketBase를 확장 하고 추가 API 경로를 정의하는 것과 같은 작업을 할 수 있습니다 . 그러나 Go 또는 JavaScript를 사용해야 합니다. 안타깝게도 Dart는 옵션이 아닙니다.
이 두 가지 단점 때문에 저는 이렇게 생각하게 되었습니다. PocketBase를 인증 서버로 사용하고 동일한 컴퓨터에서 Dart Shelf 서버를 실행 하여 데이터베이스 작업과 기타 로직을 처리하면 어떨까요? 그렇게 하는 것도 이상적이지는 않지만, 효과가 있을 것 같습니다. 이를 위해 Flutter 클라이언트 앱은 먼저 PocketBase로 인증하고 액세스 토큰을 받습니다. 그런 다음 클라이언트는 헤더에 있는 토큰을 AuthorizationDart 서버로 전달합니다. Dart 서버는 PocketBase로 토큰을 검증하고 유효한 경우 사용자가 요청한 작업을 수행합니다. 이 기능은 PocketBase에 내장되어 있지 않지만 작성자는 .을 호출하여 토큰을 검증할 수 있다는 것을 인정합니다 authRefresh. 자세한 내용은 이 GitHub 토론을 읽어보세요 .
업데이트 : Dart 서버에서 PostgreSQL을 사용하는 방법에 대한 튜토리얼을 작성했습니다. 다른 단계는 PocketBase 액세스 토큰으로 호출을 인증하는 것입니다. 해당 기사를 여기에서 읽어보세요: Dart 서버에서 PostgreSQL 사용 .
[출처] https://suragch.medium.com/a-pocketbase-backend-for-flutter-and-dart-c962bea4e3f1
https://github.com/suragch/flutter_pocketbase_tutorial?tab=readme-ov-file
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
댓글 0
| 번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
|---|---|---|---|---|
| 1 |
[react native] 2025년 리액트 네이티브로 프로젝트 시작하기
| 졸리운_곰 | 2025.08.15 | 241 |

