Compare commits

...

15 commits

Author SHA1 Message Date
thomashii
b3b5d01aec Updated log message 2022-04-26 08:22:40 +08:00
thomashii
563f7f8dde Updated to SDK 2.16.0 2022-04-26 08:11:53 +08:00
thomashii
8facd65c14 Updated packages 2022-03-18 09:20:40 +08:00
thomashii
d8c3736955 Updated graphql template 2021-09-25 18:39:19 +08:00
thomashii
8c63811c50 Updated packages 2021-08-19 08:25:45 +08:00
thomashii
5c4eded653 Updated graphql 2021-07-17 13:05:34 +08:00
thomashii
16565c26cd Updated angel3-graphql 2021-06-14 09:37:53 +08:00
thomashii
9d9a94965e Migrated to NNBD 2021-06-14 09:28:20 +08:00
thomashii
77b61d30ed Graphql template for SDK 2.12.x 2021-03-07 20:59:21 +08:00
Tobe O
35b4706078 Merge branch 'master' into graphql 2019-10-09 14:27:01 -04:00
Tobe O
9f59ab1336 Merge branch 'master' into graphql 2019-10-09 14:22:05 -04:00
Tobe O
45f1a2f6f6 Merge branch 'master' into graphql 2019-05-01 19:33:15 -04:00
Tobe O
708502e0dc Merge branch 'master' into graphql 2019-05-01 19:30:25 -04:00
Tobe O
0148812c60 Add Graphiql redirect, css, etc. 2019-04-29 13:20:47 -04:00
Tobe O
9cfb56f123 Complete todo api 2019-04-29 13:12:23 -04:00
30 changed files with 418 additions and 274 deletions

3
.github/FUNDING.yml vendored
View file

@ -1,3 +0,0 @@
# These are supported funding model platforms
github: [thosakwe]

25
.gitignore vendored
View file

