플러터.py | 양쪽 끝의 왕
오늘 우리는 Python 확장 기능인 Flask-RESTful 백엔드를 Flutter를 프런트엔드로 통합하여 매우 간단한 API를 활용할 것입니다.
요컨대, 우리는 FRONTEND의 왕과 BACKEND의 왕을 통합하고 있습니다.
🎨 Flutter 및 Flask-RESTful
Flutter은 크로스 플랫폼 및 고성능 앱을 개발하기 위한 UI 툴킷입니다. 매우 유연하며 Google에서 개발했습니다.
Flask-RESTful은 REST API를 신속하게 구축하기 위한 지원을 추가하는 Flask의 확장입니다. Python으로 구동됩니다.
🕸 REST API
REST API는 REST 아키텍처 스타일을 기반으로 하는 애플리케이션 프로그래밍 인터페이스(API)입니다. 여기에는 데이터를 보내고 가져오기 위한 GET, POST, DELETE 등과 같은 메서드가 포함됩니다. 모든 HTTP 메서드는 REST API와 함께 사용할 수 있습니다.
🧑🏻💻 첫 번째 REST API 작성
따라서 우리는 Python으로 구동되는 flask-restful 라이브러리를 사용할 것입니다. 따라서 첫 번째 단계는 라이브러리를 설치하는 것입니다. 우리 모두는
pip
가 Python에서 다양한 패키지를 설치할 수 있는 관리자라는 것을 알고 있습니다.pip install flask-restful
Mac OS:
pip
가 작동하지 않고 최신 Python 버전을 설치한 경우 pip3
를 선택하십시오. python
~ python3
키워드와 동일합니다.파일
app.py
을 생성하고 매우 간단한hello world
API 응답을 작성하여 매우 간단하게 시작할 것입니다.import flask
from flask_restful import Resource, Api
app = flask.Flask(__name__)
api = Api(app)
class HelloWorld(Resource):
def get(self):
return {
'hello': 'world',
}
api.add_resource(HelloWorld, '/')
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=8080)
Save this code
다음 명령을 실행합니다.
python app.py
오픈http://localhost:8080
이 모양을 위해 확장 JSON 뷰어를 사용하고 있습니다.
조금 더 깊게
이제 Flutter 프런트엔드에서 보여줄 수 있도록 이 API 응답을 좀 더 복잡하게 만들어 보겠습니다.
import flask
from flask_restful import Resource, Api
app = flask.Flask(__name__)
api = Api(app)
class HelloWorld(Resource):
def get(self):
data = [
'first',
'API',
'Response',
'with',
'random List',
'python',
]
return {
'data': data,
}
api.add_resource(HelloWorld, '/')
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=8080)
Save this code
이제
localhost
를 열면 다음과 같이 표시됩니다.💻 Flutter에 통합
flutter_bloc을 사용하여 REST API를 처리하고 이어서 큐빗과 상태를 처리하겠습니다. 따라서 프로젝트 구조는 다음과 같습니다.
.
모델
a
List<String>
만 포함하는 매우 간단한 모델 클래스부터 시작하겠습니다.import 'dart:convert';
class Data {
final List<String> words;
Data({
required this.words,
});
Data copyWith({
List<String>? words,
}) {
return Data(
words: words ?? this.words,
);
}
Map<String, dynamic> toMap() {
return <String, dynamic>{
'words': words,
};
}
factory Data.fromMap(Map<String, dynamic> map) {
return Data(
words: List<String>.from((map['words'] as List)),
);
}
String toJson() => json.encode(toMap());
factory Data.fromJson(String source) =>
Data.fromMap(json.decode(source) as Map<String, dynamic>);
@override
String toString() => 'Data(words: $words)';
@override
int get hashCode => words.hashCode;
}
Save this code
data_provider.dart
그런 다음
data_provider
계층의 API에서 데이터를 요청합니다.여기에서도 dio을 사용할 수 있습니다. 이것이 제가 선호하는 것입니다.
part of 'cubit.dart';
class DataDataProvider {
static Future<Data> fetch() async {
try {
final request = await http.get(Uri.parse('http://localhost:8080'));
return Data.fromJson(request.body);
} catch (e) {
throw Exception("Internal Server Error");
}
}
}
Save this code
저장소.다트
다음으로 API에서
cubits
로 데이터를 전달합니다.part of 'cubit.dart';
class DataRepository {
Future<Data> fetch() => DataDataProvider.fetch();
}
Save this code
state.dart
여기에서 몇 가지 다른 상태를 처리하고 있습니다.
part of 'cubit.dart';
@immutable
class DataState extends Equatable {
final Data? data;
final String? message;
const DataState({
this.data,
this.message,
});
@override
List<Object?> get props => [
data,
message,
];
}
@immutable
class DataDefault extends DataState {}
@immutable
class DataFetchLoading extends DataState {
const DataFetchLoading() : super();
}
@immutable
class DataFetchSuccess extends DataState {
const DataFetchSuccess({Data? data}) : super(data: data);
}
@immutable
class DataFetchFailed extends DataState {
const DataFetchFailed({String? message}) : super(message: message);
}
Save this code
큐빗 다트
마지막으로 데이터가 있는지 여부에 따라 상태를 생략합니다.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:http/http.dart' as http;
import 'package:jugaad/models/data.dart';
part 'data_provider.dart';
part 'repository.dart';
part 'state.dart';
class DataCubit extends Cubit<DataState> {
static DataCubit cubit(BuildContext context, [bool listen = false]) =>
BlocProvider.of<DataCubit>(context, listen: listen);
DataCubit() : super(DataDefault());
final repo = DataRepository();
Future<void> fetch() async {
emit(const DataFetchLoading());
try {
final data = await repo.fetch();
emit(DataFetchSuccess(data: data));
} catch (e) {
emit(DataFetchFailed(message: e.toString()));
}
}
}
Save this code
이제
BlocBuilder
를 사용하여 프런트엔드를 처리해 보겠습니다. 최종 제품은 다음과 같습니다.import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:jugaad/cubits/data/cubit.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(create: (_) => DataCubit()),
],
child: const MaterialApp(
debugShowCheckedModeBanner: false,
title: 'flutter.py',
home: DataScreen(),
),
);
}
}
class DataScreen extends StatefulWidget {
const DataScreen({Key? key}) : super(key: key);
@override
State<DataScreen> createState() => _DataScreenState();
}
class _DataScreenState extends State<DataScreen> {
@override
void initState() {
super.initState();
DataCubit.cubit(context).fetch();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: BlocBuilder<DataCubit, DataState>(
builder: (context, state) {
// loading
if (state is DataFetchLoading) {
return const Center(
child: CircularProgressIndicator(),
);
}
// success
else if (state is DataFetchSuccess) {
return ListView(
children: state.data!.words
.map(
(word) => ListTile(
title: Text(word),
),
)
.toList(),
);
}
// failure
else if (state is DataFetchFailed) {
return Center(
child: Text(state.message!),
);
}
// something unexpected
return const Center(
child: Text('Something went wrong'),
);
},
),
);
}
}
Save this code
그리고…… 🥁🥁🥁
Flask API의 데이터
🔥 복잡성++
더 많은 이해를 위해 API 응답을 좀 더 복잡하게 만든 다음 그에 따라 data.dart 모델 클래스를 변경하여 UI를 채울 것입니다.
API 응답
import flask
from flask_restful import Resource, Api
app = flask.Flask(__name__)
api = Api(app)
class HelloWorld(Resource):
def get(self):
data = [
{
'word': 'cat',
'type': 'animal',
},
{
'word': 'football',
'type': 'sports',
},
{
'word': 'rice',
'type': 'food',
},
]
return {
'data': data,
}
api.add_resource(HelloWorld, '/')
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=8080)
Save this code
Data.dart
import 'dart:convert';
class Data {
final String word;
final String type;
Data({
required this.word,
required this.type,
});
Data copyWith({
String? word,
String? type,
}) {
return Data(
word: word ?? this.word,
type: type ?? this.type,
);
}
Map<String, dynamic> toMap() {
return <String, dynamic>{
'word': word,
'type': type,
};
}
factory Data.fromMap(Map<String, dynamic> map) {
return Data(
word: map['word'] as String,
type: map['type'] as String,
);
}
String toJson() => json.encode(toMap());
factory Data.fromJson(String source) =>
Data.fromMap(json.decode(source) as Map<String, dynamic>);
@override
String toString() => 'Data(word: $word, type: $type)';
@override
int get hashCode => word.hashCode ^ type.hashCode;
@override
bool operator ==(covariant Data other) {
if (identical(this, other)) return true;
return other.word == word && other.type == type;
}
}
Save this code
UI의 최종 모습은 다음과 같습니다.
그게 다야! 나는 당신이 오늘 무언가를 배웠기를 바랍니다. 그리고 어떤 천재가 이 기사를 읽고 모든 소란을 쉽게 처리하는
flutter.py
라는 이름의 실제 다트 패키지를 생각해 내길 바랍니다!사람들은 항상 "Flutter와 함께 어떤 종류의 백엔드를 사용할 수 있나요?"와 같은 질문을 합니다. "Python을 백엔드로 사용할 수 있습니까?""Node.js를 사용할 수 있나요?"등등.
Flutter는 백엔드에 무엇이든 연결할 수 있는 UI 툴킷일 뿐입니다. 이를 위해 Flask-RESTful을 사용했지만 Django, Node.js 또는 선호하는 백엔드를 사용할 수 있습니다.
그러니 계속 탐색하고 계속 멋진 작품을 만드세요!
고마워요 여러분 #행복 설레개 💙
Reference
이 문제에 관하여(플러터.py | 양쪽 끝의 왕), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/get_pieces/flutterpy-kings-of-both-ends-5g4c텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)