forked from loafle/openapi-generator-original
Code generator for haskell-servant framework
This commit is contained in:
parent
3a2447634c
commit
4e3d94c005
@ -23,6 +23,7 @@ cd $APP_DIR
|
||||
./bin/clojure-petstore.sh
|
||||
./bin/csharp-petstore.sh
|
||||
./bin/dynamic-html.sh
|
||||
./bin/haskell-petstore.sh
|
||||
./bin/html-petstore.sh
|
||||
./bin/java-petstore.sh
|
||||
./bin/java-petstore-jersey2.sh
|
||||
|
31
bin/haskell-petstore.sh
Executable file
31
bin/haskell-petstore.sh
Executable file
@ -0,0 +1,31 @@
|
||||
#!/bin/sh
|
||||
|
||||
SCRIPT="$0"
|
||||
|
||||
while [ -h "$SCRIPT" ] ; do
|
||||
ls=`ls -ld "$SCRIPT"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
SCRIPT="$link"
|
||||
else
|
||||
SCRIPT=`dirname "$SCRIPT"`/"$link"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ! -d "${APP_DIR}" ]; then
|
||||
APP_DIR=`dirname "$SCRIPT"`/..
|
||||
APP_DIR=`cd "${APP_DIR}"; pwd`
|
||||
fi
|
||||
|
||||
executable="./modules/swagger-codegen-cli/target/swagger-codegen-cli.jar"
|
||||
|
||||
if [ ! -f "$executable" ]
|
||||
then
|
||||
mvn clean package
|
||||
fi
|
||||
|
||||
# if you've executed sbt assembly previously it will use that instead.
|
||||
export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
|
||||
ags="$@ generate -t modules/swagger-codegen/src/main/resources/haskell -i modules/swagger-codegen/src/test/resources/2_0/petstore.json -l haskell -o samples/server/petstore/haskell"
|
||||
|
||||
java $JAVA_OPTS -jar $executable $ags
|
@ -0,0 +1,345 @@
|
||||
package io.swagger.codegen.languages;
|
||||
|
||||
import io.swagger.codegen.*;
|
||||
import io.swagger.models.properties.*;
|
||||
import io.swagger.models.Model;
|
||||
import io.swagger.models.Operation;
|
||||
import io.swagger.models.Swagger;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.File;
|
||||
|
||||
public class HaskellServantCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
|
||||
// source folder where to write the files
|
||||
protected String sourceFolder = "src";
|
||||
protected String apiVersion = "0.0.1";
|
||||
|
||||
/**
|
||||
* Configures the type of generator.
|
||||
*
|
||||
* @return the CodegenType for this generator
|
||||
* @see io.swagger.codegen.CodegenType
|
||||
*/
|
||||
public CodegenType getTag() {
|
||||
return CodegenType.SERVER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a friendly name for the generator. This will be used by the generator
|
||||
* to select the library with the -l flag.
|
||||
*
|
||||
* @return the friendly name for the generator
|
||||
*/
|
||||
public String getName() {
|
||||
return "haskell";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns human-friendly help for the generator. Provide the consumer with help
|
||||
* tips, parameters here
|
||||
*
|
||||
* @return A string value for the help message
|
||||
*/
|
||||
public String getHelp() {
|
||||
return "Generates a HaskellServantCodegen library.";
|
||||
}
|
||||
|
||||
public HaskellServantCodegen() {
|
||||
super();
|
||||
|
||||
// set the output folder here
|
||||
outputFolder = "generated-code/HaskellServantCodegen";
|
||||
|
||||
/**
|
||||
* Models. You can write model files using the modelTemplateFiles map.
|
||||
* if you want to create one template for file, you can do so here.
|
||||
* for multiple files for model, just put another entry in the `modelTemplateFiles` with
|
||||
* a different extension
|
||||
*/
|
||||
modelTemplateFiles.put(
|
||||
"model.mustache", // the template to use
|
||||
".hs"); // the extension for each file to write
|
||||
|
||||
/**
|
||||
* Api classes. You can write classes for each Api file with the apiTemplateFiles map.
|
||||
* as with models, add multiple entries with different extensions for multiple files per
|
||||
* class
|
||||
*/
|
||||
apiTemplateFiles.put(
|
||||
"api.mustache", // the template to use
|
||||
".hs"); // the extension for each file to write
|
||||
|
||||
/**
|
||||
* Template Location. This is the location which templates will be read from. The generator
|
||||
* will use the resource stream to attempt to read the templates.
|
||||
*/
|
||||
embeddedTemplateDir = templateDir = "haskell";
|
||||
|
||||
/**
|
||||
* Api Package. Optional, if needed, this can be used in templates
|
||||
*/
|
||||
apiPackage = "Api";
|
||||
|
||||
/**
|
||||
* Model Package. Optional, if needed, this can be used in templates
|
||||
*/
|
||||
modelPackage = "Model";
|
||||
|
||||
/**
|
||||
* Reserved words. Override this with reserved words specific to your language
|
||||
*/
|
||||
// from https://wiki.haskell.org/Keywords
|
||||
reservedWords = new HashSet<String>(
|
||||
Arrays.asList(
|
||||
"as", "case", "of",
|
||||
"class", "data", // "data family", "data instance",
|
||||
"default", "deriving", // "deriving instance",
|
||||
"do",
|
||||
"forall", "foreign", "hiding",
|
||||
"id",
|
||||
"if", "then", "else",
|
||||
"import", "infix", "infixl", "infixr",
|
||||
"instance", "let", "in",
|
||||
"mdo", "module", "newtype",
|
||||
"proc", "qualified", "rec",
|
||||
"type", // "type family", "type instance",
|
||||
"where"
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Additional Properties. These values can be passed to the templates and
|
||||
* are available in models, apis, and supporting files
|
||||
*/
|
||||
additionalProperties.put("apiVersion", apiVersion);
|
||||
|
||||
/**
|
||||
* Supporting Files. You can write single files for the generator with the
|
||||
* entire object tree available. If the input file has a suffix of `.mustache
|
||||
* it will be processed by the template engine. Otherwise, it will be copied
|
||||
*/
|
||||
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
|
||||
supportingFiles.add(new SupportingFile("stack.mustache", "", "stack.yaml"));
|
||||
supportingFiles.add(new SupportingFile("haskell-servant-codegen.mustache", "", "haskell-servant-codegen.cabal"));
|
||||
supportingFiles.add(new SupportingFile("Setup.mustache", "", "Setup.hs"));
|
||||
supportingFiles.add(new SupportingFile("LICENSE", "", "LICENSE"));
|
||||
supportingFiles.add(new SupportingFile("Apis.mustache", "lib", "Apis.hs"));
|
||||
supportingFiles.add(new SupportingFile("Utils.mustache", "lib", "Utils.hs"));
|
||||
supportingFiles.add(new SupportingFile("Client.mustache", "client", "Main.hs"));
|
||||
supportingFiles.add(new SupportingFile("Server.mustache", "server", "Main.hs"));
|
||||
|
||||
/**
|
||||
* Language Specific Primitives. These types will not trigger imports by
|
||||
* the client generator
|
||||
*/
|
||||
languageSpecificPrimitives = new HashSet<String>(
|
||||
Arrays.asList(
|
||||
"Bool",
|
||||
"String",
|
||||
"Int",
|
||||
"Integer",
|
||||
"Float",
|
||||
"Char",
|
||||
"Double",
|
||||
"List",
|
||||
"FilePath"
|
||||
)
|
||||
);
|
||||
|
||||
typeMapping.clear();
|
||||
// typeMapping.put("enum", "NSString");
|
||||
typeMapping.put("array", "List");
|
||||
typeMapping.put("set", "Set");
|
||||
typeMapping.put("boolean", "Bool");
|
||||
typeMapping.put("string", "String");
|
||||
typeMapping.put("int", "Int");
|
||||
typeMapping.put("long", "Integer");
|
||||
typeMapping.put("float", "Float");
|
||||
// typeMapping.put("byte", "Byte");
|
||||
typeMapping.put("short", "Int");
|
||||
typeMapping.put("char", "Char");
|
||||
typeMapping.put("double", "Double");
|
||||
typeMapping.put("DateTime", "Integer");
|
||||
// typeMapping.put("object", "Map");
|
||||
typeMapping.put("file", "FilePath");
|
||||
|
||||
importMapping.clear();
|
||||
importMapping.put("Map", "qualified Data.Map as Map");
|
||||
|
||||
cliOptions.add(new CliOption(CodegenConstants.MODEL_PACKAGE, CodegenConstants.MODEL_PACKAGE_DESC));
|
||||
cliOptions.add(new CliOption(CodegenConstants.API_PACKAGE, CodegenConstants.API_PACKAGE_DESC));
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes a reserved word as defined in the `reservedWords` array. Handle escaping
|
||||
* those terms here. This logic is only called if a variable matches the reseved words
|
||||
*
|
||||
* @return the escaped term
|
||||
*/
|
||||
@Override
|
||||
public String escapeReservedWord(String name) {
|
||||
return name + "_";
|
||||
}
|
||||
|
||||
/**
|
||||
* Location to write model files. You can use the modelPackage() as defined when the class is
|
||||
* instantiated
|
||||
*/
|
||||
public String modelFileFolder() {
|
||||
return outputFolder + File.separatorChar + "lib" + File.separatorChar + modelPackage().replace('.', File.separatorChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Location to write api files. You can use the apiPackage() as defined when the class is
|
||||
* instantiated
|
||||
*/
|
||||
@Override
|
||||
public String apiFileFolder() {
|
||||
return outputFolder + File.separatorChar + "lib" + File.separatorChar + apiPackage().replace('.', File.separatorChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional - type declaration. This is a String which is used by the templates to instantiate your
|
||||
* types. There is typically special handling for different property types
|
||||
*
|
||||
* @return a string value used as the `dataType` field for model templates, `returnType` for api templates
|
||||
*/
|
||||
@Override
|
||||
public String getTypeDeclaration(Property p) {
|
||||
if(p instanceof ArrayProperty) {
|
||||
ArrayProperty ap = (ArrayProperty) p;
|
||||
Property inner = ap.getItems();
|
||||
return "[" + getTypeDeclaration(inner) + "]";
|
||||
}
|
||||
else if (p instanceof MapProperty) {
|
||||
MapProperty mp = (MapProperty) p;
|
||||
Property inner = mp.getAdditionalProperties();
|
||||
return "Map.Map String " + getTypeDeclaration(inner);
|
||||
}
|
||||
return super.getTypeDeclaration(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional - swagger type conversion. This is used to map swagger types in a `Property` into
|
||||
* either language specific types via `typeMapping` or into complex models if there is not a mapping.
|
||||
*
|
||||
* @return a string value of the type or complex model for this property
|
||||
* @see io.swagger.models.properties.Property
|
||||
*/
|
||||
@Override
|
||||
public String getSwaggerType(Property p) {
|
||||
String swaggerType = super.getSwaggerType(p);
|
||||
String type = null;
|
||||
if(typeMapping.containsKey(swaggerType)) {
|
||||
type = typeMapping.get(swaggerType);
|
||||
if(languageSpecificPrimitives.contains(type))
|
||||
return toModelName(type);
|
||||
}
|
||||
else
|
||||
type = swaggerType;
|
||||
return toModelName(type);
|
||||
}
|
||||
|
||||
private String capturePath(String path, List<CodegenParameter> pathParams) {
|
||||
for (CodegenParameter p : pathParams) {
|
||||
String pName = "{"+p.baseName+"}";
|
||||
if (path.indexOf(pName) >= 0) {
|
||||
path = path.replace(pName, "Capture " + "\""+p.baseName+"\" " + p.dataType);
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private String queryPath(String path, List<CodegenParameter> queryParams) {
|
||||
for (CodegenParameter p : queryParams) {
|
||||
path += " :> QueryParam \"" + p.baseName + "\" " + p.dataType;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private String bodyPath(String path, List<CodegenParameter> bodyParams) {
|
||||
for (CodegenParameter p : bodyParams) {
|
||||
path += " :> ReqBody '[JSON] " + p.dataType;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private String formPath(String path, List<CodegenParameter> formParams) {
|
||||
String names = "Form";
|
||||
for (CodegenParameter p : formParams) {
|
||||
if(p.dataType.equals("FilePath")){
|
||||
// file data processing
|
||||
}
|
||||
names += p.baseName;
|
||||
}
|
||||
if(formParams.size() > 0){
|
||||
path += " :> ReqBody '[FormUrlEncoded] " + names;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private String headerPath(String path, List<CodegenParameter> headerParams) {
|
||||
for (CodegenParameter p : headerParams) {
|
||||
path += " :> Header \"" + p.baseName + "\" " + p.dataType;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
private String filterReturnType(String rt) {
|
||||
if (rt == null || rt.equals("null")) {
|
||||
return "()";
|
||||
} else if (rt.indexOf(" ") >= 0) {
|
||||
return "(" + rt + ")";
|
||||
}
|
||||
return rt;
|
||||
}
|
||||
|
||||
private String addReturnPath(String path, String httpMethod, String returnType) {
|
||||
return path + " :> " + upperCaseFirst(httpMethod) + " '[JSON] " + filterReturnType(returnType);
|
||||
}
|
||||
|
||||
private String joinStrings(String sep, List<String> ss) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String s : ss) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append(sep);
|
||||
}
|
||||
sb.append(s);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String replacePathSplitter(String path) {
|
||||
String[] ps = path.replaceFirst("/", "").split("/", 0);
|
||||
List<String> rs = new ArrayList<String>();
|
||||
for (String p : ps) {
|
||||
if (p.indexOf("{") < 0) {
|
||||
rs.add("\"" + p + "\"");
|
||||
} else {
|
||||
rs.add(p);
|
||||
}
|
||||
}
|
||||
return joinStrings(" :> ", rs);
|
||||
}
|
||||
|
||||
private String upperCaseFirst(String str) {
|
||||
char[] array = str.toLowerCase().toCharArray();
|
||||
array[0] = Character.toUpperCase(array[0]);
|
||||
return new String(array);
|
||||
}
|
||||
|
||||
private String parseScheme(String basePath) {
|
||||
return "Http";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodegenOperation fromOperation(String resourcePath, String httpMethod, Operation operation, Map<String, Model> definitions, Swagger swagger){
|
||||
CodegenOperation op = super.fromOperation(resourcePath, httpMethod, operation, definitions, swagger);
|
||||
String path = op.path;
|
||||
op.nickname = addReturnPath(headerPath(formPath(bodyPath(queryPath(capturePath(replacePathSplitter(path), op.pathParams), op.queryParams), op.bodyParams), op.formParams), op.headerParams), op.httpMethod, op.returnType);
|
||||
return op;
|
||||
}
|
||||
|
||||
}
|
@ -33,3 +33,4 @@ io.swagger.codegen.languages.TypeScriptNodeClientCodegen
|
||||
io.swagger.codegen.languages.AkkaScalaClientCodegen
|
||||
io.swagger.codegen.languages.CsharpDotNet2ClientCodegen
|
||||
io.swagger.codegen.languages.ClojureClientCodegen
|
||||
io.swagger.codegen.languages.HaskellServantCodegen
|
||||
|
@ -0,0 +1,26 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
module Apis (
|
||||
api
|
||||
, API
|
||||
) where
|
||||
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
import {{package}}.{{classname}} ({{classname}})
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
|
||||
import Data.Proxy
|
||||
import Servant.API
|
||||
import Test.QuickCheck
|
||||
import qualified Data.Map as Map
|
||||
import Utils
|
||||
|
||||
type API = {{#apiInfo}}{{#apis}}{{classname}}{{#hasMore}} :<|> {{/hasMore}}{{/apis}}{{/apiInfo}}
|
||||
|
||||
api :: Proxy API
|
||||
api = Proxy
|
@ -0,0 +1,35 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
|
||||
module Main where
|
||||
|
||||
import Control.Monad (void)
|
||||
import Control.Monad.Trans.Either
|
||||
import Control.Monad.IO.Class
|
||||
import Servant.API
|
||||
import Servant.Client
|
||||
|
||||
import Data.List.Split (splitOn)
|
||||
import Network.URI (URI (..), URIAuth (..), parseURI)
|
||||
import Data.Maybe (fromMaybe)
|
||||
import Test.QuickCheck
|
||||
import Control.Monad
|
||||
{{#models}}
|
||||
import {{importPath}}
|
||||
{{/models}}
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
import {{package}}.{{classname}}
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
|
||||
-- userClient :: IO ()
|
||||
-- userClient = do
|
||||
-- users <- sample' (arbitrary :: Gen String)
|
||||
-- let user = last users
|
||||
-- void . runEitherT $ do
|
||||
-- getUserByName user >>= (liftIO . putStrLn . show)
|
||||
|
||||
main :: IO ()
|
||||
main = putStrLn "Hello Server!"
|
202
modules/swagger-codegen/src/main/resources/haskell/LICENSE
Normal file
202
modules/swagger-codegen/src/main/resources/haskell/LICENSE
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2015 Masahiro Yamauchi
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
@ -0,0 +1,7 @@
|
||||
# Generated Servant Codes
|
||||
|
||||
## How to use
|
||||
|
||||
0. Install haskell-stack
|
||||
1. stack build
|
||||
2. stack exec client
|
@ -0,0 +1,13 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
|
||||
module Main where
|
||||
|
||||
import Apis
|
||||
import Servant
|
||||
import Servant.Mock
|
||||
import qualified Network.Wai.Handler.Warp as Warp
|
||||
|
||||
main :: IO ()
|
||||
main = Warp.run 8080 $ serve api (mock api)
|
@ -0,0 +1,2 @@
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
@ -0,0 +1,27 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
module Utils where
|
||||
|
||||
import GHC.Generics
|
||||
import Servant.API
|
||||
import Data.List (intercalate)
|
||||
import Data.List.Split (splitOn)
|
||||
import qualified Data.Map as Map
|
||||
import qualified Data.Text as T
|
||||
import Test.QuickCheck
|
||||
|
||||
instance FromText [String] where
|
||||
fromText = Just . splitOn "," . T.unpack
|
||||
|
||||
instance ToText [String] where
|
||||
toText = T.pack . intercalate ","
|
||||
|
||||
lkp inputs l = case lookup l inputs of
|
||||
Nothing -> Left $ "label " ++ T.unpack l ++ " not found"
|
||||
Just v -> Right $ read (T.unpack v)
|
||||
|
||||
instance (Ord k, Arbitrary k, Arbitrary v) => Arbitrary (Map.Map k v) where
|
||||
arbitrary = Map.fromList <$> arbitrary
|
@ -0,0 +1,82 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
{{#operations}}
|
||||
module {{package}}.{{classname}} (
|
||||
{{#operation}}{{operationId}}{{#hasMore}}
|
||||
, {{/hasMore}}{{/operation}}
|
||||
, proxy{{classname}}
|
||||
, {{classname}}
|
||||
) where
|
||||
{{/operations}}
|
||||
|
||||
import GHC.Generics
|
||||
import Data.Proxy
|
||||
import Servant.API
|
||||
import Servant.Client
|
||||
import Network.URI (URI (..), URIAuth (..), parseURI)
|
||||
import Data.Maybe (fromMaybe)
|
||||
import Servant.Common.Text
|
||||
import Data.List (intercalate)
|
||||
import qualified Data.Text as T
|
||||
import Utils
|
||||
import Test.QuickCheck
|
||||
{{#imports}}import {{import}}
|
||||
{{/imports}}
|
||||
|
||||
{{#operations}}
|
||||
{{#operation}}
|
||||
{{#hasFormParams}}
|
||||
data Form{{#formParams}}{{baseName}}{{/formParams}} = Form{{#formParams}}{{baseName}}{{/formParams}}
|
||||
{ {{#formParams}}{{baseName}} :: {{dataType}}{{#hasMore}}
|
||||
, {{/hasMore}}{{/formParams}}
|
||||
} deriving (Show, Eq, Generic)
|
||||
|
||||
instance FromFormUrlEncoded Form{{#formParams}}{{baseName}}{{/formParams}} where
|
||||
fromFormUrlEncoded inputs = Form{{#formParams}}{{baseName}}{{/formParams}} <$> {{#formParams}} lkp inputs "{{baseName}}"{{#hasMore}} <*> {{/hasMore}}{{/formParams}}
|
||||
instance ToFormUrlEncoded Form{{#formParams}}{{baseName}}{{/formParams}} where
|
||||
toFormUrlEncoded x = [({{#formParams}}(T.pack $ show $ {{package}}.{{classname}}.{{baseName}} x){{#hasMore}}, {{/hasMore}}{{/formParams}})]
|
||||
instance Arbitrary Form{{#formParams}}{{baseName}}{{/formParams}} where
|
||||
arbitrary = Form{{#formParams}}{{baseName}}{{/formParams}} <$> {{#formParams}}arbitrary{{#hasMore}} <*> {{/hasMore}}{{/formParams}}
|
||||
{{/hasFormParams}}
|
||||
|
||||
{{/operation}}
|
||||
{{/operations}}
|
||||
|
||||
{{#operations}}
|
||||
type {{classname}} = {{#operation}}{{& nickname}} -- {{operationId}}{{#hasMore}}
|
||||
:<|> {{/hasMore}}{{/operation}}
|
||||
{{/operations}}
|
||||
|
||||
proxy{{classname}} :: Proxy {{classname}}
|
||||
proxy{{classname}} = Proxy
|
||||
|
||||
{{#operations}}
|
||||
|
||||
serverPath :: String
|
||||
serverPath = "{{basePath}}"
|
||||
|
||||
parseHostPort :: String -> (String, Int)
|
||||
parseHostPort path = (host,port)
|
||||
where
|
||||
authority = case parseURI path of
|
||||
Just x -> uriAuthority x
|
||||
_ -> Nothing
|
||||
(host, port) = case authority of
|
||||
Just y -> (uriRegName y, (getPort . uriPort) y)
|
||||
_ -> ("localhost", 8080)
|
||||
getPort p = case (length p) of
|
||||
0 -> 80
|
||||
_ -> (read . drop 1) p
|
||||
|
||||
(host, port) = parseHostPort serverPath
|
||||
|
||||
{{#operation}}
|
||||
{{operationId}}{{#hasMore}}
|
||||
:<|> {{/hasMore}}{{/operation}}
|
||||
= client proxy{{classname}} $ BaseUrl Http host port
|
||||
{{/operations}}
|
@ -0,0 +1,66 @@
|
||||
name: haskell-servant-codegen
|
||||
version: 0.1.0.0
|
||||
synopsis: Swagger-codegen example for Haskell servant
|
||||
description: Please see README.md
|
||||
homepage: http://github.com/algas/haskell-servant-codegen#readme
|
||||
license: Apache-2.0
|
||||
license-file: LICENSE
|
||||
author: Masahiro Yamauchi
|
||||
maintainer: sgt.yamauchi@gmail.com
|
||||
copyright: 2015- Masahiro Yamauchi
|
||||
category: Web
|
||||
build-type: Simple
|
||||
-- extra-source-files:
|
||||
cabal-version: >=1.10
|
||||
|
||||
library
|
||||
hs-source-dirs: lib
|
||||
exposed-modules: Utils{{#models}}{{#model}}
|
||||
, {{importPath}}{{/model}}{{/models}}
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
, {{package}}.{{classname}}
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
, Apis
|
||||
ghc-options: -Wall
|
||||
build-depends: base
|
||||
, aeson
|
||||
, text
|
||||
, split
|
||||
, containers
|
||||
, network-uri
|
||||
, QuickCheck
|
||||
, servant
|
||||
, servant-client
|
||||
default-language: Haskell2010
|
||||
|
||||
executable client
|
||||
hs-source-dirs: client
|
||||
main-is: Main.hs
|
||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||
build-depends: base
|
||||
, either
|
||||
, transformers
|
||||
, split
|
||||
, network-uri
|
||||
, QuickCheck
|
||||
, servant
|
||||
, servant-client
|
||||
, haskell-servant-codegen
|
||||
default-language: Haskell2010
|
||||
|
||||
executable server
|
||||
hs-source-dirs: server
|
||||
main-is: Main.hs
|
||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||
build-depends: base
|
||||
, warp
|
||||
, servant-server
|
||||
, servant-mock
|
||||
, haskell-servant-codegen
|
||||
default-language: Haskell2010
|
||||
|
||||
source-repository head
|
||||
type: git
|
||||
location: https://github.com/algas/haskell-servant-codegen
|
@ -0,0 +1,34 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||
|
||||
{{#models}}
|
||||
{{#model}}
|
||||
module {{package}}.{{classname}}
|
||||
( {{classname}} (..)
|
||||
) where
|
||||
{{/model}}
|
||||
{{/models}}
|
||||
|
||||
import Data.Aeson
|
||||
import GHC.Generics
|
||||
import Test.QuickCheck
|
||||
{{#imports}}import {{import}}
|
||||
{{/imports}}
|
||||
|
||||
{{#models}}
|
||||
{{#model}}
|
||||
|
||||
data {{classname}} = {{classname}}
|
||||
{ {{#vars}}{{& name}} :: {{datatype}}{{#hasMore}}
|
||||
, {{/hasMore}}{{/vars}}
|
||||
} deriving (Show, Eq, Generic)
|
||||
|
||||
instance FromJSON {{classname}}
|
||||
instance ToJSON {{classname}}
|
||||
instance Arbitrary {{classname}} where
|
||||
arbitrary = {{classname}} <$> {{#vars}}arbitrary{{#hasMore}} <*> {{/hasMore}}{{/vars}}
|
||||
{{/model}}
|
||||
{{/models}}
|
@ -0,0 +1,33 @@
|
||||
# For more information, see: https://github.com/commercialhaskell/stack/blob/release/doc/yaml_configuration.md
|
||||
|
||||
# Specifies the GHC version and set of packages available (e.g., lts-3.5, nightly-2015-09-21, ghc-7.10.2)
|
||||
resolver: lts-3.17
|
||||
|
||||
# Local packages, usually specified by relative directory name
|
||||
packages:
|
||||
- '.'
|
||||
|
||||
# Packages to be pulled from upstream that are not in the resolver (e.g., acme-missiles-0.3)
|
||||
extra-deps:
|
||||
- servant-mock-0.4.4.5
|
||||
|
||||
# Override default flag values for local packages and extra-deps
|
||||
flags: {}
|
||||
|
||||
# Extra package databases containing global packages
|
||||
extra-package-dbs: []
|
||||
|
||||
# Control whether we use the GHC we find on the path
|
||||
# system-ghc: true
|
||||
|
||||
# Require a specific version of stack, using version ranges
|
||||
# require-stack-version: -any # Default
|
||||
# require-stack-version: >= 0.1.10.0
|
||||
|
||||
# Override the architecture used by stack, especially useful on Windows
|
||||
# arch: i386
|
||||
# arch: x86_64
|
||||
|
||||
# Extra directories used by stack for building
|
||||
# extra-include-dirs: [/path/to/dir]
|
||||
# extra-lib-dirs: [/path/to/dir]
|
@ -0,0 +1,36 @@
|
||||
package io.swagger.codegen.haskell;
|
||||
|
||||
import io.swagger.codegen.AbstractOptionsTest;
|
||||
import io.swagger.codegen.CodegenConfig;
|
||||
import io.swagger.codegen.languages.HaskellServantCodegen;
|
||||
import io.swagger.codegen.options.HaskellServantOptionsProvider;
|
||||
|
||||
import mockit.Expectations;
|
||||
import mockit.Tested;
|
||||
|
||||
public class HaskellServantOptionsTest extends AbstractOptionsTest {
|
||||
|
||||
@Tested
|
||||
private HaskellServantCodegen clientCodegen;
|
||||
|
||||
public HaskellServantOptionsTest() {
|
||||
super(new HaskellServantOptionsProvider());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CodegenConfig getCodegenConfig() {
|
||||
return clientCodegen;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setExpectations() {
|
||||
new Expectations(clientCodegen) {{
|
||||
clientCodegen.setModelPackage(HaskellServantOptionsProvider.MODEL_PACKAGE_VALUE);
|
||||
times = 1;
|
||||
clientCodegen.setApiPackage(HaskellServantOptionsProvider.API_PACKAGE_VALUE);
|
||||
times = 1;
|
||||
clientCodegen.setSortParamsByRequiredFlag(Boolean.valueOf(HaskellServantOptionsProvider.SORT_PARAMS_VALUE));
|
||||
times = 1;
|
||||
}};
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package io.swagger.codegen.haskell;
|
||||
|
||||
import io.swagger.codegen.CodegenModel;
|
||||
import io.swagger.codegen.CodegenOperation;
|
||||
import io.swagger.codegen.DefaultCodegen;
|
||||
import io.swagger.codegen.languages.HaskellServantCodegen;
|
||||
import io.swagger.models.Operation;
|
||||
import io.swagger.models.Swagger;
|
||||
import io.swagger.parser.SwaggerParser;
|
||||
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
public class HaskellTest {
|
||||
|
||||
@Test(description = "convert a haskell model with dots")
|
||||
public void modelTest() {
|
||||
Assert.assertEquals(true, true);
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package io.swagger.codegen.options;
|
||||
|
||||
import io.swagger.codegen.CodegenConstants;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class HaskellServantOptionsProvider implements OptionsProvider {
|
||||
public static final String MODEL_PACKAGE_VALUE = "Model";
|
||||
public static final String API_PACKAGE_VALUE = "Api";
|
||||
public static final String SORT_PARAMS_VALUE = "false";
|
||||
public static final String ENSURE_UNIQUE_PARAMS_VALUE = "true";
|
||||
|
||||
@Override
|
||||
public String getLanguage() {
|
||||
return "haskell";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> createOptions() {
|
||||
ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<String, String>();
|
||||
return builder.put(CodegenConstants.MODEL_PACKAGE, MODEL_PACKAGE_VALUE)
|
||||
.put(CodegenConstants.API_PACKAGE, API_PACKAGE_VALUE)
|
||||
.put(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG, SORT_PARAMS_VALUE)
|
||||
.put(CodegenConstants.ENSURE_UNIQUE_PARAMS, ENSURE_UNIQUE_PARAMS_VALUE)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isServer() {
|
||||
return true;
|
||||
}
|
||||
}
|
202
samples/server/petstore/haskell/LICENSE
Normal file
202
samples/server/petstore/haskell/LICENSE
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2015 Masahiro Yamauchi
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
7
samples/server/petstore/haskell/README.md
Normal file
7
samples/server/petstore/haskell/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Generated Servant Codes
|
||||
|
||||
## How to use
|
||||
|
||||
0. Install haskell-stack
|
||||
1. stack build
|
||||
2. stack exec client
|
2
samples/server/petstore/haskell/Setup.hs
Normal file
2
samples/server/petstore/haskell/Setup.hs
Normal file
@ -0,0 +1,2 @@
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
35
samples/server/petstore/haskell/client/Main.hs
Normal file
35
samples/server/petstore/haskell/client/Main.hs
Normal file
@ -0,0 +1,35 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
|
||||
module Main where
|
||||
|
||||
import Control.Monad (void)
|
||||
import Control.Monad.Trans.Either
|
||||
import Control.Monad.IO.Class
|
||||
import Servant.API
|
||||
import Servant.Client
|
||||
|
||||
import Data.List.Split (splitOn)
|
||||
import Network.URI (URI (..), URIAuth (..), parseURI)
|
||||
import Data.Maybe (fromMaybe)
|
||||
import Test.QuickCheck
|
||||
import Control.Monad
|
||||
import Model.User
|
||||
import Model.Category
|
||||
import Model.Pet
|
||||
import Model.Tag
|
||||
import Model.Order
|
||||
import Api.UserApi
|
||||
import Api.StoreApi
|
||||
import Api.PetApi
|
||||
|
||||
-- userClient :: IO ()
|
||||
-- userClient = do
|
||||
-- users <- sample' (arbitrary :: Gen String)
|
||||
-- let user = last users
|
||||
-- void . runEitherT $ do
|
||||
-- getUserByName user >>= (liftIO . putStrLn . show)
|
||||
|
||||
main :: IO ()
|
||||
main = putStrLn "Hello Server!"
|
@ -0,0 +1,68 @@
|
||||
name: haskell-servant-codegen
|
||||
version: 0.1.0.0
|
||||
synopsis: Swagger-codegen example for Haskell servant
|
||||
description: Please see README.md
|
||||
homepage: http://github.com/algas/haskell-servant-codegen#readme
|
||||
license: Apache-2.0
|
||||
license-file: LICENSE
|
||||
author: Masahiro Yamauchi
|
||||
maintainer: sgt.yamauchi@gmail.com
|
||||
copyright: 2015- Masahiro Yamauchi
|
||||
category: Web
|
||||
build-type: Simple
|
||||
-- extra-source-files:
|
||||
cabal-version: >=1.10
|
||||
|
||||
library
|
||||
hs-source-dirs: lib
|
||||
exposed-modules: Utils
|
||||
, Model.User
|
||||
, Model.Category
|
||||
, Model.Pet
|
||||
, Model.Tag
|
||||
, Model.Order
|
||||
, Api.UserApi
|
||||
, Api.StoreApi
|
||||
, Api.PetApi
|
||||
, Apis
|
||||
ghc-options: -Wall
|
||||
build-depends: base
|
||||
, aeson
|
||||
, text
|
||||
, split
|
||||
, containers
|
||||
, network-uri
|
||||
, QuickCheck
|
||||
, servant
|
||||
, servant-client
|
||||
default-language: Haskell2010
|
||||
|
||||
executable client
|
||||
hs-source-dirs: client
|
||||
main-is: Main.hs
|
||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||
build-depends: base
|
||||
, either
|
||||
, transformers
|
||||
, split
|
||||
, network-uri
|
||||
, QuickCheck
|
||||
, servant
|
||||
, servant-client
|
||||
, haskell-servant-codegen
|
||||
default-language: Haskell2010
|
||||
|
||||
executable server
|
||||
hs-source-dirs: server
|
||||
main-is: Main.hs
|
||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||
build-depends: base
|
||||
, warp
|
||||
, servant-server
|
||||
, servant-mock
|
||||
, haskell-servant-codegen
|
||||
default-language: Haskell2010
|
||||
|
||||
source-repository head
|
||||
type: git
|
||||
location: https://github.com/algas/haskell-servant-codegen
|
104
samples/server/petstore/haskell/lib/Api/PetApi.hs
Normal file
104
samples/server/petstore/haskell/lib/Api/PetApi.hs
Normal file
@ -0,0 +1,104 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module Api.PetApi (
|
||||
updatePet
|
||||
, addPet
|
||||
, findPetsByStatus
|
||||
, findPetsByTags
|
||||
, getPetById
|
||||
, updatePetWithForm
|
||||
, deletePet
|
||||
, uploadFile
|
||||
, proxyPetApi
|
||||
, PetApi
|
||||
) where
|
||||
|
||||
import GHC.Generics
|
||||
import Data.Proxy
|
||||
import Servant.API
|
||||
import Servant.Client
|
||||
import Network.URI (URI (..), URIAuth (..), parseURI)
|
||||
import Data.Maybe (fromMaybe)
|
||||
import Servant.Common.Text
|
||||
import Data.List (intercalate)
|
||||
import qualified Data.Text as T
|
||||
import Utils
|
||||
import Test.QuickCheck
|
||||
import Model.Pet
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
data Formnamestatus = Formnamestatus
|
||||
{ name :: String
|
||||
, status :: String
|
||||
} deriving (Show, Eq, Generic)
|
||||
|
||||
instance FromFormUrlEncoded Formnamestatus where
|
||||
fromFormUrlEncoded inputs = Formnamestatus <$> lkp inputs "name" <*> lkp inputs "status"
|
||||
instance ToFormUrlEncoded Formnamestatus where
|
||||
toFormUrlEncoded x = [((T.pack $ show $ Api.PetApi.name x), (T.pack $ show $ Api.PetApi.status x))]
|
||||
instance Arbitrary Formnamestatus where
|
||||
arbitrary = Formnamestatus <$> arbitrary <*> arbitrary
|
||||
|
||||
|
||||
data FormadditionalMetadatafile = FormadditionalMetadatafile
|
||||
{ additionalMetadata :: String
|
||||
, file :: FilePath
|
||||
} deriving (Show, Eq, Generic)
|
||||
|
||||
instance FromFormUrlEncoded FormadditionalMetadatafile where
|
||||
fromFormUrlEncoded inputs = FormadditionalMetadatafile <$> lkp inputs "additionalMetadata" <*> lkp inputs "file"
|
||||
instance ToFormUrlEncoded FormadditionalMetadatafile where
|
||||
toFormUrlEncoded x = [((T.pack $ show $ Api.PetApi.additionalMetadata x), (T.pack $ show $ Api.PetApi.file x))]
|
||||
instance Arbitrary FormadditionalMetadatafile where
|
||||
arbitrary = FormadditionalMetadatafile <$> arbitrary <*> arbitrary
|
||||
|
||||
|
||||
type PetApi = "pet" :> ReqBody '[JSON] Pet :> Put '[JSON] () -- updatePet
|
||||
:<|> "pet" :> ReqBody '[JSON] Pet :> Post '[JSON] () -- addPet
|
||||
:<|> "pet" :> "findByStatus" :> QueryParam "status" [String] :> Get '[JSON] [Pet] -- findPetsByStatus
|
||||
:<|> "pet" :> "findByTags" :> QueryParam "tags" [String] :> Get '[JSON] [Pet] -- findPetsByTags
|
||||
:<|> "pet" :> Capture "petId" Integer :> Get '[JSON] Pet -- getPetById
|
||||
:<|> "pet" :> Capture "petId" String :> ReqBody '[FormUrlEncoded] Formnamestatus :> Post '[JSON] () -- updatePetWithForm
|
||||
:<|> "pet" :> Capture "petId" Integer :> Header "api_key" String :> Delete '[JSON] () -- deletePet
|
||||
:<|> "pet" :> Capture "petId" Integer :> "uploadImage" :> ReqBody '[FormUrlEncoded] FormadditionalMetadatafile :> Post '[JSON] () -- uploadFile
|
||||
|
||||
proxyPetApi :: Proxy PetApi
|
||||
proxyPetApi = Proxy
|
||||
|
||||
|
||||
serverPath :: String
|
||||
serverPath = "http://petstore.swagger.io/v2"
|
||||
|
||||
parseHostPort :: String -> (String, Int)
|
||||
parseHostPort path = (host,port)
|
||||
where
|
||||
authority = case parseURI path of
|
||||
Just x -> uriAuthority x
|
||||
_ -> Nothing
|
||||
(host, port) = case authority of
|
||||
Just y -> (uriRegName y, (getPort . uriPort) y)
|
||||
_ -> ("localhost", 8080)
|
||||
getPort p = case (length p) of
|
||||
0 -> 80
|
||||
_ -> (read . drop 1) p
|
||||
|
||||
(host, port) = parseHostPort serverPath
|
||||
|
||||
updatePet
|
||||
:<|> addPet
|
||||
:<|> findPetsByStatus
|
||||
:<|> findPetsByTags
|
||||
:<|> getPetById
|
||||
:<|> updatePetWithForm
|
||||
:<|> deletePet
|
||||
:<|> uploadFile
|
||||
= client proxyPetApi $ BaseUrl Http host port
|
67
samples/server/petstore/haskell/lib/Api/StoreApi.hs
Normal file
67
samples/server/petstore/haskell/lib/Api/StoreApi.hs
Normal file
@ -0,0 +1,67 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module Api.StoreApi (
|
||||
getInventory
|
||||
, placeOrder
|
||||
, getOrderById
|
||||
, deleteOrder
|
||||
, proxyStoreApi
|
||||
, StoreApi
|
||||
) where
|
||||
|
||||
import GHC.Generics
|
||||
import Data.Proxy
|
||||
import Servant.API
|
||||
import Servant.Client
|
||||
import Network.URI (URI (..), URIAuth (..), parseURI)
|
||||
import Data.Maybe (fromMaybe)
|
||||
import Servant.Common.Text
|
||||
import Data.List (intercalate)
|
||||
import qualified Data.Text as T
|
||||
import Utils
|
||||
import Test.QuickCheck
|
||||
import qualified Data.Map as Map
|
||||
import Model.Order
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
type StoreApi = "store" :> "inventory" :> Get '[JSON] (Map.Map String Integer) -- getInventory
|
||||
:<|> "store" :> "order" :> ReqBody '[JSON] Order :> Post '[JSON] Order -- placeOrder
|
||||
:<|> "store" :> "order" :> Capture "orderId" String :> Get '[JSON] Order -- getOrderById
|
||||
:<|> "store" :> "order" :> Capture "orderId" String :> Delete '[JSON] () -- deleteOrder
|
||||
|
||||
proxyStoreApi :: Proxy StoreApi
|
||||
proxyStoreApi = Proxy
|
||||
|
||||
|
||||
serverPath :: String
|
||||
serverPath = "http://petstore.swagger.io/v2"
|
||||
|
||||
parseHostPort :: String -> (String, Int)
|
||||
parseHostPort path = (host,port)
|
||||
where
|
||||
authority = case parseURI path of
|
||||
Just x -> uriAuthority x
|
||||
_ -> Nothing
|
||||
(host, port) = case authority of
|
||||
Just y -> (uriRegName y, (getPort . uriPort) y)
|
||||
_ -> ("localhost", 8080)
|
||||
getPort p = case (length p) of
|
||||
0 -> 80
|
||||
_ -> (read . drop 1) p
|
||||
|
||||
(host, port) = parseHostPort serverPath
|
||||
|
||||
getInventory
|
||||
:<|> placeOrder
|
||||
:<|> getOrderById
|
||||
:<|> deleteOrder
|
||||
= client proxyStoreApi $ BaseUrl Http host port
|
82
samples/server/petstore/haskell/lib/Api/UserApi.hs
Normal file
82
samples/server/petstore/haskell/lib/Api/UserApi.hs
Normal file
@ -0,0 +1,82 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module Api.UserApi (
|
||||
createUser
|
||||
, createUsersWithArrayInput
|
||||
, createUsersWithListInput
|
||||
, loginUser
|
||||
, logoutUser
|
||||
, getUserByName
|
||||
, updateUser
|
||||
, deleteUser
|
||||
, proxyUserApi
|
||||
, UserApi
|
||||
) where
|
||||
|
||||
import GHC.Generics
|
||||
import Data.Proxy
|
||||
import Servant.API
|
||||
import Servant.Client
|
||||
import Network.URI (URI (..), URIAuth (..), parseURI)
|
||||
import Data.Maybe (fromMaybe)
|
||||
import Servant.Common.Text
|
||||
import Data.List (intercalate)
|
||||
import qualified Data.Text as T
|
||||
import Utils
|
||||
import Test.QuickCheck
|
||||
import Model.User
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
type UserApi = "user" :> ReqBody '[JSON] User :> Post '[JSON] () -- createUser
|
||||
:<|> "user" :> "createWithArray" :> ReqBody '[JSON] [User] :> Post '[JSON] () -- createUsersWithArrayInput
|
||||
:<|> "user" :> "createWithList" :> ReqBody '[JSON] [User] :> Post '[JSON] () -- createUsersWithListInput
|
||||
:<|> "user" :> "login" :> QueryParam "username" String :> QueryParam "password" String :> Get '[JSON] String -- loginUser
|
||||
:<|> "user" :> "logout" :> Get '[JSON] () -- logoutUser
|
||||
:<|> "user" :> Capture "username" String :> Get '[JSON] User -- getUserByName
|
||||
:<|> "user" :> Capture "username" String :> ReqBody '[JSON] User :> Put '[JSON] () -- updateUser
|
||||
:<|> "user" :> Capture "username" String :> Delete '[JSON] () -- deleteUser
|
||||
|
||||
proxyUserApi :: Proxy UserApi
|
||||
proxyUserApi = Proxy
|
||||
|
||||
|
||||
serverPath :: String
|
||||
serverPath = "http://petstore.swagger.io/v2"
|
||||
|
||||
parseHostPort :: String -> (String, Int)
|
||||
parseHostPort path = (host,port)
|
||||
where
|
||||
authority = case parseURI path of
|
||||
Just x -> uriAuthority x
|
||||
_ -> Nothing
|
||||
(host, port) = case authority of
|
||||
Just y -> (uriRegName y, (getPort . uriPort) y)
|
||||
_ -> ("localhost", 8080)
|
||||
getPort p = case (length p) of
|
||||
0 -> 80
|
||||
_ -> (read . drop 1) p
|
||||
|
||||
(host, port) = parseHostPort serverPath
|
||||
|
||||
createUser
|
||||
:<|> createUsersWithArrayInput
|
||||
:<|> createUsersWithListInput
|
||||
:<|> loginUser
|
||||
:<|> logoutUser
|
||||
:<|> getUserByName
|
||||
:<|> updateUser
|
||||
:<|> deleteUser
|
||||
= client proxyUserApi $ BaseUrl Http host port
|
24
samples/server/petstore/haskell/lib/Apis.hs
Normal file
24
samples/server/petstore/haskell/lib/Apis.hs
Normal file
@ -0,0 +1,24 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
module Apis (
|
||||
api
|
||||
, API
|
||||
) where
|
||||
|
||||
import Api.UserApi (UserApi)
|
||||
import Api.StoreApi (StoreApi)
|
||||
import Api.PetApi (PetApi)
|
||||
|
||||
import Data.Proxy
|
||||
import Servant.API
|
||||
import Test.QuickCheck
|
||||
import qualified Data.Map as Map
|
||||
import Utils
|
||||
|
||||
type API = UserApi :<|> StoreApi :<|> PetApi
|
||||
|
||||
api :: Proxy API
|
||||
api = Proxy
|
24
samples/server/petstore/haskell/lib/Model/Category.hs
Normal file
24
samples/server/petstore/haskell/lib/Model/Category.hs
Normal file
@ -0,0 +1,24 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||
|
||||
module Model.Category
|
||||
( Category (..)
|
||||
) where
|
||||
|
||||
import Data.Aeson
|
||||
import GHC.Generics
|
||||
import Test.QuickCheck
|
||||
|
||||
|
||||
data Category = Category
|
||||
{ id_ :: Integer
|
||||
, name :: String
|
||||
} deriving (Show, Eq, Generic)
|
||||
|
||||
instance FromJSON Category
|
||||
instance ToJSON Category
|
||||
instance Arbitrary Category where
|
||||
arbitrary = Category <$> arbitrary <*> arbitrary
|
28
samples/server/petstore/haskell/lib/Model/Order.hs
Normal file
28
samples/server/petstore/haskell/lib/Model/Order.hs
Normal file
@ -0,0 +1,28 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||
|
||||
module Model.Order
|
||||
( Order (..)
|
||||
) where
|
||||
|
||||
import Data.Aeson
|
||||
import GHC.Generics
|
||||
import Test.QuickCheck
|
||||
|
||||
|
||||
data Order = Order
|
||||
{ id_ :: Integer
|
||||
, petId :: Integer
|
||||
, quantity :: Integer
|
||||
, shipDate :: Integer
|
||||
, status :: String
|
||||
, complete :: Bool
|
||||
} deriving (Show, Eq, Generic)
|
||||
|
||||
instance FromJSON Order
|
||||
instance ToJSON Order
|
||||
instance Arbitrary Order where
|
||||
arbitrary = Order <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
|
30
samples/server/petstore/haskell/lib/Model/Pet.hs
Normal file
30
samples/server/petstore/haskell/lib/Model/Pet.hs
Normal file
@ -0,0 +1,30 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||
|
||||
module Model.Pet
|
||||
( Pet (..)
|
||||
) where
|
||||
|
||||
import Data.Aeson
|
||||
import GHC.Generics
|
||||
import Test.QuickCheck
|
||||
import Model.Category
|
||||
import Model.Tag
|
||||
|
||||
|
||||
data Pet = Pet
|
||||
{ id_ :: Integer
|
||||
, category :: Category
|
||||
, name :: String
|
||||
, photoUrls :: [String]
|
||||
, tags :: [Tag]
|
||||
, status :: String
|
||||
} deriving (Show, Eq, Generic)
|
||||
|
||||
instance FromJSON Pet
|
||||
instance ToJSON Pet
|
||||
instance Arbitrary Pet where
|
||||
arbitrary = Pet <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
|
24
samples/server/petstore/haskell/lib/Model/Tag.hs
Normal file
24
samples/server/petstore/haskell/lib/Model/Tag.hs
Normal file
@ -0,0 +1,24 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||
|
||||
module Model.Tag
|
||||
( Tag (..)
|
||||
) where
|
||||
|
||||
import Data.Aeson
|
||||
import GHC.Generics
|
||||
import Test.QuickCheck
|
||||
|
||||
|
||||
data Tag = Tag
|
||||
{ id_ :: Integer
|
||||
, name :: String
|
||||
} deriving (Show, Eq, Generic)
|
||||
|
||||
instance FromJSON Tag
|
||||
instance ToJSON Tag
|
||||
instance Arbitrary Tag where
|
||||
arbitrary = Tag <$> arbitrary <*> arbitrary
|
30
samples/server/petstore/haskell/lib/Model/User.hs
Normal file
30
samples/server/petstore/haskell/lib/Model/User.hs
Normal file
@ -0,0 +1,30 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||
|
||||
module Model.User
|
||||
( User (..)
|
||||
) where
|
||||
|
||||
import Data.Aeson
|
||||
import GHC.Generics
|
||||
import Test.QuickCheck
|
||||
|
||||
|
||||
data User = User
|
||||
{ id_ :: Integer
|
||||
, username :: String
|
||||
, firstName :: String
|
||||
, lastName :: String
|
||||
, email :: String
|
||||
, password :: String
|
||||
, phone :: String
|
||||
, userStatus :: Integer
|
||||
} deriving (Show, Eq, Generic)
|
||||
|
||||
instance FromJSON User
|
||||
instance ToJSON User
|
||||
instance Arbitrary User where
|
||||
arbitrary = User <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
|
27
samples/server/petstore/haskell/lib/Utils.hs
Normal file
27
samples/server/petstore/haskell/lib/Utils.hs
Normal file
@ -0,0 +1,27 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
module Utils where
|
||||
|
||||
import GHC.Generics
|
||||
import Servant.API
|
||||
import Data.List (intercalate)
|
||||
import Data.List.Split (splitOn)
|
||||
import qualified Data.Map as Map
|
||||
import qualified Data.Text as T
|
||||
import Test.QuickCheck
|
||||
|
||||
instance FromText [String] where
|
||||
fromText = Just . splitOn "," . T.unpack
|
||||
|
||||
instance ToText [String] where
|
||||
toText = T.pack . intercalate ","
|
||||
|
||||
lkp inputs l = case lookup l inputs of
|
||||
Nothing -> Left $ "label " ++ T.unpack l ++ " not found"
|
||||
Just v -> Right $ read (T.unpack v)
|
||||
|
||||
instance (Ord k, Arbitrary k, Arbitrary v) => Arbitrary (Map.Map k v) where
|
||||
arbitrary = Map.fromList <$> arbitrary
|
13
samples/server/petstore/haskell/server/Main.hs
Normal file
13
samples/server/petstore/haskell/server/Main.hs
Normal file
@ -0,0 +1,13 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
|
||||
module Main where
|
||||
|
||||
import Apis
|
||||
import Servant
|
||||
import Servant.Mock
|
||||
import qualified Network.Wai.Handler.Warp as Warp
|
||||
|
||||
main :: IO ()
|
||||
main = Warp.run 8080 $ serve api (mock api)
|
33
samples/server/petstore/haskell/stack.yaml
Normal file
33
samples/server/petstore/haskell/stack.yaml
Normal file
@ -0,0 +1,33 @@
|
||||
# For more information, see: https://github.com/commercialhaskell/stack/blob/release/doc/yaml_configuration.md
|
||||
|
||||
# Specifies the GHC version and set of packages available (e.g., lts-3.5, nightly-2015-09-21, ghc-7.10.2)
|
||||
resolver: lts-3.17
|
||||
|
||||
# Local packages, usually specified by relative directory name
|
||||
packages:
|
||||
- '.'
|
||||
|
||||
# Packages to be pulled from upstream that are not in the resolver (e.g., acme-missiles-0.3)
|
||||
extra-deps:
|
||||
- servant-mock-0.4.4.5
|
||||
|
||||
# Override default flag values for local packages and extra-deps
|
||||
flags: {}
|
||||
|
||||
# Extra package databases containing global packages
|
||||
extra-package-dbs: []
|
||||
|
||||
# Control whether we use the GHC we find on the path
|
||||
# system-ghc: true
|
||||
|
||||
# Require a specific version of stack, using version ranges
|
||||
# require-stack-version: -any # Default
|
||||
# require-stack-version: >= 0.1.10.0
|
||||
|
||||
# Override the architecture used by stack, especially useful on Windows
|
||||
# arch: i386
|
||||
# arch: x86_64
|
||||
|
||||
# Extra directories used by stack for building
|
||||
# extra-include-dirs: [/path/to/dir]
|
||||
# extra-lib-dirs: [/path/to/dir]
|
Loading…
x
Reference in New Issue
Block a user