@ -37,25 +37,7 @@ pubspec.lock
# User-specific stuff: # User-specific stuff:
.idea/workspace.xml .idea/workspace.xml
.idea/tasks.xml
.idea/dictionaries
.idea/vcs.xml
.idea/jsLibraryMappings.xml
# Sensitive or high-churn files:
.idea/dataSources.ids
.idea/dataSources.xml
.idea/dataSources.local.xml
.idea/sqlDataSources.xml
.idea/dynamic.xml
.idea/uiDesigner.xml
# Gradle:
.idea/gradle.xml
.idea/libraries
# Mongo Explorer plugin:
.idea/mongoSettings.xml
## File-based project format: ## File-based project format:
*.iws *.iws
@ -78,11 +60,8 @@ crashlytics-build.properties
fabric.properties fabric.properties
### VSCode template ### VSCode template
.vscode/* .vscode/
!.vscode/settings.json .metals/
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
logs/ logs/
*.pem *.pem

View file

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.pub" />
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Dart SDK" level="project" />
<orderEntry type="library" name="Dart Packages" level="project" />
</component>
</module>

View file

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectInspectionProfilesVisibleTreeState">
<entry key="Project Default">
<profile-state>
<expanded-state>
<State>
<id />
</State>
<State>
<id>General</id>
</State>
<State>
<id>XPath</id>
</State>
</expanded-state>
<selected-state>
<State>
<id>AngularJS</id>
</State>
</selected-state>
</profile-state>
</entry>
</component>
</project>

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/angel.iml" filepath="$PROJECT_DIR$/.idea/angel.iml" />
</modules>
</component>
</project>

View file

@ -1,8 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="dev.dart" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application" singleton="true" nameIsGenerated="true">
<option name="VMOptions" value="--observe" />
<option name="filePath" value="$PROJECT_DIR$/bin/dev.dart" />
<option name="workingDirectory" value="$PROJECT_DIR$" />
<method />
</configuration>
</component>

View file

@ -1,11 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="prod.dart" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application" singleton="true" nameIsGenerated="true">
<option name="checkedMode" value="false" />
<option name="envs">
<entry key="ANGEL_ENV" value="production" />
</option>
<option name="filePath" value="$PROJECT_DIR$/bin/prod.dart" />
<option name="workingDirectory" value="$PROJECT_DIR$" />
<method />
</configuration>
</component>

7
CHANGELOG.md Normal file
View file

@ -0,0 +1,7 @@
# Change Log
## 1.0.0
* Changed to use `angel3` packages
* Updated to support NNBD
* Updated linter to `package:lints`

View file

@ -1,14 +1,23 @@
FROM google/dart:latest FROM dart:latest
COPY ./ ./ # Copy all the source code
COPY ./config /app/config
COPY ./lib /app/lib
COPY ./bin /app/bin
COPY ./views /app/views
COPY ./web /app/web
COPY ./*.yaml /app/
# Install dependencies, pre-build WORKDIR /app
RUN pub get RUN dart pub upgrade
# Optionally build generaed sources. # Optionally build generated sources.
# RUN pub run build_runner build # RUN pub run build_runner build
# Set environment, start server # Set environment, start server in JIT mode
ENV ANGEL_ENV=production ENV ANGEL_ENV=production
EXPOSE 3000 EXPOSE 3000
CMD dart bin/prod.dart CMD dart ./bin/prod.dart -p 3000 -a 0.0.0.0
# Use -j flag to set higher number of isolates
#CMD dart ./bin/prod.dart -p 3000 -a 0.0.0.0 -j 50

42
LICENSE
View file

@ -1,21 +1,29 @@
The MIT License (MIT) BSD 3-Clause License
Copyright (c) 2016 angel-dart Copyright (c) 2021, dukefirehawk.com
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy Redistribution and use in source and binary forms, with or without
of this software and associated documentation files (the "Software"), to deal modification, are permitted provided that the following conditions are met:
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all 1. Redistributions of source code must retain the above copyright notice, this
copies or substantial portions of the Software. list of conditions and the following disclaimer.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2. Redistributions in binary form must reproduce the above copyright notice,
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, this list of conditions and the following disclaimer in the documentation
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE and/or other materials provided with the distribution.
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 3. Neither the name of the copyright holder nor the names of its
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE contributors may be used to endorse or promote products derived from
SOFTWARE. this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,60 +1,35 @@
[![The Angel Framework](https://angel-dart.github.io/assets/images/logo.png)](https://angel-dart.dev) # Graphql Starter Application for Angel3 framework
[![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/angel_dart/discussion) This is a graphql starter application for [Angel3 framework](https://angel3-framework.web.app) which is a full-stack Web framework in Dart.
[![Pub](https://img.shields.io/pub/v/angel_framework.svg)](https://pub.dartlang.org/packages/angel_framework)
[![Build status](https://travis-ci.org/angel-dart/framework.svg?branch=master)](https://travis-ci.org/angel-dart/framework)
![License](https://img.shields.io/github/license/angel-dart/framework.svg)
**A polished, production-ready backend framework in Dart.**
*Note: This repo is an application boilerplate ,and not the underlying framework library.*
-----
## About
Angel is a full-stack Web framework in Dart. It aims to
streamline development by providing many common features
out-of-the-box in a consistent manner.
With features like the following, Angel is the all-in-one framework you should choose to build your next project:
* [GraphQL Support](https://github.com/angel-dart/graphql)
* [PostgreSQL ORM](https://github.com/angel-dart/orm)
* [Dependency Injection](https://docs.angel-dart.dev/guides/dependency-injection)
* And [much more](https://github.com/angel-dart)...
## Installation & Setup ## Installation & Setup
Once you have [Dart](https://www.dartlang.org/) installed, bootstrapping a project is as simple as running a few shell commands: 1. Download and install [Dart](https://dart.dev/get-dart).
Install the [Angel CLI](https://github.com/angel-dart/cli): ### Development
```bash 1. Run the following command to start Angel3 server in dev mode to *hot-reloaded* on file changes:
pub global activate angel_cli
```
Bootstrap a project: ```bash
dart --observe bin/dev.dart
```
```bash 2. Modify the code and watch the changes applied to the application
angel init hello
```
You can even have your server run and be *hot-reloaded* on file changes: ### Production
```bash 1. Run the following command:
dart --observe bin/dev.dart
```
Next, check out the [detailed documentation](https://docs.angel-dart.dev/v/2.x) to learn to flesh out your project. ```bash
dart bin/prod.dart
```
## Examples and Documentation 2. Run as docker. Edit and run the provided `Dockerfile` to build the image.
Visit the [documentation](https://docs.angel-dart.dev/v/2.x)
for dozens of guides and resources, including video tutorials,
to get up and running as quickly as possible with Angel.
Examples and complete projects can be found ## Resources
[here](https://github.com/angel-dart/examples-v2).
Visit the [Developer Guide](https://angel3-docs.dukefirehawk.com/guides) for dozens of guides and resources, including video tutorials, to get up and running as quickly as possible with Angel3.
You can also view the [API Documentation](http://www.dartdocs.org/documentation/angel_framework/latest). Examples and complete projects can be found [here](https://angel3-framework.web.app/#/examples).
There is also an [Awesome Angel :fire:](https://github.com/angel-dart/awesome-angel) list.
You can also view the [API Documentation](https://pub.dev/documentation/angel3_framework/latest/).

View file

@ -1,8 +1 @@
include: package:pedantic/analysis_options.yaml include: package:lints/recommended.yaml
analyzer:
strong-mode:
implicit-casts: false
linter:
rules:
- unnecessary_const
- unnecessary_new

View file

@ -1,17 +1,17 @@
import 'dart:io'; import 'dart:io';
import 'package:angel/src/pretty_logging.dart'; import 'package:belatuk_pretty_logging/belatuk_pretty_logging.dart';
import 'package:angel/angel.dart'; import 'package:angel/angel.dart';
import 'package:angel_container/mirrors.dart'; import 'package:angel3_container/mirrors.dart';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel_hot/angel_hot.dart'; import 'package:angel3_hot/angel3_hot.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
main() async { void main() async {
// Watch the config/ and web/ directories for changes, and hot-reload the server. // Watch the config/ and web/ directories for changes, and hot-reload the server.
hierarchicalLoggingEnabled = true; hierarchicalLoggingEnabled = true;
var hot = HotReloader(() async { var hot = HotReloader(() async {
var logger = Logger.detached('{{angel}}') var logger = Logger.detached('Angel3')
..level = Level.ALL ..level = Level.ALL
..onRecord.listen(prettyLog); ..onRecord.listen(prettyLog);
var app = Angel(logger: logger, reflector: MirrorsReflector()); var app = Angel(logger: logger, reflector: MirrorsReflector());
@ -24,5 +24,5 @@ main() async {
var server = await hot.startServer('127.0.0.1', 3000); var server = await hot.startServer('127.0.0.1', 3000);
print( print(
'{{angel}} server listening at http://${server.address.address}:${server.port}'); '[Angel3] server listening at http://${server.address.address}:${server.port}');
} }

View file

@ -1,6 +1,6 @@
import 'package:angel/angel.dart'; import 'package:angel/angel.dart';
import 'package:angel_container/mirrors.dart'; import 'package:angel3_container/mirrors.dart';
import 'package:angel_production/angel_production.dart'; import 'package:angel3_production/angel3_production.dart';
// NOTE: By default, the Runner class does not use the `MirrorsReflector`, or any // NOTE: By default, the Runner class does not use the `MirrorsReflector`, or any
// reflector, by default. // reflector, by default.
@ -17,7 +17,7 @@ import 'package:angel_production/angel_production.dart';
// so use it if possible. // so use it if possible.
// //
// However, the following alternatives exist: // However, the following alternatives exist:
// * Generation via `package:angel_container_generator` // * Generation via `package:angel3_container_generator`
// * Creating an instance of `StaticReflector` // * Creating an instance of `StaticReflector`
// * Manually implementing the `Reflector` interface (cumbersome; not recommended) // * Manually implementing the `Reflector` interface (cumbersome; not recommended)
// //
@ -25,6 +25,5 @@ import 'package:angel_production/angel_production.dart';
// so in the meantime, visit the Angel chat for further questions: // so in the meantime, visit the Angel chat for further questions:
// //
// https://gitter.im/angel_dart/discussion // https://gitter.im/angel_dart/discussion
main(List<String> args) => void main(List<String> args) =>
Runner('{{angel}}', configureServer, reflector: MirrorsReflector()) Runner('Angel3', configureServer, reflector: MirrorsReflector()).run(args);
.run(args);

View file

@ -1,8 +1,6 @@
/// Your very own web application! /// Your very own web application!
library angel;
import 'dart:async'; import 'dart:async';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_framework/angel3_framework.dart';
import 'package:file/local.dart'; import 'package:file/local.dart';
import 'src/config/config.dart' as configuration; import 'src/config/config.dart' as configuration;
import 'src/routes/routes.dart' as routes; import 'src/routes/routes.dart' as routes;

View file

@ -1,9 +1,6 @@
/// Configuration for this Angel instance. import 'package:angel3_configuration/angel3_configuration.dart';
library angel.src.config; import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel3_jael/angel3_jael.dart';
import 'package:angel_configuration/angel_configuration.dart';
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_jael/angel_jael.dart';
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'plugins/plugins.dart' as plugins; import 'plugins/plugins.dart' as plugins;

View file

@ -1,8 +1,5 @@
/// Custom plugins go here.
library angel.src.config.plugins;
import 'dart:async'; import 'dart:async';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_framework/angel3_framework.dart';
Future configureServer(Angel app) async { Future configureServer(Angel app) async {
// Include any plugins you have made here. // Include any plugins you have made here.

11
lib/src/models/todo.dart Normal file
View file

@ -0,0 +1,11 @@
import 'package:angel3_serialize/angel3_serialize.dart';
import 'package:graphql_schema2/graphql_schema2.dart';
part 'todo.g.dart';
@graphQLClass
@serializable
abstract class _Todo extends Model {
String? get text;
bool? get isComplete;
}

155
lib/src/models/todo.g.dart Normal file
View file

@ -0,0 +1,155 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'todo.dart';
// **************************************************************************
// JsonModelGenerator
// **************************************************************************
@generatedSerializable
class Todo extends _Todo {
Todo({this.id, this.text, this.isComplete, this.createdAt, this.updatedAt});
@override
final String? id;
@override
final String? text;
@override
final bool? isComplete;
@override
final DateTime? createdAt;
@override
final DateTime? updatedAt;
Todo copyWith(
{String? id,
String? text,
bool? isComplete,
DateTime? createdAt,
DateTime? updatedAt}) {
return Todo(
id: id ?? this.id,
text: text ?? this.text,
isComplete: isComplete ?? this.isComplete,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt);
}
@override
bool operator ==(other) {
return other is _Todo &&
other.id == id &&
other.text == text &&
other.isComplete == isComplete &&
other.createdAt == createdAt &&
other.updatedAt == updatedAt;
}
@override
int get hashCode {
return hashObjects([id, text, isComplete, createdAt, updatedAt]);
}
@override
String toString() {
return 'Todo(id=$id, text=$text, isComplete=$isComplete, createdAt=$createdAt, updatedAt=$updatedAt)';
}
Map<String, dynamic> toJson() {
return TodoSerializer.toMap(this);
}
}
// **************************************************************************
// SerializerGenerator
// **************************************************************************
const TodoSerializer todoSerializer = TodoSerializer();
class TodoEncoder extends Converter<Todo, Map> {
const TodoEncoder();
@override
Map convert(Todo model) => TodoSerializer.toMap(model);
}
class TodoDecoder extends Converter<Map, Todo> {
const TodoDecoder();
@override
Todo convert(Map map) => TodoSerializer.fromMap(map);
}
class TodoSerializer extends Codec<Todo, Map> {
const TodoSerializer();
@override
TodoEncoder get encoder => const TodoEncoder();
@override
TodoDecoder get decoder => const TodoDecoder();
static Todo fromMap(Map map) {
return Todo(
id: map['id'] as String?,
text: map['text'] as String?,
isComplete: map['is_complete'] as bool?,
createdAt: map['created_at'] != null
? (map['created_at'] is DateTime
? (map['created_at'] as DateTime?)
: DateTime.parse(map['created_at'].toString()))
: null,
updatedAt: map['updated_at'] != null
? (map['updated_at'] is DateTime
? (map['updated_at'] as DateTime?)
: DateTime.parse(map['updated_at'].toString()))
: null);
}
static Map<String, dynamic> toMap(_Todo model) {
return {
'id': model.id,
'text': model.text,
'is_complete': model.isComplete,
'created_at': model.createdAt?.toIso8601String(),
'updated_at': model.updatedAt?.toIso8601String()
};
}
}
abstract class TodoFields {
static const List<String> allFields = <String>[
id,
text,
isComplete,
createdAt,
updatedAt
];
static const String id = 'id';
static const String text = 'text';
static const String isComplete = 'is_complete';
static const String createdAt = 'created_at';
static const String updatedAt = 'updated_at';
}
// **************************************************************************
// _GraphQLGenerator
// **************************************************************************
/// Auto-generated from [Todo].
final GraphQLObjectType todoGraphQLType =
objectType('Todo', isInterface: false, interfaces: [], fields: [
field('id', graphQLString),
field('text', graphQLString),
field('is_complete', graphQLBoolean),
field('created_at', graphQLDate),
field('updated_at', graphQLDate),
field('idAsInt', graphQLInt)
]);

View file

@ -1,38 +0,0 @@
import 'package:angel_http_exception/angel_http_exception.dart';
import 'package:logging/logging.dart';
import 'package:io/ansi.dart';
/// Prints the contents of a [LogRecord] with pretty colors.
void prettyLog(LogRecord record) {
var code = chooseLogColor(record.level);
if (record.error == null) print(code.wrap(record.toString()));
if (record.error != null) {
var err = record.error;
if (err is AngelHttpException && err.statusCode != 500) return;
print(code.wrap(record.toString() + '\n'));
print(code.wrap(err.toString()));
if (record.stackTrace != null) {
print(code.wrap(record.stackTrace.toString()));
}
}
}
/// Chooses a color based on the logger [level].
AnsiCode chooseLogColor(Level level) {
if (level == Level.SHOUT)
return backgroundRed;
else if (level == Level.SEVERE)
return red;
else if (level == Level.WARNING)
return yellow;
else if (level == Level.INFO)
return cyan;
else if (level == Level.CONFIG ||
level == Level.FINE ||
level == Level.FINER ||
level == Level.FINEST) return lightGray;
return resetAll;
}

View file

@ -1,7 +1,5 @@
library angel.src.routes.controllers;
import 'dart:async'; import 'dart:async';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_framework/angel3_framework.dart';
Future configureServer(Angel app) async { Future configureServer(Angel app) async {
/// Controllers will not function unless wired to the application! /// Controllers will not function unless wired to the application!

View file

@ -0,0 +1,20 @@
import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel3_graphql/angel3_graphql.dart';
import 'package:graphql_server2/graphql_server2.dart';
import 'schema.dart';
/// Configures the [app] to server GraphQL.
void configureServer(Angel app) {
// Create a [GraphQL] service instance, using our schema.
var schema = createSchema(app);
var graphQL = GraphQL(schema);
// Mount a handler that responds to GraphQL queries.
app.all('/graphql', graphQLHttp(graphQL));
// In development, serve the GraphiQL IDE/editor.
// More info: https://github.com/graphql/graphiql
if (!app.environment.isProduction) {
app.get('/graphiql', graphiQL());
}
}

View file

@ -0,0 +1,22 @@
import 'package:angel3_framework/angel3_framework.dart';
import 'package:graphql_schema2/graphql_schema2.dart';
import 'todo.dart';
/// Creates a GraphQL schema that manages an in-memory store of
/// Todo items.
GraphQLSchema createSchema(Angel app) {
var queryType = objectType(
'TodoQuery',
fields: todoQueryFields(app),
);
var mutationType = objectType(
'TodoMutation',
fields: todoMutationFields(app),
);
return graphQLSchema(
queryType: queryType,
mutationType: mutationType,
);
}

View file

@ -0,0 +1,73 @@
import 'package:angel/src/models/todo.dart';
import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel3_graphql/angel3_graphql.dart';
import 'package:graphql_schema2/graphql_schema2.dart';
/// Find or create an in-memory Todo store.
MapService? _getTodoService(Angel app) {
const key = 'todoService';
// If there is already an existing singleton, return it.
if (app.container.hasNamed(key)) {
return app.container.findByName<MapService>(key);
}
// Create an in-memory service. We will use this
// as the backend to store Todo objects, serialized to Maps.
var mapService = MapService();
// Register this service as a named singleton in the app container,
// so that we do not inadvertently create another instance.
app.container.registerNamedSingleton(key, mapService);
return mapService;
}
/// Returns fields to be inserted into the query type.
Iterable<GraphQLObjectField> todoQueryFields(Angel app) {
var todoService = _getTodoService(app)!;
// Here, we use special resolvers to read data from our store.
return [
field(
'todos',
listOf(todoGraphQLType),
resolve: resolveViaServiceIndex(todoService),
),
field(
'todo',
todoGraphQLType,
resolve: resolveViaServiceRead(todoService),
inputs: [
GraphQLFieldInput('id', graphQLString.nonNullable()),
],
),
];
}
/// Returns fields to be inserted into the query type.
Iterable<GraphQLObjectField> todoMutationFields(Angel app) {
var todoService = _getTodoService(app)!;
var todoInputType = todoGraphQLType.toInputObject('TodoInput');
// This time, we use resolvers to modify the data in the store.
return [
field(
'createTodo',
todoGraphQLType,
resolve: resolveViaServiceCreate(todoService),
inputs: [
GraphQLFieldInput('data', todoInputType.nonNullable()),
],
),
field(
'modifyTodo',
todoGraphQLType,
resolve: resolveViaServiceModify(todoService),
inputs: [
GraphQLFieldInput('id', graphQLString.nonNullable()),
GraphQLFieldInput('data', todoInputType.nonNullable()),
],
),
];
}

View file

@ -1,21 +1,22 @@
/// This app's route configuration. import 'package:angel3_framework/angel3_framework.dart';
library angel.src.routes; import 'package:angel3_static/angel3_static.dart';
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_static/angel_static.dart';
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'controllers/controllers.dart' as controllers; import 'controllers/controllers.dart' as controllers;
import 'graphql/graphql.dart' as graphql;
/// Put your app routes here! /// Put your app routes here!
/// ///
/// See the wiki for information about routing, requests, and responses: /// See the wiki for information about routing, requests, and responses:
/// * https://github.com/angel-dart/angel/wiki/Basic-Routing /// * https://angel3-docs.dukefirehawk.com/guides/basic-routing
/// * https://github.com/angel-dart/angel/wiki/Requests-&-Responses /// * https://angel3-docs.dukefirehawk.com/guides/requests-and-responses
AngelConfigurer configureServer(FileSystem fileSystem) { AngelConfigurer configureServer(FileSystem fileSystem) {
return (Angel app) async { return (Angel app) async {
// Typically, you want to mount controllers first, after any global middleware. // Typically, you want to mount controllers first, after any global middleware.
await app.configure(controllers.configureServer); await app.configure(controllers.configureServer);
// Mount our GraphQL routes as well.
await app.configure(graphql.configureServer);
// Render `views/hello.jl` when a user visits the application root. // Render `views/hello.jl` when a user visits the application root.
app.get('/', (req, res) => res.render('hello')); app.get('/', (req, res) => res.render('hello'));
@ -27,7 +28,7 @@ AngelConfigurer configureServer(FileSystem fileSystem) {
// //
// Read the following two sources for documentation: // Read the following two sources for documentation:
// * https://medium.com/the-angel-framework/serving-static-files-with-the-angel-framework-2ddc7a2b84ae // * https://medium.com/the-angel-framework/serving-static-files-with-the-angel-framework-2ddc7a2b84ae
// * https://github.com/angel-dart/static // * https://pub.dev/packages/angel3_static
if (!app.environment.isProduction) { if (!app.environment.isProduction) {
var vDir = VirtualDirectory( var vDir = VirtualDirectory(
app, app,
@ -43,7 +44,7 @@ AngelConfigurer configureServer(FileSystem fileSystem) {
// Set our application up to handle different errors. // Set our application up to handle different errors.
// //
// Read the following for documentation: // Read the following for documentation:
// * https://github.com/angel-dart/angel/wiki/Error-Handling // * https://angel3-docs.dukefirehawk.com/guides/error-handling
var oldErrorHandler = app.errorHandler; var oldErrorHandler = app.errorHandler;
app.errorHandler = (e, req, res) async { app.errorHandler = (e, req, res) async {

View file

@ -1,8 +1,5 @@
/// Declare services here!
library angel.services;
import 'dart:async'; import 'dart:async';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_framework/angel3_framework.dart';
/// Configure our application to use *services*. /// Configure our application to use *services*.
/// Services must be wired to the app via `app.use`. /// Services must be wired to the app via `app.use`.

View file

@ -1,20 +1,24 @@
name: angel name: angel
description: An app that's going to be amazing pretty soon. description: A graphql starter application for Angel3 framework
publish_to: none # Ensure we don't accidentally publish our private code! ;) publish_to: none
environment: environment:
sdk: '>=2.0.0-dev <3.0.0' sdk: '>=2.16.0 <3.0.0'
homepage: https://github.com/angel-dart/angel
dependencies: dependencies:
angel_auth: ^2.0.0 # Supports stateless authentication via JWT angel3_auth: ^6.0.0
angel_configuration: ^2.0.0 # Loads application configuration, along with support for .env files. angel3_configuration: ^6.0.0
angel_framework: ^2.0.0 # The core server library. angel3_framework: ^6.0.0
angel_jael: ^2.0.0 # Server-side templating engine angel3_graphql: ^6.0.0
angel_production: ^1.0.0 # Production application runner. angel3_jael: ^6.0.0
angel_static: ^2.0.0 # Static file server angel3_production: ^6.0.0
angel_validate: ^2.0.0 # Allows for validation of input data angel3_static: ^6.0.0
angel3_validate: ^6.0.0
dev_dependencies: dev_dependencies:
angel_hot: ^2.0.0 # Hot-reloading support. :) angel3_hot: ^6.0.0
angel_test: ^2.0.0 # Utilities for testing Angel servers. angel3_serialize_generator: ^6.0.0
io: ^0.3.2 # For pretty printing. angel3_test: ^6.0.0
pedantic: ^1.0.0 # Enforces Dart style conventions. graphql_generator2: ^4.0.0
test: ^1.0.0 # For unit testing. belatuk_pretty_logging: ^4.0.0
build_runner: ^2.0.4
io: ^1.0.0
test: ^1.21.0
lints: ^1.0.0

View file

@ -1,6 +1,6 @@
import 'package:angel/angel.dart'; import 'package:angel/angel.dart';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel_test/angel_test.dart'; import 'package:angel3_test/angel3_test.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
// Angel also includes facilities to make testing easier. // Angel also includes facilities to make testing easier.
@ -19,8 +19,8 @@ import 'package:test/test.dart';
// here: // here:
// https://github.com/dart-lang/test // https://github.com/dart-lang/test
main() async { void main() async {
TestClient client; late TestClient client;
setUp(() async { setUp(() async {
var app = Angel(); var app = Angel();
@ -35,7 +35,7 @@ main() async {
test('index returns 200', () async { test('index returns 200', () async {
// Request a resource at the given path. // Request a resource at the given path.
var response = await client.get('/'); var response = await client.get(Uri.parse('/'));
// Expect a 200 response. // Expect a 200 response.
expect(response, hasStatus(200)); expect(response, hasStatus(200));

View file

@ -1,5 +1,8 @@
<extend src="layout.jael"> <extend src="layout.jael">
<block name="content"> <block name="content">
<div class="title">Angel</div> <div class="title">Angel</div>
<p>
<a href="/graphiql">Click here</a> to access GraphiQL.
</p>
</block> </block>
</extend> </extend>

View file

@ -11,6 +11,16 @@ body {
font-family: 'Lato', sans-serif; font-family: 'Lato', sans-serif;
} }
a {
color: rgb(8, 114, 175) !important;
font-weight: 900;
text-decoration: none;
}
p {
font-size: 1.3em;
}
.container { .container {
text-align: center; text-align: center;
display: table-cell; display: table-cell;