Only this pageAll pages
Powered by GitBook
1 of 47

code.store Documentation

Loading...

Loading...

Loading...

Getting started

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Command Line Interface

Loading...

Loading...

What is code.store?

Welcome!

We are happy that you're here! 👋

So what is code.store? It all started with a simple idea: the complexity of the modern world is astonishing and is increasing every day, that's why we should be spending our time and energy on problems that are new and complex to solve and try and reuse everything else. So we decided to create a platform for companies and software engineers to reuse and share live, hosted code among projects and organizations. We also want to create a public marketplace where every developer and company could sell their API-first services on a subscription or pay-per-call rate-plan.

So, in short, code.store is a backend-as-a-service, a GraphQL schema-first platform where you can build, host, reuse, and bill your so that you could create some truly amazing products!

For the good of your company and the planet, we think that reusing code is very important!

Community

Like many other great products, code.store is continuously evolving as we are striving to bring more features, improve the existing ones and make sure that the product is as stable as it could be. 🤞

That's why if you have ANY suggestions while using code.store, whether it be feature requests, suggestions on how to improve our documentation, or just some questions, we are here for you!

Create a feature request or chat with us in real-time in our community home here: .

What next?

A good to place to start would be to read about , and of course, our .

Enjoy the reading and don't hesitate to !

services
https://spectrum.chat/code-store
Our Vision
How it works?
Core concepts
contact us

Import and Export

Our vision

If you have nothing else to do, you can read this long piece of art about our vision of the future of the world. 🤦‍♀️

♻️ Reusability

We created code.store because we believe the way software is being built today is not adapted to the pace of the modern world. We think that you should not spend time on problems that have been already solved in the past.

From custom-built monolith to software editor powered monoliths to re-usable API components.

Software started with fully custom-built monoliths. Large mono-repository projects where teams coded absolutely everything. Then came frameworks and software editor solutions (Magento, Drupal, Wordpress, Salesforce, SAP...), providing vertical monoliths for common needs (CRM, e-commerce, ERP, DAM, PIM, ...). Usually, clients of software editor solutions end up overpaying for features they don't use (a client uses only 30% of features on average), and they still have an ever-growing budget for maintenance of a massive monolith.

Now is the time to build software in a new way: re-using small building blocks that solve a unique functional problem, like using lego bricks.

‌Modules, packages, DLLs, JARs, servlets, there has always been a desire for reusability, but there were always many barriers to reusability: technological stack, support & maintenance, integration, compatibility, and size of each component, the coupling between UX and back-end.

So why it would be different with code.store?

In the past years, the world of web-development saw several profound changes in the way we build software that makes out code.store idea reasonable:

  • Headless and decoupled approaches

    With robust and stable frontend frameworks like Angular, React, and Vue, it is now easy to build genuinely decoupled applications. It is important because the strongest barrier to reusability is frontend and UX. With decoupling, we can focus on API reusability.

  • GraphQL

    It offers a lot of flexibility to frontend developers. Previously, each time an application needed a product listing presented in a slightly different way, we would either have to load all the unnecessary data from a single REST endpoint or ask backend developers to provide a new "lighter" endpoint.

💰Revenues

When independent developers, companies, or digital agencies build software for others, they usually bill the time they spent on it. It's therefore complicated to re-use components from one project to another, and almost impossible to share funding, specifically when you mix hosting and support. We wanted to change that paradigm by providing a new way for billing projects.

For each service on code.store, you may activate metered or monthly billing and sell them to your clients. We take care of retrieving funds and take a small cut of only 10%. The recurring revenues cover your initial development time, hosting resources, our platform, and the time you spent on the support and maintenance of your service.

Nowadays, « Every company is a tech company », but being a software editor is not easy. Initial technological stack, marketing, R&D investments, ROI roadmap management, indirect distribution are complex and inaccessible for most companies.

We bet that by providing a common platform and reducing the software to « bite » sized, running, live service, we’ll enable re-usability, sharing and ultimately, billing through direct sales or marketplace.

🦄 Simplicity

There are too many ways to create software today. We created code.store in a way that you can focus only on your code, while we take care of the rest (some of the features in the list are still in the roadmap, but we are working hard to deliver them to you as soon as possible):

  • containerization

  • database modelling and management

  • security

  • GDPR

code.store is a rather opinionated platform, which means we have made a certain number of choices for you to simplify the development. However, we want it to be a platform built by developers for developers, and we are open to suggestions and would be very happy to hear from you in our community chat !

PS: If you've read it all, please about us!

Quick Start with Web Interface

Oops!🙀 Our team is working hard to build a great web UI that will help manage your services online. Join us at our community home to find out more about it and when it is going to be released: https://spectrum.chat/code-store

Metabase integration

FUNDAMENTALS

External database: DynamoDB

Microservices

RECIPES

Auth0 authentication

TypeScript

Database manipulations

We'll create a service where you can store, update and read data in your service.

Coming soon!

External database: MongoDB

Custom .tslint

Serverless is widely accepted

You want to reuse live, running, supported, and functional code. That means you accept that the module/service/lego brick you reuse might run somewhere and you do not care if it handles traffic and provides good SLAs.

  • Microservices are mainstream

    You already do "microservices" without knowing it, when you implement external APIs on your projects like Google Maps, Stripe, or Facebook Connect. Call them nano/micro/macro/mini services, but your project is already the patchwork of small, isolated, and autonomous services glued together by your frontend application.

  • performance

  • continuous integration and deployment

  • automated tests

  • monitoring

  • 24/7 support

  • instant re-use

  • https://spectrum.chat/code-store
    tweet

    Communication

    Overview

    When you include services to you project there might be a cases, when services should communicate with each other. code.store platform allows inter-HTTP communication

    We are working hard on the platform functionality and soon we will provide an opportunity to organize inter-service communication through message-brokers.

    Tutorials

    👋 Take my hand, stranger. We'll go through code.store paradise.

    Quick Start

    The goal of this section is to get you up to speed real fast. We are going to learn how to install and use the command line tools of code.store, how to create an account, and write a basic service! Let's continue 🚀

    There are two ways to manage your Service: and Both of them give you the ability to perform the same actions with code.store, so you can start with either of them and continue later with another.

    Basic authentication
    Setup a local database with your service
    Wrapping an NPM package with GraphQL: a chess server
    code.store Console
    code.store CLI.
    Routing concept

    Services, which project includes and deployed in one environment can communicate with each other.

    To call GraphQL or REST API of another service on the same environment - make an HTTP request, where URL should build by next pattern: http://{SERVICE_NAME}-service Each service has an internal URL which available only per environment.

    Let's imagine that we have service "example", which deployed to the development environment. This service can be accessed by another service on the development environment by next URL:

    HTTP request example

    To provide an HTTP call to service install any HTTP client, for example axios using npm:

    Import axios dependency in your code:

    And execute request yo your service. In example below you can find simple HTTP request to [GET] /rest/hello route of example service:

    The result of HTTP request execution will be available in the result object.

    http://example-service
    npm i axios
    import axios from 'axios';
    const result = await axios.get('http://service-example/rest/hello');

    Setup a local database with your service

    To help you with local development of you services you'll need a local Postgre database.

    You know that we care about your time, so we created a local launcher for your services. But you also know that your services have a local database to store your objects. Let's setup a local Postgre database.

    This tutorial covers postgre setup for mac. Follow postgre site instruction for other OS.

    I love working with their simplest version: postgreapp. Go there and download it.

    Launch the application. You have your local postgre database. You should see a small icon of postgre in your menu top bar.

    Now you can go in any of your services folders and and edit codestore.yaml file. You should see something like that :

    Change the database name, password, and username to the ones from

    To test your connection, nothing more simple : execute in the root folder of your service cs dev command. You should see something like that :

    Middlewares

    Overview

    code.store platform support middleware functions for REST endpoints. To avoid manual file creation allowed a command cs generate:middleware, which generate a template of middleware with handler method.

    To generate middleware for your route just execute cs generate:middleware CLI command, select one of middleware type: request or response middleware type, specify name for your function and select route from the route list:

    > cs generate:middleware
    
    ? Select position of middleware (Use arrow keys)
      response 
    ❯ request 
    
    ? Enter name of your middleware: permissions
    
    ? Select route to apply (Use arrow keys)
    
    File ./demo_app/src/rest-middlewares/permissions.middleware.ts has been generated.
    

    Also, you can use flags:

    -p for type specification (allowed: 'request' or 'response)

    -r name of the route to apply middleware function

    -n name of middleware function

    For example, here a command from previous example: cs generate:middleware -p request -r hello -n permissions

    After command execution will be generated file permissions.middleware.ts in src/rest-middlewares directory:

    More information about handler method and his params can be found in section.

    REST

    Overview

    code.store platform support file based REST endpoints. To avoid manual file creation allowed a command cs generate:rest, which generate an empty route template with handler method.

    To generate REST route just execute cs generate:rest CLI command, select one of HTTP methods: GET, POST, PUT, DELETE and specify a new route name

    > cs generate:rest
    
    ? Select HTTP method (Use arrow keys)
    ❯ GET 
      POST 
      PUT 
      DELETE 
      
    ? Select HTTP method GET
    
    ? Name of your REST endpoint hello

    Also, you can use flags:

    -m for method specification (GET, POST, PUT, DELETE)

    -n for route name

    For example, here a command from previous example: cs generate:rest -m get -n hello

    After command execution will be generated file get.hello.ts in src/rest directory:

    More information about handler method and his params can be found in section.

    Generation

    Overview

    code.store platform makes it possible to generate most of the necessary entities for comfortable development.

    At the beginning of the journey, when creating a service, it is possible to choose the language of your future service. code.store platform will generate default "hello world" application.

    Generation happens cs generate CLI command. During development, it is possible to generate entities such as:

    Environment Variables

    Overview

    By default, each service has different variables, which depends on the environment. For example, database environments, which available on the development environment may differ from the staging environment, and so on... For more information about environments, see the Environments section. Depends on service language, environment variables can be accessed in different ways.

    To access environment variables using TypeScript or JavaScript language use:

    code.store platform guarantees a high level of security, but we do not recommend displaying secret variables in the stdout or other sources.

    Below, you can find information about available environment variables which code.store platform set by default.

    Service Environment Variables

    PROJECT_ID internal ID of the project on the code.store platform

    ENVIRONMENT_ID name of the , where service deployed

    SERVICE_ID internal ID of the service on the code.store platform

    Database Environment Variables

    Postgres Variables

    DATABASE_HOST connection host

    DATABASE_PORT connection port

    DATABASE_NAME name of the database

    DATABASE_USERNAME name of the user which can access to services database

    Redis Variables

    REDIS_HOST Redis connection host

    REDIS_PORT Redis connection port

    Language-based environment variables

    TypeScript & JavaScript

    NODE_VERSION node version, which deployed service used

    Resolvers

    Overview

    code.store platform support . To avoid manual file creation allowed a command cs generate:resolver, which generate an empty resolver for your query or mutation which specified in schema.graphql file in src directory.

    To generate resolver execute cs generate:resolver

    Handlers

    Overview

    To simplify authorization and authentication process code.store platform provide an opportunity to create an authorization handler for REST and context handler for your GraphQL API.

    Authorization handlers released as middlewares and allows to implement custom authorization logic.

    process.env
    REST API handlers
    GraphQL resolvers
    Authorization and context handlers
    Database models
    Database migrations
    environment
    serviceId: 145
    localConfiguration:
      database:
        port: 5432
        database: database
        password: password
        username: username
        host: localhost
      application:
        port: 3000
    postgre configuration.
    /**
     * This handler was generated by code.store CLI.
     *
     * Visit our documentation to learn more about the support of REST APIs in our SDK:
     * https://docs.code.store/getting-started/sdk/rest-apis
     *
     * You can also join our community at https://spectrum.chat/code-store if you have any
     * questions which are not covered by the documentation.
     *
     */
    
    import { Handler } from 'codestore-utils';
    
    const handler: Handler = async (event, context) => {
      // your code goes here
      return 'Hello, world!';
    }
    
    export default handler;
    REST
    /**
     * This handler was generated by code.store CLI.
     *
     * Visit our documentation to learn more about the support of REST APIs in our SDK:
     * https://docs.code.store/getting-started/sdk/rest-apis
     *
     * You can also join our community at https://spectrum.chat/code-store if you have any
     * questions which are not covered by the documentation.
     *
     */
    
    import { Handler } from 'codestore-utils';
    
    const handler: Handler = async (event, context) => {
      // your code goes here
      return 'Hello, world!';
    }
    
    export default handler;
    REST
    CLI command, select resolver type: mutation or query and and specify a name:

    Also, you can use flags:

    -t resolver type, one of: 'query' or 'mutation'

    -n resolver name

    -f force overwrite file if it already exists

    For example, here a command from previous example: cs generate:resolver -t query -n hello

    After command execution will be generated file get.hello.ts in src/rest directory:

    More information about resolver method and his params can be found in GraphQL section.

    file based resolvers
    > cs generate:resolver
    
    ? Select the type of resolver (Use arrow keys)
    ❯ query 
      mutation  
      
    ? Enter the name of your resolver hello
    Generation

    Auth handler

    To generate auth handler execute cs generate:resolver CLI command, select auth handler type:

    Also, you can use flags:

    -t handler type, one of: 'context' or 'auth'

    After command execution will be generated file auth.handler.ts in src/resolvers directory:

    Usage

    You can specify your authentication strategy here. This handler works as an authentication middleware which will be called for all GraphQL queries/mutations marked with directive @auth.

    In order to use that directive in your GraphQL schema, add a following directive declaration at the top of your GraphQL file:

    Then use it in query/mutation declarations, for example:

    Context handler

    Use context handler as a handler, which will be execute before each GraphQL resolver. To generate context handler execute cs generate:resolver CLI command, select context handler type:

    Also, you can use flags:

    -t handler type, one of: 'context' or 'auth'

    After command execution will be generated file context.handler.ts in src/resolvers directory:

    cs dev
    2020-09-11T10:10:00.638Z [NPM] Installing dependencies
    2020-09-11T10:10:05.359Z [TypeScript] Compiling typescript code
    2020-09-11T10:10:13.745Z [GraphQL] Validating schema
    2020-09-11T10:10:13.767Z [GraphQL] Validating queries and mutations
    2020-09-11T10:10:17.168Z [INFO] Starting development server
    2020-09-11T10:10:17.168Z [Bootstrap] Start bootstrapping the application
    2020-09-11T10:10:17.168Z [Database] Connecting to database
    2020-09-11T10:10:17.316Z [Database] Successfully connected
    2020-09-11T10:10:17.441Z [Database] Migrations ran
    2020-09-11T10:10:17.443Z [GqlLoader] Loaded queries: load
    2020-09-11T10:10:17.462Z [Bootstrap] Graphql is available on: http://localhost:3000/graphql
    /**
     * This resolver was generated by code.store CLI.
     *
     * Visit our documentation to learn more about writing custom resolvers for your GraphQL schema:
     * https://docs.code.store/getting-started/quick-start/quick-start-with-cli
     *
     * You can also join our community at https://spectrum.chat/code-store if you have any
     * questions which are not covered by the documentation.
     *
     */
    import { Resolver } from 'codestore-utils';
    
    const resolver: Resolver = async (parent, args, context, info) => {
      // Your code goes here.
      // Example of how to initialize an Entity:
      //   const exampleEntity = context.db.connection.getRepository(exampleEntity);
      //   exampleEntity.find();
      return 'Hello, World!';
    }
    
    export default resolver;
    > cs generate:handler
    
    ? Select the type of resolver (Use arrow keys)
    ❯ auth 
      context 
    import { AuthHandler } from 'codestore-utils';
    
    const authHandler: AuthHandler = async (context) => {
      // your code goes here
      return {};
    };
    
    export default authHandler;
    directive @auth on FIELD_DEFINITION
    type Query {
        helloWorld: String! @auth
    }
    > cs generate:handler
    
    ? Select the type of resolver (Use arrow keys)
      auth 
    ❯ context 
    import { ContextHandler } from 'codestore-utils';
    
    const contextHandler: ContextHandler = async (context) => ({
      //  your code goes here
    });
    
    export default contextHandler;

    Versioning

    Overview

    The bigger your system grows and the more libs or packages you integrate into your project, the more likely you are to face such a problem as dependency hell.

    As a solution, code.store platform suggests relying on a simple set of rules and requirements that govern how version numbers are assigned and incremented. There are many approaches to software versioning and their interfaces, the choice is always up to the developer.

    code.store platform doesn't enforce any standard on how you need to version your services, but we highly recommend looking at a standard like

    's approach can solve most of the versioning issues

    When you create a new service, by default, it deployed into private and demo and it's version is 0.0.1

    Which version currently deployed?

    To find out which version is in use execute cs service:info CLI command and select the service. You will find which versions deployed on private and demo environments.

    On example above on the private environment deployed service with 0.0.2 version and 0.0.1 on the demo.

    If you already include service to project, you can execute cs project:service:info CLI command, select project and service to display.

    On example above deployed on three environments deployed next versions:

    Create a new service version

    To create a new version just push your changes using cs push CLI command. More information about pushing changes can be found in section. After pushing changes - a new version will be available on the private .

    It's very important to increment service version after making changes to service. Actual service version is always available at package.json file.

    By default, code.store platform will automatically increment path (x.y.Z) version of your code after each push, if you follow specification.

    Publish a new service version

    After creating a new service version using cs push command - changes will be available only on the private .

    demo - is the only place, where developed changes can be published. Changes from demo environment is available for including to the project or public .

    To make a new version available - execute cs promote CLI command. This command will deploy changes from private to demo environment and makes a new version available for update/include into projects. Promoted version to demo environment is marks as LATEST

    Manage service version inside project

    When you include a new service to the - version from demo will be deployed. This allows adhering to the concept of public release of new versions to avoid unexpected system behavior. More information about including services to projects can be found in section.

    Move service version per environment

    After including service to the project - it's deployed only to development . To move service version to another environment use cs project:service:promote CLI command. It allows you to move already deployed version to another environment.

    For example, if your project includes some service - you can promote only already deployed service version to another environments.

    Update service version to latest

    To update project service to latest version execute cs project:service:roll CLI command, where you can select project, environment where will be applied changes, service and version.

    Select latest version if you need a latest available service version.

    Rollback service version

    To rollback service version use the same command cs project:service:roll and just select needed version and environment where to deploy needed version.

    How it works?

    A short guide explaining the whole code.store in a single page. Don't say thanks! 👊

    Schema is not perfect but represents quite well code.store.

    Create your service & GraphQL Schema

    The service you are building is going to be consumed by your clients (real clients or frontend teammates) via an API (GraphQL), which your service is exposing. That is why we believe in the schema-first approach, where you are required to define an API (or a schema) first and then develop a backend that provides data for this schema (as opposed to a code-first approach where the schema is generated from the code you write). GraphQL schema (or API) IS YOUR PRODUCT! That is why everything starts with a schema at code.store.

    Database generation

    We strive to simplify your life, and so we are taking the complexity of database management from your shoulders and are g automatically from your schema. Whenever you add a new type, field, or modify the existing ones, our platform generates migrations and which you can use to write business logic in resolvers.

    At the moment, we are supporting Typescript/JS services, thus the generation of TypeORM models. We are going to support other programming languages as well, with PHP being the next one.

    Promote your service to a private environment

    When ready, push your changes to our cloud using the to our platform. code.store will check your code, containerize it, and deploy it to a private . You can then promote your service to the Demo environment, which is used to let every developer in your experiment with your and check if it corresponds to the needs of their .

    Add a service to a project

    Once created, your cannot be used per se in a production application or site, you need to add it to a . Projects represent applications or sites where your is used. Each service can be used in as many projects as you wish. You can use our web UI or to add your service to any of your projects. Every developer in your organization can create projects and add services to them. A is created when you add a service to a . It's an entirely isolated version of your service: it has its dedicated environments, database, and logs.

    Sell your work to your clients for a monthly fee, if you want 💰

    For each in a , you can define a rate-plan so that you can bill your clients monthly per service usage (price per call) or as a subscription. The core idea is to bundle together costs of building the service, its maintenance, support, and hosting in a single simple fee that your client pays. Up to today, you can sell and bill services to your clients only, but we'll be launching a public marketplace as soon as we have enough on-board service .

    Access and Authorization

    Overview

    In order to secure public access to API of your projects and services - code.store platform allows you to restrict access using the request authorization mechanism and using access key

    code.store platform provides an ability to restrict access using access keys, which serve to identify each request that is sent to your services. Access keys are generated by default when a service or project is created. Also, you can create new access keys for the purpose of separating access for clients manually.

    The access key is the sole mechanism for authenticating access to your project/service endpoint and must be included in each request.

    Authorization

    To authenticate your request just add a HEADER “x-user-authorization” to each request, where value of this header will be access key, which you can receive using cs service:info CLI command on the private environment or generate a new one using cs project:client:add command.

    Below an example of authorization using curl command in your terminal:

    More information about service environments and project environments can be found in section. Highly recommended reading before studying the material below

    Service access

    Each service at the beginning is deployed in demo and private environment. But, there are different way to access your service.

    Demo environment access

    Demo environment is always public and can be accessed by any platform user.

    Private environment access

    private environment - it's a private space, where developer can personally run and test his code. In order to restrict access to the development process, a developer key key was created.

    After service creation, you receive a developer key for your private environment. This key must be used each time when you call your service in a private environment.

    If you forget your service developer key - execute cs service:info CLI command, select required service (or just navigate to service directory) and you will find it there.

    Project services access

    Developer key

    By default, when you create a new project - you receive a project developer key. Using this key you can access any service deployed into your project on any environment. If you forget your project developer key - execute cs project:info CLI command, select required project and you will find it there.

    Clients

    There are cases when it is necessary to provide to the whole project or included in the project services to the client or third party person. code.store platform provides and CLI interface, which allows to manage client's access keys.

    Using cs project:client CLI command you can add, list or remove client's access keys for your project and project services.

    Clients access keys has a restriction: using this key client can access only production environment. staging and development environments is available only using developer key.

    In the future, the code.store platform will provide the ability to bill your customers for using the API of your services.

    Create a new client access key

    To create a new client access key just execute cs project:client:add command, select the required project from the list and specify client's email

    List client's access keys

    To list client access keys execute cs project:client:list command, select project form the list below and enjoy your client's list:

    Revoke client access

    To revoke client access you should remove client access key using cs project:client:remove command with CLIENT_ID flag.

    To receive client's ID execute cs project:client:list command

    FAQ

    You'll find all the answers you were looking for since you were born. TL;DR> 42.

    🏠 Where my services are hosted?

    code.store is cloud-agnostic, meaning we can deploy code.store on any cloud provider or even on-premises for Enterprise clients.

    Services of all other plans are currently hosted on our AWS infrastructure (Frankfurt region at the moment, other regions are coming soon).

    🦄 Who creates services?

    You do it. Don't be lazy. 😈

    💰How do I monetize my services?

    There is no public marketplace yet. When you build new projects for your clients, you can create some part of those as reusable . Then you can sell them to your clients with a subscription or pay-per-use rate plan.

    When you add a in a , you can set up a different price for each of your . You can then invite your client to this , providing his billing details. We'll generate the invoice for each client and collect payments for you. Each month you'll receive your combined funds collected from all clients in a single payment from us. Money time!

    💵 How should I price my services?

    You can bundle in a single monthly rate everything:

    • your initial build cost (example: the 50 working days used to build the service)

    • support and maintenance time (example: the 5 working days you spend every month on this service)

    • hosting (code.store costs)

    🗣️ What programming languages do you support?

    At the moment we support only (which is the 2nd most loved programming language in the world 🤘 as per ). If you need a specific language for your , drop us a word .

    🛢 I need a database for my service, how do I create one?

    We provide a managed Postgres database for your services, but you don't have to worry about it as code.store creates and updates your based on the of your .

    🧱 What is a service?

    We call a service piece of code running on our platform that is accessed through a GraphQL API. You can learn more about our core concepts here.

    🖼️ Where should I host my front-end?

    We provide a platform to create and host back-end services that are accessed through GraphQL API. So at the moment, we are not focused on this particular feature, especially knowing that there are already many great services that can help host your frontend in the cloud.

    However, this is something that is in our roadmap, and you can to help us prioritize it!

    Configuration

    Overview

    Each service has a default configuration file, which available by default, after new service creation. This configuration file named codestore.yaml and located in the root of service dir.

    codestore.yaml is required, without it, the service will not be launched. Please, don't remove this file.

    This file contains service configuration and used to:

    • enable/disable PostgreSQL database

    • enable/disable Redis database

    • setup configuration for local development

    • contains internal code.store's serviceId

    Variables

    serviceId internal code.store's service id

    serviceConfiguration remote service configuration, which allows and contains the following flags:

    • skipDatabase (false by default) boolean flag, allows to enable or disable PostgreSQL database

    • enableRedis (false by default) boolean flag, allows to enable or disable Redis database

    localConfiguration configuration, which allows to run local development service using cs dev CLI command and. Local configuration contains service, database (Redis, PostgreSQL) configurations which required if databases in serviceConfiguration are enabled. localConfiguration is contains the following properties:

    • application

      • port a port where an application will runs

    • database PostgreSQL connection config

    localConfiguration applies only during local development process and have no impact on deployed application

    Configuration versions

    In future, code.store platform will support different codestore.yaml configuration versions for backward compatibility.

    Enable/Disable PostgreSQL

    By default, PostgreSQL - enabled. To disable PostgreSQL set skipDatabase: true of the serviceConfigurationobject and push changes using cs push command.

    Enable/Disable Redis

    By default, Redis - disabled. To enable Redis set enableRedis: true of the serviceConfigurationobject and push changes using cs push command.

    Models

    Overview

    code.store platform by default use RDBMS with and provides opportunity to generate models and migrations based on your schema.graphql.

    is a powerful, open source object-relational database based on SQL and supports many of the features of the SQL standard.

    Logging

    Overview

    From time to time becomes necessary to monitor the status and progress of a deployed application, look at the current application activity, or debug an error.

    code.store platform provides an interface for working with report logs. By default logs contain information about the exceptions that the deployed application produces, service bootstrap and other things that the developer considered necessary to add as logs.

    On backstage, as a log storage code.store platform used database, which allows to organize a quick search through the logs.

    Environments

    Overview

    Environments are created for those cases when it is necessary to create a set of independent services, with own databases, which interacted with each other, in order to isolate the environment for development, testing, and release of service groups.

    In service deployment, environments are a kind of isolation medium. Each environment unites certain sets of rules which describe components that it includes, namely: services, their versions, databases, routing traffic rules...

    For convenience, we on the code.store platform creates several environments at once for the purpose of comfortable development and rolling out updates.

    Getting started

    code.store CLI provides a set of commands that allow you to manage your services and projects. This section contains the installation steps, a typical workflow and a description of main commands.

    Installation

    We are iterating really fast in order to bring the best user experience and some great features to our product, that's why please check for updates in our CLI!

  • port port, where Postgres server launched, usually it's 5432

  • username your Postgres user

  • password password for your Postgres user

  • host PostgreSQL host (for example localhost or 127.0.0.0)

  • database name of the database

  • and provision for new features
    (for example yearly 20 working days used to add new features to your service).
    Code
    projects
    services
    service
    project
    service-instances
    project
    TypeScript
    the 2020 Stack Overflow survey
    project
    here
    database
    GraphQL schema
    service
    drop us a message in our community

    environment

    version

    development

    0.0.3

    staging

    0.0.2

    production

    0.0.2

    semver
    semver
    environment
    Services
    environment
    semver
    environment
    environment
    access
    project
    environment
    Projects
    environment
    Environments
    TypeORM is amazing ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports many SQL databases, including MySQL, PostgreSQL,

    Each time, when you develop your application you should carry about your data layer - the place, where database entities, migrations, seeds... are defined. code.store shared developers pain and provide amazing ability automatically generate TypeORM entities and SQL migrations for your database.

    When you create a new type or input for your query or mutation inside schema.graphql, which located in your src service directory, or make changes to already existed types you should make changes inside your data models and think about migrations... You don't have to do it each time, code.store platform provides cs generate:models CLI command, which allows to do whole magic for you!

    Generate models and migrations

    Models and migrations are powerful tool, which allows you to generate complex things. Generator supports different types and relations such as one-to-one, one-to-many, many-to-many...

    Simple entity

    First of all, you should define your types in schema.graphql, which located in src directory of your service. For example, let's define a simple type Post with some fields:

    After schema.graphql modification execute cs generate:models CLI command, which will trigger generation process. During command execution schema.graphql file will upload to code.store's generator. code.store's generator will validate this schema, generate TypeORM entities and migrations and save it on your local machine on src/generatedData folder:

    Generated data

    generatedData/ includes two directories:

    • entities/ dir with your TypeORM entities

    • migrations/ dir with SQL migrations

    code.store's generator allows you to generate models and migrations both for service which already has models and migrations and for an empty project, where you just define your GraphQL schema.

    For Post type generated next migration in src/generatedData/migrations/Migration1606769241856.ts file:

    There are two methods you must fill with your migration code: up and down. up has to contain the code you need to perform the migration. down has to revert whatever up changed. down method is used to revert the last migration. To learn more about TypeORM migrations visit TypeORM migrations page.

    Also, you can find a TypeORM entity inside generatedData/entities/Post.ts file.

    Apply generated changes

    If everything is OK and generated files meet your needs - just copy them to the appropriate directories: src/data/entities and src/data/migrations.

    To make sure that generated entity is correct, just execute cs dev CLI command. As a result you can find the Post table inside your database. More information about local launch of your code you can find in local development section.

    We recommend use entities and migrations generation as bootstrap feature. Always check the files that are generated to avoid surprises.

    Postgres
    TypeORM
    PostgreSQL

    Note: logs are stored on the platform for a month.

    Service logs

    To reach service logs navigate to your service directory and execute cs service:logs command, or specify service ID using -s flag. Below is an example of listing demo_app service logs, where demo_app is an id of service.

    Logs for private environment will be displayed, if environment is not specified manually.

    By default, command display only 20 of the most recent log lines, to increase output lines count use -n flag. Below is an example of listing demo_app service logs, where output lines count are set to 1000

    Project and environment logs

    Project logs

    To access full project logs you should specify project ID using -p flag.

    To list your available project execute cs project:service:list command. Learn more on the Projects section.

    After command execution logs from all deployed services on all (development, staging, production) environments will be displayed.

    Environment logs

    To filter environments just specify environment name using -e flag. Below is an example of displaying logs of all deployed services on development environment of my_project project.

    Also, you can display service logs from demo and private environment. To display these logs specify environment name using -e and service id using -s flag.

    Logger

    Overview

    code.store platform read full stdout log and store, you may use any convenient logger. But, to make developers life easier - code.store platform provides a built-in logger, which can be imported from codestore-utils.

    Built-in logger provides default method for logging and map each log for future text search. Logger provides default logging methods, such as:

    • log - informational logs that might make sense to system administrators, and highlight the progress of the application

    • error - error logs of considerable importance that will prevent normal program execution, but might still allow the application to continue running

    • warn - potentially harmful situations of interest that indicate potential problems -

    • debug - information that is diagnostically helpful to people more than to system administrators

    • verbose - verbose information about any thing which may be useful

    Usage

    By default, any log method consume three params: message, context and data.

    message - is a message, which will be logged

    context (empty by default) - is a prefix of message, which usually indicated where method was executed (method, or constructor name for example...). This param are .

    data (optional) - is an optional object, which will be stringify and append to the message

    Example of usage:

    An exception to the rule is an error method that has a slightly different signature:

    This method usually used to log a handled exception. You can just pass an error object as first argument and logger will format a message to valid format. For example:

    elasticsearch
    macOS

    Other installation methods

    NPM

    This installation method is not recommended as it does not auto-update.

    Standalone tarballs

    These are available in gzip compression:

    • macOS

    • Linux (x64)

    • Windows (x64)

    • Windows (x86)

    • PalmOS (just kidding)

    Verifying the installation

    To verify that the CLI has been correctly installed, use the codestore --version command:

    You should see "codestore x.y.z darwin-X node-vX.Y.Z" output.

    The CLI can be accessed through two commands: codestore or its shorter version cs

    Staying up to date

    The code.store CLI will keep itself up to date automatically, unless you installed it via npm install. In that case use npm update codestore in order to upgrade the package to the latest version.

    Most of the commands accept some specific arguments which can be provided while invoking the command in a long or short formats:

    • Long format: cs command --argumentName argumentValue

    • Short format: cs command -a argumentValue

    Use cs help to know more about its commands and their arguments.

    Service directory structure

    For each service, the code.store CLI is generating a directory structure that resembles the following:

    Read more about the anatomy of the service directory here.

    > cs service:info
    
                  Private                                                         Demo                                                            
    version       0.0.2                                                           0.0.1                                                           
    deployed      8/5/2020, 10:37:21 PM                                           8/5/2020, 10:38:58 PM                                           
    developer key null                                                                                                                            
    url           https://api.code.store/a6203d238a744492bf1bf33833c3ebf6/graphql https://api.code.store/a858e12ddd2c47f5b381bef9d98dc7a9/graphql 
    > cs project:service:info
    
                  Development                                                     Staging                                                         Production                                                      
    version       0.0.3                                                           0.0.2                                                           0.0.2                                                           
    deployed      8/5/2020, 10:39:22 PM                                           8/5/2020, 10:39:23 PM                                           8/5/2020, 10:39:21 PM                                           
    developer key                                                                                                                                                                                                 
    url           https://api.code.store/8ddc603ea9dd4a669755bf2125bdca24/graphql https://api.code.store/bb2eae903e924bdeb3f6fe9627055d93/graphql https://api.code.store/efe4caaf5584497599728f3785e8fc7d/graphql 
    cs promote
    cs project:service:promote
    cs project:service:roll
    curl \
      -X POST \
      -H "x-user-authorization: DEFINE_YOUR_ACCESS_KEY_HERE" \
      --data 'your GraphQL query' \
      https://api.code.store/{service_url_hash}/graphql
    > cs service:info
    
    version       0.0.1                                                           0.0.1                                                           
    deployed      11/17/2020, 4:05:27 PM                                          11/17/2020, 4:14:58 PM                                          
    developer key cff7f0fb-8856-48e7-817b-0d83c696b247                                                                                            
    url           https://api.code.store/{SERVICE_HASH}/graphql https://api.code.store/{SERVICE_HASH}/graphql 
    > cs project:info
    
    Project ID:	 YOUR_PROJECT_ID
    Status:		 ACTIVE
    Services:	 1
    Developer Key:	 YOUR_PROJECT_KEY
    Author:		 [email protected]
    > cs project:client:add
    
    Email: [email protected]
    Key: YOUR_CLIENT_KEY
    > cs project:client:list
    
    Client ID     Key                      Email            
    1             YOUR_CLIENT_KEY          [email protected]
    > cs project:client:remove --CLIENT_ID 1
    
    Client access key successfully removed!
    type Post {
        id: ID!
        createdAt: String!
        title: String!
        body: String!
        authorName: String!
    }
    > cs generate:models
    
    ✔ Reading the service schema
    ✔ Uploading the service schema to the generator
    ✔ Generated code has been saved to ...demo_app/generatedData 
    import {MigrationInterface, QueryRunner} from "typeorm";
    
    export class Migration1606769241856 implements MigrationInterface {
        name = 'Migration1606769241856'
    
        public async up(queryRunner: QueryRunner): Promise<any> {
            await queryRunner.query(`CREATE TABLE "Post" ("id" BIGSERIAL NOT NULL, "createdAt" varchar NOT NULL, "title" varchar NOT NULL, "body" varchar NOT NULL, "authorName" varchar NOT NULL, CONSTRAINT "PK_c4d3b3dcd73db0b0129ea829f9f" PRIMARY KEY ("id"))`, undefined);
        }
    
        public async down(queryRunner: QueryRunner): Promise<any> {
            await queryRunner.query(`DROP TABLE "Post"`, undefined);
        }
    }
    import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
    
    @Entity('Post')
    export default class Post {
      @PrimaryGeneratedColumn()
      id: number;
    
      @Column()
      createdAt: string;
      
      @Column()
      title: string;
      
      @Column()
      body: string;
      
      @Column()
      authorName: string;
    }
    
    > cs logs -s demo_app
    
    Displaying logs for environment private, service demo_app
    2020-11-17T14:02:49.243Z [GqlLoader] Loaded queries: helloWorld
    2020-11-17T14:02:49.338Z [RestLoader] Loaded REST handlers:
    2020-11-17T14:02:49.341Z [RestLoader] -> /name - GET
    2020-11-17T14:02:49.341Z [Bootstrap] -> [GET] http://localhost:3002/rest/name
    2020-11-17T14:02:49.341Z [Bootstrap] REST endpoints are available on:
    2020-11-17T14:02:49.341Z [Bootstrap] GraphQL is available on: http://localhost:3002/graphql
    > cs logs -s demo_app -n 1000
    > cs logs -p my_project
    > cs logs -p my_project -e development
    > cs logs -s demo_app -e demo
    import { logger } from 'codestore-utils';
    public log(message: any, context = '', data?: any): void
    public warn(message: any, context = '', data?: any): void
    public debug(message: any, context = '', data?: any): void
    public verbose(message: any, context = '', data?: any): void
    import { logger } from 'codestore-utils';
    
    
    logger.log('User received a new achievement', `${this.constructor.name}`, { achievement: { name: 'STAR', level: 3 }});
    public error(error: string | Error, trace = '', context = '', data?: any): void
    import { logger } from 'codestore-utils';
    
    
    try {
        throw new Error('This is an error...');
    } catch(e) {
        logger.error(e);
    }
    
    brew tap code-store-platform/brew && brew install codestore
    npm install -g codestore
    codestore --version
    # Example of the directory structure of a Service
    ./
    ├── src/
    │		├── data/ # contains generated TypeORM entities
    │		├── resolvers/
    │		│		├── mutations/
    │		│				└── mutationExample.js|ts
    │		│		├── queries/
    │		│				└── queryExample.js|ts
    │		└── schema.graphql # GraphQL definition of your service's API
    ├── .build # temporary directory
    ├── package.json # standard NPM configuration file
    └── codestore.yaml # main configuration file
    For example, when you creating a new project, we automatically create three environments: development, staging, production (hereinafter: Project Environments).

    These environments are completely isolated from each other and are separate namespaces in our k8s cluster. When we include a new service in the project, we deploy a copy of a container with different databases in all three environments.

    In case when we create a new service, we deploy it on its own, isolated environments - private and demo (hereinafter: Service Environments)

    Service Environments

    When we create a new service, it is automatically deployed in two environments, which called: private and demo.

    service "A" which deployed on private and demo environment

    Private Environment

    A private environment - serves to enable an opportunity to update service and test the changes made in an isolated environment. The API of this service is accessed using a key that is generated when the service is created. Access to services, which deployed in this environment, has only the owner (developer) of this service.

    Demo environment

    demo environment - serves to publish changes, after the active development process, from a private environment. demo environment - serves as a starting point for distributing the service, or its new versions, to other projects. demo environment is a public environment, where any person who has a link - can access service without any authorization.

    You don't have to worry about creating any environment when creating a new project - code.store platform does it for you automatically.

    More details on how to create a new service can be found in Projects section. Information on how to deploy updates from private to demo environment is in the Versioning section.

    Concept

    Developer, after new service creation, may test it and roll updates using cs push command on the private environment.

    When changes were made and ready to publish - a new service version can be rolled up to demo environment using cs promote command.

    After promotion service to demo environment - a new version becomes publicly available. "Public" version - is an exact version, which will be rolled, when you include a new service in the project.

    Services are available only for the owner (person who created a service) and the organization, which he belongs

    For services deployed on demo and private environments, a set of restrictions and rules apply. These services do not scale under load and available only when requested.

    What does it mean "services on demo and private environments are available only when requested?" For example, if service doesn't receive any HTTP requests for a long time - code.store platform will transfer it to standby mode. As soon, as a request comes to it - service container becomes active. The first request to the service, after a long time in standby mode, may take slightly longer than usual. Subsequent requests will run normally.

    private and demo environments are created only for the purpose of developing service, demonstrating their functionality, and acts as a point for distributing updates.

    Project Environments

    In a micro-service architecture, deployment approaches are different, but in general, environments start with development and production environments.

    We understand how important testing and pre-release preparation for projects and added a staging environment. So, each project on the code.store platform includes the following environments:

    • development

    • staging

    • production

    project, which includes DEVELOPMENT, STAGNING, PRODUCTION environments with deployed services on it

    development and staging environments have some limitations in terms of scaling and intended for active development and testing.

    production environment has a specific set of rules for scalability and availability. We guarantee SLA (Service Level Agreement) 99.9% of the services deployed to the production environment.

    You don't have to worry about creating any environment when creating a new project - the code.store platform does it automatically.

    For more information on how to create a project, how to include or exclude a service from a project, see the Projects section.

    enerating database tables
    TypeORM Entities (also called models),
    CLI
    environment
    organization
    service
    project
    service
    project
    service
    CLI
    service-instance
    project
    service-instance
    project
    makers

    Secret management

    Overview

    Managing sensitive strings such as passwords, API keys, and secret credentials — is just one of the steps in the quest for increasing security in a project. We understand this like no one else and provide an extremely easy and secure way of managing secret variables.

    All secret variables are stored in Vault, secret storage from HashiCorp organization, which provides a high-security level thanks to its architecture and secret engines.

    Service Secrets

    For convenience, all variables that we specify for the service are available as environment variables. In order to add a new variable for the service, you can use the CLI interface, which can be found in .

    Please note, that each operation with a secret (create, update, remove…) will trigger service (container) reboot. Currently, we are working on improving the current secret delivery solution. Soon, secrets variables will deliver to your services on the fly.

    Service secrets are secure key-value storage, which syntax is available using cs secret command.

    Add a new service secret

    To add a new secret variable just execute cs secret:add command with flags which next flags:

    • -k key of the secret variable

    • -v value of the secret variable

    • -s service ID

    Information about all supported flags can be found on section.

    Below is an example of adding the FOO variable with the BAR value to the existing service with ID: MY_SERVICE. For clarity, we will use a service that is deployed in a demo environment.

    Successful result of the command execution will be:

    That’s it! Now, variable FOO will be available as an environment variable after container reboot. Now, you can access it in your code.

    Access a new variable in code

    For example, to access variable using TypeScript use process global variable:

    List service secrets

    Update service secret

    Remove service secret

    Project Service Secrets

    Using the same command syntax we can add an environment variable for any project services.

    -p flag allows adding a variable on the project level.

    The FOO variable is now available inside the MY_SERVICE service, which is included in the MY_PROJECT project.

    Please note: MY_SERVICE service is already included in MY_PROJECT project.

    But what if my project includes many services that are deployed in different environments? Would be inconvenient to prescribe a separate set of secret variables for each service, so we implemented inheritance.

    Inheritance

    There are cases when we need to specify only one secret variable for all services which includes in the whole project. In this case, we can just execute cs secret:add only with -p project flag.

    Let's imagine that we have an empty project with ID: MY_PROJECT, which includes three services with ID's: A, B, and C. They, by default, deployed on three project environments: development, staging, production. For more information about environments, see the section.

    Project level variables inheritance

    Let’s add variable FOO with value BAR to project MY_PROJECT, which will be available for each service on each environment inside MY_PROJECT project.

    Successful result of the command execution will be:

    As you can see, the Source of a variable - is a project, where we just added a new variable. From this moment, we can access FOO variable from each service, in each environment, which included in our project. In the diagram below, the services that have access to the value of the FOO variable are highlighted in green:

    Environments level variables inheritance

    We may face a case when you need a different secret variable value on some service or on the whole environment. This isn't a problem, cause we can just override the value of the variable, using the same cs secret:add command, specifying for which environment/or service we should apply it.

    For example, if we specify the FOO variable with value BAR2 for a project MY_PROJECT from the previous example and just set flag -e (environment) with value development, we override this value for each service in the development environment.

    Successful result of the command execution will be:

    In this case, the Source displays the current variable source and shows that FOO variable has BAR2 value for each service, WHICH includes in the project MY_PROJECT, and deployed on the development environment. In the diagram below, the services that have access to the new value BAR2 of the FOO variable are highlighted in blue:

    Service level variable inheritance

    In case, when our service requires another secret variable value - we can just override it. To override it - just specify -s flag with service ID, let it be service A for example, and a new value of FOO variable is BAR3.

    Successful result of the command execution will be:

    In this case, service A will obtain a new value of FOO variable. In the diagram below, the services that have access to the new value BAR3 of the FOO variable are highlighted in yellow:

    Basically, you can do the same with services, which deployed on demo and private environments. But note, that demo and private - is a non-production service environments, and has many limitations, including "per-request availability". To learn more see section.

    GraphQL

    A quick guide to get you onboard with GraphQL

    When you create a service on code.store, it is accessible via a unique API endpoint and you'll need to use GraphQL in order to interact with this endpoint.

    While you'll find all the details on GraphQL site, we've prepared you a short summary of GraphQL basics here.

    What is GraphQL ?

    You can think of GraphQL as of SQL but for API (it is a very loose and far-fetched analogy, but it should deliver the message).

    GraphQL is an API standard that provides a more efficient, powerful and flexible alternative to REST. It was developed and open-sourced by Facebook but now many companies, including us, support and rely on GraphQL. We do think it will become worldwide API standard very soon.

    code.store GraphQL service is created by defining types and fields on those types, then providing resolvers for those types.

    GraphQL types

    GraphQL has its own type system that’s used to define the schema of an API. The syntax for writing schemas is called (SDL).

    Here is an example how we can use the SDL to define a simple type called Product:

    There are 5 built-in scalar types with GraphQL: Int, Float, String, Boolean and ID. Scalar types, as opposed to object types, point to actual data. The ID type resolves to a string, but expects a unique value.

    Enumerations

    Enumeration types allow to define a specific subset of possible values for a type. In the previous example, the Category enum type can take a value of Clothes, Shoes or Watches and anything else will result in a validation error. We need to update our example providing definition of our enumeration category :

    Type modifiers

    Modifiers can be used on the type that a field resolves to, by using characters like ! and […]. Here’s a breakdown, using the String scalar type as an example:

    • String: nullable string (the resolved value can be null)

    • String!: Non-nullable string (if the resolved value is null, an error will be raised)

    • [String]: Nullable list of nullable string values. The entire value can be null, or specific list elements can be null.

    GraphQL queries execution

    GraphQL doesn’t just specify a way to describe schemas and a query language to retrieve data from those schemas, but an actual execution algorithm for how those queries are transformed into results. This algorithm is quite simple at its core: the query is traversed field by field, executing “resolvers” for each field.

    The payload of a GraphQL query (or mutation) consists of a set of fields. In code.store, each of these fields actually corresponds to exactly one service that’s called a resolver. The sole purpose of a resolver function is to fetch the data for its field.

    When code.store receives a query, it will call all the functions for the fields that are specified in the query’s payload. It thus resolves the query and is able to retrieve the correct data for each field. Once all resolvers returned, the server will package data up in the format that was described by the query and send it back to the client.

    Queries to retrieve data & mutations to push data

    Queries as mutations are the methods or functions of your API. Both have arguments and can return scalars or objects. The difference between the two?

    Use queries to query data from your API. With query, you do not modify your model (even if you can, you should not).

    Use mutations to update or create things in your service model. Mutations are also methods or functions of your API and can accept arguments. Use them to modify your model.

    A mutation can contain multiple fields, just like a query. There's one important distinction between queries and mutations, other than the name:

    While query fields are executed in parallel, mutation fields run in series, one after the other.

    This means that if we send two incrementCredits mutations in one request, the first is guaranteed to finish before the second begins, ensuring that we don't end up with a race condition with ourselves.

    GraphQL

    Overview

    code.store platform supports GraphQL and allows you to set up your GraphQL API in the quickest way. To make a developer's life easier code.store platform:

    • by default runs GraphQL Apollo Server

    • provides an opportunity to generate database entities based on graphql.schema

    • generate resolvers for your queries and mutations

    • secure your GraphQL API from massive complex requests and DDoS attacks, and allows you to configure GraphQL query costs

    Basic information about GraphQL can be found in section.

    Endpoint

    By default, code.store platform runs and GraphQL playground available via /graphql endpoint.

    Local development:

    Remote address:

    Schema

    When you create a new service, we code.store platform generating it with default schema.graphql file, which contains services GraphQL schema. You can find it in src directory of the generated project. Generated file contains a simple helloWorld query:

    It's a very basic schema of an API that has a single Query called helloWorld (which doesn't accept arguments) and which returns a single output of type string. You can query it using GraphQL playground, which available on /graphql endpoint or execute next command using CLI:

    Please, replace service_url_hash on your service URL hash, which can be found after cs service:info command execution. After helloWorld query execution we should get "Hello, World!" response in our terminal:

    Resolvers

    Each field, query or mutation, which we specify in schema.graphql require resolver. A resolver is a function that's responsible for populating the data for a single field in your schema.

    Handler for all queries and mutations, which described in schema.graphql file should be placed to src/resolvers directory. Each resolver file of your query or mutation should be named the same, as it declared in graphql.schema and placed the appropriate directory src/resolvers/queries for queries and src/resolvers/mutations for mutations.

    For example, in generated service template you can find, that query helloWorld in schema.graphql have resolver src/resolvers/queries/helloWorld.ts

    code.store platform simplifies the process of creating GraphQL resolvers and their handlers using flexible configuration and provides an ability to generate it using cs generate:resolver command.

    Context

    Each resolver can optionally accept four positional arguments:

    parent returns value of the previous resolver in the resolver chain for this field's parent

    args an object that contains all GraphQL arguments provided for this field. For example, when executing a query: query{ user(id: "4") }, the args object passed to the user resolver is { "id": "4" }.

    context an object shared across all resolvers that are executing for a particular operation and has ResolverContext type.

    As you can see, context allows receiving database connection and provide access to request object, which includes such objects as headers, method, url...

    info contains information about the operation's execution state, including the field name, the path to the field from the root, and more.

    Data management

    Overview

    code.store platform allows you use two database types for your services:

    Recipes - GraphQL
    Apollo Server

    Redis

    Based on standards for building a microservice architecture, we follow database-per-service design pattern and generate separate database for each service.

    Connection details are provided in env variables.

    You can manage your data using visual data manager using backoffice on the service page (will be available soon)

    Postgres

    code.store platform by default creates a Postgres database for each your service. You can enable or disable database using codestore.yaml configuration file in the root service directory.

    You have no limits in your database and can store any data there, code.store platform takes care of the scaling of your relational database so your database can keep up with the increasing demands of your application or applications.

    To disable or enable Postgres database for your service just set it in skipDatabase flag.

    • true - to disable Postgres database

    • false (default value) - to enable it

    You can find connection to your database in context variable which available inside each handler method. More information about context objects can be found in GraphQL and REST sections.

    To apply changes just push your service code using cs push command

    Redis

    To disable or enable Redis database for your service just set it in enableRedis flag.

    • true - to enable Redis database

    • false (default value) - to disable it

    You have no limits in your Redis database and can store any data there, code.store platform takes care of the scaling of memory usage so your database can keep up with the increasing demands of your application or applications.

    To get credentials for Redis database use next env variables:

    REDIS_HOST

    REDIS_PORT

    More information about accessing environment variables can be found in Environment variables section.

    Postgres
    http://localhost:3000/graphql
      https://api.code.store/{service_url_hash}/graphql
    type Query {
        helloWorld: String!
    }
    curl \
      -X POST \
      -H "Content-Type: application/json" \
      --data '{ "query": "{ helloWorld }" }' \
      https://api.code.store/{service_url_hash}/graphql
    {"data":{"helloWorld":"Hello, World!"}}
    import { logger, Resolver } from 'codestore-utils';
    
    const resolver: Resolver = async (parent, args, context, info) => {
      logger.log('This is a helloWorld resolver!', 'helloWorld');
      return 'Hello, World!';
    };
    
    export default resolver;
    
    export interface ResolverContext {
        db: {
            connection: Connection;
        };
        request: Request;
        [key: string]: any;
    }
    serviceConfiguration:
      skipDatabase: true
    serviceConfiguration:
      enableRedis: true

    -e service environment

    Commands section
    Commands
    Environments
    Environments
    Project without any secret variable, which includes three services: A, B, C
    Services, where available project level FOO variable.
    Services, where available environment level FOO variable with BAR2 value.
    Service A with a new value of FOO variable.

    [String!]: Nullable list of non-nullable string values. Then entire value can be null, but specific list elements cannot be null.

  • [String!]!: Non-nullable list of non-nullable string values. Nothing can be null, neither the whole value nor the individual items.

  • Schema Definition Language

    Projects

    Overview

    Projects are the essence of the code.store platform, which has the ability to contain many services.

    Projects serve as an isolated environment for services groups. Any project can contain one or more services, and available within the organization the user belongs to.

    In order for the service to be publicly available, it must be included in the project, since the code.store platform guarantees high availability and scalability only in a production environment. For more information about environments, see the Environments section.

    Create a new project

    In order to create a new project, you need to execute cs project:create command and provide information about your service. Below an example of cs project:create command execution:

    Successful result of the command execution will be:

    After successful project creation, an access key to the development and staging environments will be issued in the command output. Information about authorization using the provided key can be found in section.

    When creating a new project, by default, the code.store platform will create three environments: development, staging, and production. For more information about environments, see the section.

    Let's make sure that the project has been created by running the cs project:list command.

    Project ID displays ids of all projects that available for user. Please, note, that ID is lowercase.

    Services count of included to project services.

    Author email of the project creator.

    Description description, which user set, when creating a project.

    After creating a project, it will be available to all members of the organization to which the user belongs.

    Include service to project

    By default, there are no services in the project. To add a new service to the project just execute cs project:service:add command with two arguments: projectID - where service should be included and serviceID - id of service, which will be included.

    For example, let's include service demo_app to the my_project project:

    Will be included version of the service from the demo environment.

    After command execution, the service is being to deploy to the development project environment.

    To monitor service deployment status just execute cs project:service:info command and select the project and service.

    cs project:service:info command output will display environments, where service is deployed (in our case service just added to project and deployed only to development environment), deployed service version, developer key, and the service URL.

    Promote service

    After adding a new service to the project, it becomes necessary to deploy it not only to development but also to staging and production environments.

    To promote service per environments available cs project:service:promote command. After command execution, you will be able to select the project, service which already included into the selected project and environment, where service should be deployed.

    In the example above, we promote service with ID: demo_app, which already included to project with ID: my_project to the staging environment.

    Using this approach, you can deploy the service to a production environment.

    Update service version

    To update service version just re-use cs project:service:promote command.

    Note, after command execution version from the demo environment will be applied.

    It is necessary that the service was previously updated on the demo environment. For more information about environments, see the section. About versioning see the section.

    Exclude service from project

    Delete project

    cs secret:add -s MY_SERVICE -e demo -k FOO -v BAR
    Successfully added a new secret variable FOO
    Key Value Source                            
    FOO BAR   Environment: demo, ServiceID: 1 
    process.env.FOO
    cs secret:add -p MY_PROJECT -s MY_SERVICE -e development -k FOO -v BAR
    cs secret:add -p MY_PROJECT -k FOO -v BAR
    Successfully added a new secret variable FOO
    Key Value Source        
    FOO BAR   ProjectID: 1 
    cs secret:add -p MY_PROJECT -e development -k FOO -v BAR2
    Successfully added a new secret variable FOO
    Key Value Source                                  
    FOO BAR2  ProjectID: 1, Environment: development 
    cs secret:add -p MY_PROJECT -e development -s A -k FOO -v BAR3
    Successfully added a new secret variable FOO
    Key Value Source                                                 
    FOO BAR3  ProjectID: 1, Environment: development, ServiceID: 1 
    type Product { 
        title: String! 
        SKU: ID!
        descirption: String!
        price: Float!
        stock: Int!
        category: Category!
    }
    enum Category {
      Clothes
      Shoes
      Watches
    }
    
    type Product { 
        title: String! 
        SKU: ID!
        descirption: String!
        price: Float!
        stock: Int!
        category: Category!
    }
    Access and Authorization
    Environments
    Services
    Versioning
    Include service to project - deployment schema
    Promote service to staging
    Updated version on development environment.

    Core concepts

    This page is all about definitions and vocabulary to get you on board as fast as possible.

    🧱 Service

    Service is the most crucial concept in code.store. It is a stand-alone web-service that can be (re)used in projects. What defines a service:‌

    • GraphQL Schema: you start by defining a GraphQL API describing types, queries and mutations of your service

    • Code: actual code that is invoked when your GraphQL API is called. There is a specific structure and naming convention for your files which we describe in our Quick Start guide.

    • Database: based on your GraphQL schema, there is a where you can store your data. We take care of its creation, updates and whole management including automatic migrations in case of any change in your .

    • Documentation: when you create a new service you need to explain what functional problem your service solves, how does it solve it and what is its functional domain (e-commerce, content management, logistics, etc.). You can also add some free #tags to help users search for your service.

    What makes a perfect code.store service :

    • Independent: it does not rely on anything else to function (no external APIs or services or software is required to use it).

    • Isolated: by all means, it should avoid communication with external systems (except for connectors)

    • Autonomous: it's shipped with a database and file storage if any of those are required.

    Some examples of what we call service : ‌

    • Shopping cart of an e-commerce site

    • Meeting rooms booking system

    • Email sending service

    • Credit card payment

    Each service has 2 : private - used by service for their development and tests, and demo, used by developers to test the service

    🚧 Project

    A project is a particular app or website, where you reuse your existing services. It might be your e-commerce project or a logistics mobile application or business web-app. Because you pay us only when we help you save money, we bill you only for live (those that are included in Projects).

    Each time you add a service to a project, we create a separate, isolated instance of your . Each service reused in a project has its own , , logs, and billing.

    ♻️ Service instance

    A service reused in a is an instance of a you've created. Each time you add a service to a project, you create a service instance. Each instance of a service is isolated, runs its own set of 3 (dev, stage, prod) and is accessible through its GraphQL .

    ⚛ Schema or GraphQL Schema

    A schema or defines and describes your . It uses with some additional directives. You have to define 3 main things:

    • : they describe objects your service is manipulating (Product for a cart, Meeting Room for rooms booking engine or Client for a CRM service).

    • : at its simplest, GraphQL is about asking for specific fields on objects. It's a shorthand syntax where we omit both the query keyword and the query name, but in production apps, it's useful to use these to make our code less ambiguous.

    • Mutations: most discussions of GraphQL focus on data fetching, but any complete data platform needs a way to modify server-side data as well. So mutations offer your API consumers a way to create and update objects manipulated by your service (i.e., addToCart(productSKU))

    📁 Model

    A model is a description of the way your service's database is structured. You cannot directly modify your service's model, which is generated based on the GraphQL schema of your service. We generate TypeORM entities in your service files directories here: /src/models/

    ‌ You can access the structure of your database or model through the web-UI data viewer too.

    🛢Database

    Each has a managed database related to its . Each time you add, remove or update a type or a field, we automatically update and migrate your service's database. We use PostgreSQL to run your service's database, and we generate TypeORM entities to help you access your data from your service's code. You can also access your database, through ou data viewer web-UI.

    🍱 Environment

    An environment is an isolated, running copy of your service. Your is automatically shipped with 2 environments: private and demo. Private is visible only to you, the service , while demo is used to test the service by anyone in your willing to use it on their . It's also demo environment which is used in web-UI service page where users within your can use the playground to experiment with your service.

    As soon as you reuse a in a , you create a and 3 environments for this particular service in this particular : dev, stage and prod. Each environment has its own , , logs and other stuff. Be careful though, only prod environment is suitable to be used, well... in production, others (dev, stage, private, demo) have quotas and limitations and are not scalable.

    Of course, you are not obliged to use any of those environments, and you can push your service to prod as soon as it's ready. However, first of all, it is not considered to be a good practice, and secondly, you may want to match the environment of your service with that of your front-end.

    👷‍♀️Maker

    If you read this documentation, you're a developer. We needed to distinguish developers who create from those who use them in . It's not a role or hard distinction, and you can be both consumer and maker of services within your . So to make it clear, we call maker the developer who created a .

    🤷‍♂️Client

    When you enable billing on your , you're prompted to invite a client to your . So on code.store, a client is an who pays for used in a project. It's entirely optional to have clients. If you don't sell your services and use them internally, you will not need to deal with clients.

    🏢Organization

    It's an entity where projects, services and users are attached to. All services you create as a maker are visible to all users within your organization. Each user of code.store is always attached to an organization.

    ⚓ Endpoint

    It's the URL you need to call to connect to your and execute queries. There is an endpoint for each of your . There are endpoints used to test a service before using it (private and demo attached to each service created by your ), and there are 3 endpoints for each inside each : dev, stage and prod.

    REST

    Overview

    At the moment, code.store's platform supports a simple file-system-based routing of REST API endpoints.

    REST endpoints are based on framework, so you can use all Express features to build your application. Using REST-based on you are able to create endpoints of different methods (such as GET, POST, PUT, DELETE, PATH…), define your route paths, handlers, work with route parameters, define your middlewares…

    code.store platform simplifies the process of creating endpoints and their handlers using flexible configuration and provides an ability to generate a couple of entities.

    > cs project:create
    
     What is your project's name?
     Name: MY_PROJECT
     
    
     Please add a short description of your project. 255 chars max
     Description: This is my project.
     
     ? Is everything ok, can I create this project? (Y/n) Y
     
     ⠦ Creating Project "MY_PROJECT"   
    ✔ Your project "MY_PROJECT" with ID my_project has been created!
      › You can now add your services there using  codestore project:service:add  command.
        Use your developer key to access developer and stage environments: bb9c2512-3d4c-4e57-8dfa-99eafc1484c8 
    Project ID     Services     Author                   Description      
       
    my_project     0            [email protected]      This is my project.                  
    > cs project:service:add my_project demo_app
    
     Would you like to enable billing for your service?
     Enable billing: No
    ✔ Service demo_app is included to project my_project
    Status: DEPLOYMENT_INITIALIZING 
    
    > cs project:service:info
    
     Choose which project you want to display information about
     Project: my_project
    
    
     Choose which service you want to display information about
     Service: demo_app
    
                  Development                                                     
    version       0.0.1                                                           
    deployed      11/17/2020, 12:15:02 PM                                         
    developer key                                                                 
    url           https://api.code.store/8e7bf7e43f63414c9f7fc8d7fe7d0410/graphql 
    > cs project:service:promote
    
     Choose a project you want to promote to
     Project: my_project
    
    
     Choose a service which you want to promote
     Service: demo_app
    
    ? Please select the environment staging
    
    
    Updated "staging" in project my_project
    
    > cs project:service:promote
    
     Choose a project you want to promote to
     Project: my_project
    
    
     Choose a service which you want to promote
     Service: demo_app
    
    ? Please select the environment development
    
    
    Updated "development" in project my_project
    
    Solving one functional problem: we do not limit services by size, but it must solve a real functional problem and only one.
  • Accessible only through GraphQL: yes, the only way to access your service and its data, is through its GraphQL API.

  • Promotions code management for an e-commerce site

  • Client view service presenting complete information about a client gathering parts from SAP, Magento and Salesforce.

  • database
    GraphQL schema
    environments
    maker
    services
    service
    environments
    databases
    project
    service
    environments
    endpoint
    GraphQL schema
    service
    GraphQL
    SDL
    Types
    Queries
    service
    GraphQL schema
    service
    maker
    organization
    projects
    organization
    service
    project
    service instance
    project
    endpoint
    database
    services
    projects
    organization
    service
    services
    project
    organization
    services
    service
    GraphQL
    environment
    service
    environments
    organization
    service-instance
    project
    Endpoints

    code.store platform exposes the http://{your service url}/rest/{endpoint} route, where {endpoint} is getting routed to the file ./src/rest/{http method}.{endpoint}.ts.

    Endpoint handler

    In order to create an endpoint, you need to create a new file in the src/rest folder (by default, no such directory exists) the name of which will contain the request method (GET, POST, PUT, DELETE ...) at the beginning of the name and the name of the route. For example:

    • request GET http://localhost:3000/rest/helloWorld will be routed to src/rest/get.helloWorld.ts

    • request POST http://localhost:3000/rest/user/create will get routed to src/rest/post.user.create.ts

    Commands: cs :generate:rest -m get -n helloWorld and cs :generate:rest -m get -n helloWorld will avoid the manual step of endpoint creation and generate files from the previous example with predefined handlers. We strongly recommend using this way of endpoint creation. More information about endpoints generation can be found in Generation - REST section.

    Handlers

    Each newly created endpoint file must export a function that contains the business logic. Exported function takes two arguments: event and context, which contains a connection to the database and mapped request object. Each handler may release any business logic you need. You can import any library, connect to the database, execute queries... Here an example of "hello world" handler:

    By running cs generate:rest -m get -n helloWorld we will generate the following file at src/rest/get.helloWorld.ts:

    Context

    Handler function takes two arguments: event and context.

    event - is an object, which provides mapped request objects. Query params, request body, request headers can be accessed here. Below you can find an interface of event object:

    In cases, when params, body and headers are not enough to implement you can access req and res object. REST endpoints are based on Express framework and allow you to use all features of this framework. event object exposes request and response objects, which are Express objects and can be used in the handler as you wish.

    If you use response middlewares execute next() function from event object at the end of the handler execution context.

    The next POST request curl -X POST 'http://localhost:3000/rest/helloWorld?hello=world' --data '{ "test": "object" }' -H "Content-Type: application/json" will result in the following event object:

    context - is an object, which provides TypeORM connection object. In case if database is available for your service - you can access it and establish a connection with database.

    The context argument contains the database connection property which you can use with your TypeORM entities:

    As you can see, the concept is very simple but is very powerful at the same time, as it allows you to create custom REST endpoints, which could be used for integration with OAuth provides, Stripe or other payment systems which require callbacks!

    Response

    There is no need to use an Express response object to generate a server response, just return string in case if string response is required or return an object, which will be sent as JSON response, following the next interface:

    status - will set a status code of HTTP response

    data - is a custom JSON object

    The result of handler execution will be a JSON object { hello: 'world' } with 201 status code.

    As alternative Express event.resobject can be used to set a custom response.

    Middlewares

    code.store platform allows create middleware functions, which are similar to Express middlewares. To create middleware function for any route you should follow the next steps:

    • create a file with a handler function in src/rest-middlewares

    • apply middleware function in a configuration file codestore.yaml

    • specify your business logic inside handler file

    Create a handler file

    Create folder rest-middlewares inside src directory if it not exists. To create this folder just execute in root service directory following CLI command:

    Then, create a new file, which will contain code with your middleware function. For example, let's define a permissions middleware function, which will be in src/rest-middlewares/permissions.middleware.ts file with the following content:

    This is a default Express middleware, which different method signature.

    The first argument - is an object, which includes req, res objects and next function.

    req - is an Express request object which represents the HTTP request and has properties for the request query string, parameters, body, HTTP headers, and so on

    res - is an Express response object which represents the HTTP response that an Express app sends when it gets an HTTP request.

    next - is a function which invokes to pass control to the next middleware function.

    The second argument context- is an object, which provides TypeORM connection object. In case if a database is available for your service - you can access it and establish a connection it.

    Also, using cs generate:middleware command you can generate files with middleware functions. To learn more visit Generation section.

    Apply middleware function in a configuration file

    To apply middleware function just modify rest object in codestore.yaml and define which middleware function should be applied on which route.

    Below you can find an example of permissions middleware function which located in src/rest-middlewares/permissions.middleware.ts file which applied to [GET] /hello route in src/rest/get.hello.ts file:

    Middleware function can be applied before or after handler execution. code.store platform allowed request and response middleware functions.

    To execute middleware function before handler execution, just define your middleware function in requestMiddlewares object of codestore.yaml and use responseMiddleware to execute middleware function after handler execution.

    In example above permissions middleware function specified for /hello route in the requestMiddleware scope and will be execute before route handler function.

    Express
    Express

    Wrapping an NPM package with GraphQL: a chess server

    Let's have fun : create a GraphQL chess server !

    In some projects, you'll need to include some NPM packages and run them as a service. Let's take an example and create a chess server using

    We consider that you're familiar with code.store CLI, you have an account and you know how to create a new service. If not, follow our .

    Step 1: Create a new service

    Check that you're authenticated :

    If you receive following error message, that means you're not authenticated and you'll need to execute

    import { Handler } from 'codestore-utils';
    
    const handler: Handler = async (event, context) => {
      // your code goes here
      return 'Hello, world!';
    }
    
    export default handler;
    interface HandlerEvent {
      params: {
        query: {
          [key: string]: string;
        };
      };
      body: {
        [key: string]: string;
      };
      headers: {
        [key: string]: string;
      };
      req: Request;
      res: Response;
      next: NextFunction;
    }
    {
      "params": {
        "query": {
          "hello": "world"
        }
      },
      "body": {
        "test": "object"
      },
      "headers": {
        "host": "localhost:3000",
        "user-agent": "curl/7.64.1",
        "accept": "*/*",
        "content-type": "application/json",
        "content-length": "20"
      }
    }
    db: {
        connection: Connection;
    };
    context.db.connection.getRepository(...);
    interface HandlerResponse {
      status?: number;
      data: any;
    }
    import { Handler } from 'codestore-utils';
    
    const handler: Handler = async (event, context) => {
    
      return { status: 201, data: { hello: 'world' };
    }
    
    export default handler;
    mkdir src/rest-middlewares
    export default ({req, res, next}, context)=>{
      next();
    }
    db: {
        connection: Connection;
    };
    rest:
      routes:
        - path: /hello
          handler: /rest/get.hello
          method: GET
          requestMiddlewares:
            - /rest-middlewares/permissions.middleware
    
    codestore auth:login
    command.

    Let's create a new service :

    You should get something like that :

    Step 2: Chess game schema

    As we created our service, the first thing we need to do is to modify the default GraphQL schema by adding a new Type: Game. Players will interact with our API to play chess, games will be stored in our database. Inside your service, you'll need to edit the /src/schema.graphql file.

    By default, your schema looks like that :

    Let's remove the default helloWorld query and add a type where we'll store chess Game states, your schema should look like this :

    Adding a new type will generate a table and TypeOrm entity for you. What we put inside our Game type is open, I decided here to store a unique identifier of a game, a timestamp of when the game was created, a FEN representation string ( Forsyth–Edwards Notation, which is a kind of compressed representation of a chess game), an ASCII textual visualization of a board and current turn (black of white). We could do less (just an ID is ok) or more (adding the game's state, history, comments, ...)

    Let's test it immediately. Go inside your service folder and execute the following command :

    generate command validates your schema and, if necessary, generates database models, TypeOrm entities, and migrations. In our case, it will throw an error, because there are no queries anymore in our schema (we removed the default helloWorld query).

    So we need to add a query to create a valid schema. One of the simplest ones would a query to load a game from the database providing its ID as parameter and returning a Game object :

    You can notice here that there is no ! mark after the Game, which means our query may return null (in case of the wrong ID for example). Save your schema.graphql file, return to your favorite CLI, and run cs generate again. Yeehaa! You should get something like that :

    As we started to work with stored objects, we need to setup a local database. You can just install postgre, if you don't know check our quick tutorial.

    So now we have a schema with one query: load and one type: Game. We've setup a local database. We can try to run our chess service locally. You need to go to the root directory of your service and execute cs dev command:

    Oops! We've removed helloWorld query from our schema and replaced it with load query, but we forgot resolvers. Basically, for each query (mutation or query) there is one TypeScript file in /src/resolvers/queries folder. By default, when you create a new service, we create a helloWorld query resolver, so you'll find helloWorld.ts file there. Our loader will try to match available resolvers to the ones in the schema, and that's why we got the previous error.

    Let's simply rename helloWorld.ts to load.ts

    Step 3: Include an NPM package

    So now we need to add chess.js NPM package to our service, execute the following command in the root directory of your service:

    To control that everything is ok, check the package.json file, it should look like that:

    Step 4: Create a game and store it in a database with a mutation

    So it's time to write our first mutation and use chess.js at the same time! First, let's edit the schema.graphql file in /src folder. As you remember we've added a Game type and a query load. Now time to add a mutation. Mutations are specific kind of queries that can modify the service's database state:

    We need now create a mutation TypeScript file named createGame.ts in /src/resolvers/mutations

    Let's analyze what's inside. First, we need to include chess.js package, the one we installed trough npm install command:

    Then, we also need to import the Game TypeOrm entity, so we can access the storage object:

    Then, we simply create a chess object and a new Game entity and fill Game's entity fields. Then we create a TypeOrm repository connection, save the Game object, and return it.

    When a TypeOrm object has an ID field, it will be automatically created and filled in the returned object.

    Let's test our service locally, by running from the service root folder cs dev command. You should see something like that :

    You can play with your service by loading in your browser the API endpoint : http://localhost:3000/graphql

    chess.js
    quick start guide
    cs whoami
    Seems that you're not logged in. Please execute  codestore login  command to sign-in again.
    cs service:create
    
     What is your service name?
     It should be the shortest meaningful name possible, for example:
            Meeting-rooms booking
     Service name: Chess Server
    
     Describe what functional problem are you solving with your service?
     It's optional and here is an example:
            My service manages meeting rooms and their booking by users
     What problem are you solving?: Let consumers play chess using GraphQL
    
     Describe how you solve it? It's optional too and should look something like:
            This service provides an API to create, update and delete rooms and
            another set of queries to manage bookings, cancellations, and search for available rooms.
     How you solve it?: Wrapping chess.js into a GraphQL endpoint
    
     What is the most relevant business domain of your service?
     Use up/down arrows to navigate and hit ENTER to select.
     Please select 'Other' as last option
     Business domain: Content_Management
    
     Now, the last thing, enter free-hashtags describing your service.
     Up to 5, comma-separated, no need to add #.
     Example:
            hospitality, booking, meeting-rooms, office
     Hashtags: games,chess,play,fun
    ✔ Created service with ID: chess-server
    ✔ Private and demo environment containers were built
    ✔ Deployed to private and demo environments
    ✔ Downloading service template 
    Your service on private environment is available by this url: https://api.code.store/121066bcd3ae4a049a326c99639e26bc/graphql
    Your service on demo environment is available by this url: https://api.code.store/858f86742a234d0b91be456a59089adb/graphql
    # This file was generated by code.store CLI and it should not be deleted.
    #
    # Visit our documentation to learn more about GraphQL https://docs.code.store/getting-started/graphql-schemas as well as about working with code.store https://docs.code.store/getting-started/quick-start/quick-start-with-cli
    #
    # In case of questions, you can send us a message at our community chat https://spectrum.chat/code-store
    #
    type Query {
        helloWorld: String!
    }
    type Game {
        id: ID!                                     #Game's unique identifier
        createdAt: String!                          #Game's creation date
        fen: String                                 #Game's FEN representation 
        ascii: String                               #ASCII art representation of the board
        turn: String!                               #Current turn of the game, may be B or W
    }
    cs generate
    cs generate
    ✔ Compiling your code
    ✖ Query root type must be provided.
    ◼ Preparing the service code for upload
    ◼ Reverting extra migrations
    ◼ Uploading service to the generator
    ◼ Saving generated code 
    
     ›   Error: Error: Query root type must be provided.
    type Game {
        id: ID!             #Game's unique identifier
        createdAt: String!  #Game's creation date
        fen: String         #Game's FEN representation 
        ascii: String       #ASCII art representation of the board
        turn: String!       #Current turn of the game, may be B or W
    }
    
    type Query {
        load(gameId: ID!): Game
    }
    cs generate
    ✔ Compiling your code
    ✔ Validating schema
    ✔ Preparing the service code for upload
    ↓ Migrations were not reverted: role "username" does not exist [SKIPPED]
    ✔ Uploading service to the generator
    ✔ Generated code has been saved 
    
    cs dev
    2020-09-11T10:02:54.416Z [NPM] Installing dependencies
    2020-09-11T10:02:58.832Z [TypeScript] Compiling typescript code
    2020-09-11T10:03:08.122Z [GraphQL] Validating schema
    2020-09-11T10:03:08.146Z [GraphQL] Validating queries and mutations
     ›   Error: Error: helloWorld queries are not defined in schema
    mv helloWorld.ts load.ts
    npm install chess.js
    {
      "name": "chess-server",
      "version": "1.0.0",
      "author": "code.store",
      "scripts": {},
      "dependencies": {
        "chess.js": "^0.11.0",
        "codestore-utils": "^1.3.4",
        "pg": "^8.2.1",
        "typeorm": "^0.2.24"
      }
    }
    type Game {
        id: ID!                     #Game's unique identifier
        createdAt: String!          #Game's creation date
        fen: String                 #Game's FEN representation 
        ascii: String               #ASCII art representation of the board
        turn: String!               #Current turn of the game, may be B or W
    }
    
    type Query {
        load(gameId: ID!): Game     #Loads an existing game by it's ID and returns a Game object
    }
    
    type Mutation {
        createGame: Game!           #Creates a new game and returns a Game object
    }
    import { logger, Resolver } from 'codestore-utils';
    import Chess from 'chess.js'
    import Game from '../../data/entities/Game';
    
    const resolver: Resolver = async (parent, args, context, info) => {
      logger.log('This is a createGame mutation!', 'createGame');
      const chess = new Chess.Chess()
      let game = new Game()
     
      game.createdAt = Date.now().toString()
      game.ascii = chess.ascii()
      game.fen = chess.fen()
      game.turn = chess.turn()
      
      const repository = context.db.connection.getRepository(Game)
      await repository.save(game);   
      
      return game
    }
    
    export default resolver;
    import Chess from 'chess.js'
    import Game from '../../data/entities/Game';
    cs dev
    2020-09-18T12:44:19.286Z [NPM] Installing dependencies
    2020-09-18T12:44:23.395Z [TypeScript] Compiling typescript code
    2020-09-18T12:44:23.398Z /Users/maximetopolov/CLI-Demo/chess-server/src/rest is not available
    2020-09-18T12:44:32.886Z [GraphQL] Validating schema
    2020-09-18T12:44:32.914Z [GraphQL] Validating queries and mutations
    2020-09-18T12:44:36.159Z [INFO] Starting development server
    2020-09-18T12:44:36.159Z [Bootstrap] Start bootstrapping the application
    2020-09-18T12:44:36.160Z [Database] Connecting to database
    2020-09-18T12:44:36.309Z [Database] Successfully connected
    2020-09-18T12:44:36.454Z [Database] Migrations ran
    2020-09-18T12:44:36.456Z [GqlLoader] Loaded queries: load
    2020-09-18T12:44:36.456Z [GqlLoader] Loaded mutations: createGame
    2020-09-18T12:44:36.472Z [RestLoader] Loading rest handlers
    2020-09-18T12:44:36.472Z [RestLoader] No REST handlers available
    2020-09-18T12:44:36.478Z [Bootstrap] Graphql is available on: http://localhost:3000/graphql

    Services

    Overview

    Services - is the main entity that you operate on when working with the code.store platform. These are backends that you, members of your organization, or public users of the code.store platform creates.

    One of the key features of our platform is the reuse of services. Since the service doesn't belong to any specific project, you can reuse the services that are available to you.

    For convenience, the code.store platform provides the ability to develop your services in various languages:

    • TypeScript

    Currently, we are actively working on adding support for different languages and frameworks, such as: Go, PHP, Python, Java, C#... so soon you will be able to see support for your particular technology.

    Using the CLI or web interface - you can create/edit/update/add to projects/delete your services. Below are examples of how this can be done.

    When service is created - the platform automatically deploys it to private and demo environments. For more information about environments, see the section.

    private environment - created exclusively for you, with the purpose of developing and testing your service, when the demo - is a public environment, in the context of your organization (or marketplace, if you wish to publish your service in mass and make some money on it)

    New Service Creation

    In order to create a new service, you must have an account on the platform

    Web interface

    You can create a new service using the web interface by going to by clicking on the “create service” button located at the bottom of the screen. Fill out the service creation form and click on the CREATE button. After that, the service will be available on the general list on the services page.

    It takes some time for the service to be available, in general, the creation process takes less than a few minutes, during which we create a working instance of your future service, collecting an image for you, and deploying it in one of the k8s clusters. We are actively working on the platform and in the future, the process of creating service will take no more than 10 seconds.

    CLI

    In general, creating a service through the web interface or through the CLI is no different, except for the visual design. Perhaps, as a developer, the way of creating a service using the CLI will be more comfortable for you, since at the stage of creation you will receive more information about what is happening “under the hood”

    In order to create a new service, you need to have a pre-installed CLI and be authorized on the platform (see guide)

    First, go to the directory where the folder with the initialization template for your service will be created, for example, let it be your home directory.

    Then, just execute the :

    Using the cs service: create command, we initiate the process of creating a service, during which it will be necessary to answer the following questions:

    • ? Service name:

    • ? What problem are you solving?:

    • How do you solve it?:

    • Choose business domain using arrow keys

    After that, you will see the progress of creating a new service, during which we copy the starting project template, build the image, and deploy it to our k8s cluster.

    We are actively working on the platform and in the future, the process of service creation will take only a few seconds.

    After successfully creating the service, you will receive a message with links and secrets. Here an example of the output:

    You can check its performance by following the links that you received when creating the service. These links lead to the GraphQL playground, which is available by default for every new service.

    Please note that your service was deployed on two private and demo environments at once. For more information about environments, see the section.

    You also receive a developer key for your private environment. This key must be used each time when you call your service in a private environment, just by adding HEADER “x-user-authorization”. In order to restrict access to a service that is under active development, you should use an authorization. The built-in mechanism for accessing and authorizing your services can be found in the section.

    After creating the service - the code is available at the same dir, where you execute cs service:create command, in a new folder, which has the name of your service, that you specified while creating.

    File Structure

    The root directory contains two files and one folder:

    • codestore.yaml – the file that contains the configurations of your service, you can learn more about the settings on the service page

    • package.json – it is a standard NPM configuration file. Feel free and add any NPM packages you like using npm install {packageName};

    • src/

    Let's dive into the src/ directory:

    • schema.graphql – contains a schema of your service;

    • data/ – folder that contains entities, which required to work with the database.

    • data/entities – this directory contains TypeORM entities. You can automatically generate TypeScript classes for your database tables using

    Most of the things for working with the database, such as migrations, Typeorm entities, can be generated using the generator built into the CLI. The principles of models and migrations generation can be found in the section.

    Local development

    To simplify the local launch of the service - available simple command: cs dev. After executing, on the backstage will be installed all dependencies (npm i), compiled typescript code (tsc), validating GraphQL schema, queries, and mutations, and applied functions.

    Note, if the service uses a database, you need to provide the credentials (login, password, database, port, host) for the database object in the file. Here an example of the local configuration of codestore.yaml:

    Running this command will install all the necessary dependencies with package.json, compile the code (for this we use tsc), validated GraphQL schema.

    After successful execution of the command, the service will be available at the link: http://localhost:3000/grpahql Please, make sure that 3000 port is free, before launching command.

    Below is as an example of successful execution cs dev command

    Service update

    Create a new version

    Each service from time to time has to roll our new updates. After changes have been made to your service code - we can roll updates to the . To publish a new version you have to use cs push command.

    If you roll new updates and don't update your version at your packgaje.json, we will automatically increment the path version (x.y.Z). We recommend follow standard and update your service version each time when you push updates.

    Displayed service version will take from package.json file.

    Following our concept, by default, the service will be updated on the private environment.

    Pushing updates

    Using the cs push command - you publish your changes. When executing this command, you will specify release notes, which will serve as information about what exactly changes have been made. Below is as an example of successful execution cs push command:

    As you can see, on backstage we compiling your code using tsc, and validating the schema, so you can be sure - changes you made are valid. If something went wrong - you will see an error message and pushing will be interrupted.

    In general, working with the cs push command can be thought of as a git command with validation and pre-compilation of your code. In the future, we will provide access to your code through the GIT repository, but at the moment, you need to take care of this by yourself.

    Promote new version to Demo environment

    After pushing changes to Private , in order to further distribute a new version of the service to projects, it becomes necessary to publish the changes. To publish changes just execute cs promote command.

    Service promotion from private to demo environment will create a new service version. To learn about environments and versioning concepts follow and sections.

    Validation and compilation

    Each time when you push your code using cs push command - we compile and validate your code. If you develop your services using local development using cs dev command - you can be sure that everything will be OK.

    Each push of your updates trigger compilation based on tsc (TypeScript compiler) and GraphQL schema validation. If something went wrong - you will receive an error message.

    Interfaces

    The code.store framework provides the ability to create both REST and GraphQL interfaces.

    REST

    REST interfaces - is a simple file-system-based routing of REST API endpoints based on framework. How to create REST endpoints, handlers, middlewares described in section.

    GraphQL

    is an API standard that provides a more efficient, powerful, and flexible alternative to REST. We understand it like no one else and provides an opportunity for full-cycle data management of your GraphQL API. With code.store platform you able to:

    • be sure, that you schema and code always valid

    • generate database models ( entities) based on your GraphQL schema

    • generate migrations to your PostgreSQL database

    • generate handlers to your queries and mutations

    How to use GraphQL described in section. How to generate models, migrations, resolvers... described in section.

    Service info

    To display information about your service just execute cs service:info command inside service dir.

    Command execution result will be displayed with information about deployed on the demo and private environment service version, deployed date, developer key's and service URL's.

    Specify hashtags

    – this is where all the source code lives.
    cs generate:models -p src/data
    command;
  • data/migrations – this directory contains SQL migrations for your service;

  • resolvers/ – this is where your business logic lives.

  • resolvers/query andresolvers/mutation – resolvers and mutations serve two purposes: connect your GraphQL objects to data in the database and is a place where you implement any additional business logic.

  • Environments
    code.store
    https://app.code.store/services
    code.store
    Getting started
    service creation command
    Environments
    Access and Authorization
    configuration
    GraphQL
    Generation
    middleware
    codestore.yaml
    private environment
    SemVer
    environment
    environment
    Environments
    Versioning
    Express
    REST
    GraphQL
    TypeORM
    Services - GraphQL
    Generation
    cd ~
    cs service:create 
    Use developer key for private environment: d72e1217-28e8-44bf-9a31-9b220f2e29fc
    Your service on private environment is available by this url: https://api.code.store/50de255b0812453e9ae3cec6ee7e8b83/graphql
    Your service on demo environment is available by this url: https://api.code.store/ffc8b48e5c1d45e2b48d5c7b91ca6748/graphql
    
    YOUR_SERVICE_NAME
    ├── codestore.yaml
    ├── package.json
    └── src
        ├── data
        │   ├── entities
        │   └── migrations
        ├── resolvers
        │   ├── mutations
        │   ├── queries
        │   │   └── helloWorld.ts
        │   └── resolvers.ts
        └── schema.graphql
    # ./codestore.yaml
    
    localConfiguration:
     database:
       port: 5432
       database: my-local-database
       password: password
       username: postgres
       host: localhost
    2020-11-02T20:27:34.930Z [NPM] Installing dependencies 
    2020-11-02T20:28:00.848Z [TypeScript] Compiling typescript code 
    2020-11-02T20:28:04.570Z [GraphQL] Validating schema 
    2020-11-02T20:28:04.589Z [GraphQL] Validating queries and mutations 
    2020-11-02T20:28:05.856Z [INFO] Starting development server 
    2020-11-02T20:28:05.856Z [Bootstrap] Start bootstrapping the application 
    2020-11-02T20:28:05.864Z [Database] Connecting to database 
    2020-11-02T20:28:05.983Z [Database] Successfully connected 
    2020-11-02T20:28:05.985Z [GqlLoader] Loaded queries: helloWorld 
    2020-11-02T20:28:05.997Z [RestLoader] Loaded REST handlers: 
    2020-11-02T20:28:05.999Z [Bootstrap] GraphQL is available on: http://localhost:3000/graphql 
     Please enter release notes (semicolon separated)
     Notes: note
    
    ✔ Compiling your code
    ✔ Validating schema
    ✔ Preparing the service code for upload
    Service: demo_app	demo
    
                  Private                                                         Demo                                                            
    version       0.0.1                                                           0.0.1                                                           
    deployed      11/12/2020, 10:18:57 AM                                         11/12/2020, 10:18:57 AM                                         
    developer key cff7f0fb-8856-48e7-817b-0d83c696b247                                                                                            
    url           https://api.code.store/a147ac464fd94f4ea9f430e9f28ba933/graphql https://api.code.store/2f8f2cf0d1e046e1b27dc2d14a357f13/graphql 
    

    Commands

    Did you ever play Command & Conquer? No? Continue, comrade... and you will find yourself on the floor, with Kukov! ☭

    To download and install CLI, follow the instructions here.

    You can invoke code.store CLI either by using the full codestore command, or by using the short version cs.

    Synopsis

    To get a list of all commands, call cs help:

    Basic usage

    Most of the commands accept some specific arguments which can be provided while invoking the command in a long or short format:

    • Long format: cs command --argumentName argumentValue

    • Short format:

    Authentication

    To be able to use the CLI you have to login into your code.store account. To do that use the following command:

    cs login will try to authenticate through the browser (it is going to open the default browser in your system).

    At any time you can check under which user you are being authenticated:

    In order to finish your session and logout use the following command:

    You can also use short aliases of the above commands: cs login, cs whoami and cs logout.

    Services

    List

    The cs service:list command that can be shortened to cs service:ls, and is used to provide a list of your along with their status.

    Create

    Create a new service by calling cs service:create which will display a wizard and ask for some necessary information in order to create a service.

    Info

    Displays more detailed information about the service:

    Delete

    Deletes the service. Deletes it for real, so please make sure that you are sure about what you are doing.

    Dev

    Launches a service locally. Requires PostgreSQL and configuration in codestore.yaml.

    Generate

    This command has been moved to cs generate:models

    List

    List the services in your organization. You can also use a short version of this command: cs service:ls.

    Note: don't be surprised to see some services when you just created an account as those may be the services created by the colleagues in your organization.

    Logs

    Print out the logs of your service. Available options are:

    Promote

    Pushes your service from Private to Demo environment.

    When launched without the optional Service ID argument, the command will look for codestore.yaml file and will promote the current service.

    Pull

    Downloads a service to the current directory.

    hen launched without the optional Service ID argument, the command will look for codestore.yaml file and will promote the current service.

    Push

    Push local changes to Private environment.

    Projects

    In order for your to be published, they have to be added to . Projects can be created and managed either by using the web-site or via CLI.

    Create

    Launches a project creation dialogue:

    Delete

    Deletes the project but only if there are no existing services inside it. Make sure that you remove all services from the project before removing the project itself.

    List

    Get a list of all your projects (you can also use a shorthand alias cs project:ls:

    Services inside the Project

    In order to manage services inside your project, you can use cs project:service sub-commands. Most of the commands are quite similar to those of cs service.

    Add

    Adds an existing service to a project. Requires a Project ID as an argument.

    List

    Lists services in your project:

    Info

    Displays detailed information about project's service, in a similar way to cs service:info.

    Promote

    Promotes your service inside the project between Development, Staging and Production environments.

    Remove

    Removes the service from the project.

    This is a destructive operation that might result in the loss of data! Please make sure that you definitely want to remove the service from the project.

    Generate

    This group of commands generate scaffolding (templates) of some important files.

    Handler

    Generates auth and context handlers.

    Read more about the usage of those handlers in our .

    Models

    Generates the entity models and database migrations for your GraphQL types and puts them into src/entities.

    Entity and database generation functionalities are still in alpha version. We are iterating fast to bring the best features as soon as possible. We would be happy to hear from you about what do you think about it in our community chat here:

    Resolver

    Generate a template of a GraphQL resolver:

    REST

    Generates a template of a REST API endpoint handler:

    Basic authentication

    How to build a GraphQL API with authentication

    This guide covers writing custom middleware for authentication purposes.

    Overview

    You can tell code.store to pass every request (query or mutation) marked with @auth directive via your custom middleware. In a nutshell, it looks like the following. Imagine, that you have two queries:

    Here is what happens on each request to one of those queries:

    All queries/mutation marked by @auth will pass via auth.handler.ts first

    What happens is that all requests marked by @auth directive will pass via auth.handler.ts first and the context argument passed to the subsequent resolver is going to be concatenated with the return result of auth.handler:

    That's not very complicated so let's build a simple example using this information!

    Very simple example

    For the sake of simplicity, we are going to use the code from our but essentially any other working service (including the newly created one) will suffice.

    Let's take a look at our schema first:

    As you may see, we have restored the helloWorld query, we also have restored the src/resolvers/queries/helloWorld.ts file too.

    Let's modify our schema by adding the directive declaration and by marking one of the requests as @auth:

    There are two things that happened here:

    1. We added a declaration of the directive to the top of our schema.

    2. We marked two of our requests (query allPosts and mutation createPost) with @auth directive, which means that we will be able to create and see the posts only as authenticated users. Neat!

    At the moment, this @auth directive won't do anything, so let's add middleware and implement a very basic authentication model.

    First, generate the handler file by running the following command in your service directory:

    This is what you will see inside the file (I removed the comments to save screen-space):

    The typical authentication flow is like the following:

    • the client (your front-end or another service) will send a GraphQL request by passing some sort of authorization token in a specific header (typically it would be 'Authorization' header);

    • your middleware will parse the token and validate it (against another service, or by interrogating the database with active sessions, etc);

    • in the case when the token is not valid, your middleware will throw an error;

    Say no more, let's implement a very basic authorization, that is going to check the Authorization header and will compare it with two pre-defined tokens:

    This is a very basic and insecure example of the authentication which is serving the demonstration purposes only and should not be used on production!

    I hope that it is really straightforward what we do in the above code: we react on two predefined tokens (it's really hard to call them tokens, to be honest 😬), based on which we will assign the permissions or in case if it's missing, we'll throw an error.

    Next, we should somehow react to these permissions in our resolvers. Let's see how exactly we might do that:

    This is what has changed comparing to the code from our , we added a small if condition that checks the permissions in the request context argument:

    Let's do the same for createPost.ts resolver:

    That's it! We can now test how our changes impact the behaviour of the service.

    Testing

    Let's test this baby! First of all, quick go-through to see what we are actually expecting:

    1. query helloWorld should work as before, without any Authorization header (or with it);

    2. query allPosts should return an error if the header is not specified;

    3. query createPost should return an error if the header is not specified, or if the write permission does not equal true.

    Let's test all these three scenarios.

    1. query helloWorld should work as before

    OK, so that worked as expected. Moving next.

    For the sake of better readability, I will be formatting the JSON output of my curl commands with jq '.' command. That's why the way how JSON output looks like in the examples below may be different from what you see on your screen.

    2. query allPosts

    You shall not pass indeed! Let's try to add the correct token header to our request:

    This time it worked as expected. Let's move on to the final part.

    3. mutation createPost

    Let's try without the token first (or with the user_token, the result should be the same:

    Bang! 💣Let's add the correct token now:

    This time, it's a success.

    Conclusion

    In this short tutorial, we wanted to show you how to put in place a basic authorization system in your service. The idea was to show the capabilities of our SDK on a simple example, but the same approach could be applied to authorization with external systems like AWS Cognito or Auth0, as well as with the dedicated service on code.store.

    Quick Start with CLI

    🖥🤔⌨️👏🚀

    This guide will introduce some basic code.store concepts like services and schema generation using CLI. The goal of this quick start is to get you up and running fast, so let's not waste any time and start!

    Create code.store account

    If you haven't done this already, then .

    # This directive has to be added to the top of your GraphQL schema
    directive @auth on FIELD_DEFINITION
    
    type Query {
        allPosts: [Post]
        helloWorld: String! @auth
    }
    cs command -a argumentValue

    Use cs help command to know more about the specific command and its arguments.

    services
    Services
    Projects
    dedicated tutorial here
    https://spectrum.chat/code-store
    Install the code.store CLI

    We invite you to follow this guide and install our command-line interface:

    Authenticate and create service

    Once you have your account and the CLI is installed, we can finally do some interesting stuff!

    In order to work with the CLI, you have to connect it with your account by launching the following command:

    This command is going to launch your default browser and ask for your login details. Once you are authenticated, we can go on and create a new service.

    The anatomy of a service

    You can check the contents of your new service directory by running ls -lh ./

    Let's get into the details of each file and directory.

    The root directory contains two files and one folder:

    • package.json – it is a standard NPM configuration file. Feel free and add any NPM packages you like using npm install {packageName};

    • codestore.yaml – contains your service ID and will contain more configuration options in later versions;

    • src/ – this is where all the source code lives.

    Let's dive into the src/ directory:

    • schema.graphql – one of the most (if not the most) important files. It contains a GraphQL schema of your service;

    • data/ – this directory contains TypeORM entities. You can automatically generate TypeScript classes for your database tables using cs generate:models -p src/data command;

    • resolvers/ – this is where your business logic lives. Resolvers serve two purposes: connect your GraphQL objects to data in the database and is a place where you implement any additional business logic.

    Basic API schema and resolver

    When you create a new service, we are generating it with default schema.graphql which contains the following code:

    It is a very basic schema of an API that has a single Query called helloWorld (which doesn't accept arguments) and which returns a single output of type string.

    If you are not comfortable with GraphQL syntax, we are inviting you to read our GraphQL quick-start guide first and if you want to go deeper into that rabbit-hole 🐰then the official GraphQL documentation https://graphql.org/learn/.

    We can test this query by running the following curl command in your terminal:

    Hopefully, we should get "Hello, World!" response (something looking like that {"data":{"helloWorld":"Hello, World!"}}) in our terminal 🤞

    Let's take a look at the resolver (business logic) for this query which is located in the file src/resolvers/queries/helloWorld.ts:

    This is a basic code which does few things:

    • we are importing a logger module which is going to output messages to the local console or to our cloud log storage;

    • we are importing a Resolver, which is an Interface for a function type; it is not a necessary step but it is a useful one if you want to see type hints in your IDE;

    • if your code editor cannot find 'codestore-utils' then simply run npm install in the service directory root.

    When starting the service, code.store loads all files from src/resolvers/mutations and src/resolvers/queries directories and passes them to the GraphQL server. The filename of the resolver must be equal to the name of a query or a mutation. Each query and mutation in theschema.graphql file must have a corresponding resolver in the filesystem.

    This should give you a basic understanding of how GraphQL schema and resolvers work together and let's write something more meaningful in the next chapter.

    Local development

    The local development workflow is still in early beta and we are working hard to bring you the most stable and comfortable local development experience. If you notice any issues, please ping us in our community.

    Local development comes in handy if you don't want to launch codestore push after each modification and then wait until it finishes.

    In order to use local development workflow:

    • install PostgreSQL database locally; you can do it quite easily either https://postgresapp.com/ or via Docker;

    • configure your local settings in codestore.yaml:

    • launch a local development server by running codestore dev

    • codestore dev will try to run "npm install" to make sure that the dependencies of your service are installed but you can also launch it manually if you wish.

    After launching codestore dev you should see the following output:

    Voila ! Let's try and test our local server:

    You should get a "Hello, World!" message if everything works properly 🤞

    We are using lots of curl commands to query the web-services in this Quick Start, however, you can also GraphQL Playground by clicking on the link of the service, i.e. http://localhost:3000/graphql for the local environment, or https://api.code.store/{service URL hash}/graphql for remote environments.

    Blog-post example

    We can finally write something more or less meaningful! For the sake of simplicity, we decided to implement a well-beaten example of a Blog-post. We are going to be using the local development server during this example, so make sure that you have a PostgreSQL database ready.

    First of all, we should modify our schema.graphql file:

    Every GraphQL schema has a query type and may or may not have a mutation type. Read more about GraphQL in our quick start guide here, or in the official GraphQL documentation.

    We have added two types and two queries in the schema and we can now go on and add the resolvers. Let's begin with the query allPosts: create a file src/resolvers/queries/allPosts.ts and initialize it with the following code:

    Each GraphQL query or mutation must be mapped to a resolver. In order to find a resolver for a query/mutation, code.store is using a file structure mapping to find a corresponding resolver.

    The rules are simple:

    • all queries should be placed into src/resolvers/queries/{queryName}.ts files,

    • all mutations into src/resolvers/mutations/{mutationName}.ts

    For example, resolver for a mutation createUser should be placed into src/resolvers/mutations/createUser.ts file.

    Here we go, this is our first test resolver which is not yet connected to anything but which already can return the data! One last step before running the deployment command - we have to remove src/resolvers/queries/helloWorld.ts or simply rename it to helloWorld.ts_. And that's it, you can now run your application locally via codestore dev and test it via CURL:

    GraphQL queries and mutations in your schema.graphql should match 1-to-1 the queries and migrations in the file system, i.e. if you have a query "test" in a schema and you don't have in the file system, the service will throw an error. The same in the opposite order, if you have a resolver in the file system but not in the schema.

    Until now we were not using any database at all and the time has come to grab a beer create one. The cool thing is that code.store can generate the database automatically based on the GraphQL schema you provided! In order to generate the entities locally, we should run codestore generate:models -p src/data command which will generate the entities based on your schema. As soon as it finishes the generation, let's modify our resolver and add some database queries:

    For every type in your GraphQL schema, code.store performs two operations:

    • it generates database migrations (using TypeORM)

    • it generates TypeORM entities which it stores in src/data/entities/{TypeName}.ts

    Few things have changed here:

    • we are importing TypeORM Repository and our generated Post entity

    • we are initializing the repository and performing a find query for our Post entity

    As soon as we run the application with codestore dev , we can test it again and see that it's returning an empty array as we haven't created anything yet 🤦🏽‍♀️.

    Time to add the first mutation.

    First of all, modify your schema.graphql to look like the following:

    This is what has changed, we added a type Mutation to our GraphQL schema containing a mutation createPost. Now we can implement our resolver:

    Now launch codestore dev again and run some queries (we are going to be using a http command which is similar to cURL but provides a better output):

    Finalizing

    So now we have a working service on our local machine and it would be great to have it deployed somewhere in the cloud. Let's do exactly that and deploy the service to the private environment by running codestore push command. As soon as finished, you can launch the queries in your private environment!

    Conclusion

    Not sure if it was quick 😉 but we hope that after this guide you have a good understanding of how code.store works. Feel free to check the rest of the documentation and contact us in the community chat if you will have any questions!

    Happy coding and may the force be with you! 🦾

    click on this link
    Getting started
    cs help
    $ cs help auth
    Authentication commands, login, logout, whoami
    
    USAGE
      $ codestore auth:COMMAND
    
    COMMANDS
      auth:login   Authenticate at code.store platform
      auth:logout  Clears user credentials and invalidates local session
      auth:whoami  Display the currently logged in user
    cs auth:login
    cs auth:whoami
    cs auth:logout
    $ cs service help
    Manage your services
    
    USAGE
      $ codestore service:COMMAND
    
    COMMANDS
      service:create    Create new service
      service:dev       Launch your service locally
      service:info      Displays detailed information about a service
      service:list      List services in your organization
      service:logs      Print the logs for your services
      service:promote   Promotes service from private env to demo
      service:pull      Download an existing service
      service:push      Push local changes to Private environment
      service:remove    Remove a service
    $ cs service:list # or cs service:ls
    Service ID         Name                Status
    amazing-service-1  Amazing service #1  ACTIVE
    amazing-service-2  Amazing service #2  ACTIVE
    $ cs service:create
    $ cs service:info
             Private                     Demo
    version  0.0.3                       0.0.2
    deployed 8/31/2020, 10:01:44 PM      8/31/2020, 2:48:30 PM
    url      ...                         ...
    $ cs service:delete
    $ cs service:dev # or cs dev
    $ cs service:list
    $ cs service:logs --help
    Print the logs for your services
    
    USAGE
      $ codestore service:logs
    
    OPTIONS
      -e, --env=(private|demo|development|staging|production)  [default: development] Project environment.
      -f, --follow                                             Specify if the logs should be streamed.
      -n, --num=num                                            [default: 20] Number of most recent log lines to display.
      -p, --projectId=projectId                                Project ID
      -s, --serviceId=serviceId                                Service ID
    
    ALIASES
      $ codestore logs
    $ cs service:promote [ID] --help
    Promotes service from private env to demo
    
    USAGE
      $ codestore service:promote [SERVICEID]
    
    ARGUMENTS
      SERVICEID  An (optional) Service ID
    $ cs service:pull --help
    Download an existing service
    
    USAGE
      $ codestore service:pull [SERVICEID]
    
    ARGUMENTS
      SERVICEID  An (optional) Service ID
    
    ALIASES
      $ codestore pull
    $ cs service:push --help
    Push local changes to Private environment
    
    USAGE
      $ codestore service:push
    
    ALIASES
      $ codestore push
    $ cs project --help
    🚧 A project is a particular app or website, where you can (re)use your existing services. It might be your e-commerce project or a logistics mobile application or business web-app. Each time you add a service to a project, we create a separate, isolated instance of your service. Each service reused in a project has its own environments, databases, logs, and billing
    
    USAGE
      $ codestore project:COMMAND
    
    COMMANDS
      project:create   Creates a new project, where you can add services
      project:delete   Removes project (only if there are no more services inside)
      project:list     List projects in your organization
      project:service  Adds and existing service to your project
    $ cs project:create
    ? What is your project's name? Test project
    ? Please add a short description of your project (255 chars max): Project description
    ? Is everything ok, can I create this project? Yes
    ⠹ Creating Project Test project
    $ cs service:delete --help
    Removes the project (only if there are no more services inside)
    
    USAGE
      $ codestore project:delete [PROJECTID]
    
    ARGUMENTS
      PROJECTID  ID of the Project that should be removed
    cs project:list
    $ cs project:service --help
    Manage services inside your project
    
    USAGE 
      $ codestore project:service:COMMAND
      
    COMMANDS 
      project:service:add Adds and existing service to your project
      project:service:info Displays detailed information about project's service
      project:service:list Lists services in your project
      project:service:promote Promotes service inside the project between Development, Stating and Production environments
      project:service:remove Exclude service from project. This is a potentially destructive operation that might result in a loss of data.
    $ cs project:service:add --help
    Adds and existing service to your project
    
    USAGE
      $ codestore project:service:add [SERVICEID]
    
    ARGUMENTS
      SERVICEID  Id of the service
    
    OPTIONS
      --project-id=project-id  (required) Id of the project
    $ cs project:service:list --help
    Lists services in your project
    
    USAGE
      $ codestore project:service:list PROJECTID
    
    ARGUMENTS
      PROJECTID  (required) Project ID
    
    ALIASES
      $ codestore project:service:ls
    cs project:service:info {PROJECT} {SERVICE}
    $ cs project:service:promote --help
    Promotes service inside the project between Development, Stating and Production environments
    
    USAGE
      $ codestore project:service:promote [SERVICEID]
    
    ARGUMENTS
      SERVICEID  ID of the service
    
    OPTIONS
      --project-id=project-id  (required) ID of the project
    $ cs project:service:remove --help
    Exclude service from project. This is a potentially destructive operation that might result in a loss of data.
    
    USAGE
      $ codestore project:service:remove [SERVICEID]
    
    ARGUMENTS
      SERVICEID  ID of the service
    
    OPTIONS
      --project-id=project-id  (required) ID of the project
    $ cs generate
    Generates scaffolding (templates) of some important files
    
    USAGE
      $ codestore generate:COMMAND
    
    COMMANDS
      generate:handler   Generates auth.handler or context.handler
      generate:models    Generates database entities and migrations
      generate:resolver  Generates a GraphQL resolver
      generate:rest      Generates a REST API handler
    $ cs generate:handler --help
    Generates auth.handler or context.handler
    
    USAGE
      $ codestore generate:handler
    
    OPTIONS
      -f, --force                     Force overwrite file if it already exists
      -t, --handlerType=context|auth  Handler type, can be one of: context, auth.
    $ cs generate:models
    $ cs generate:resolver --help                                                                                              12.18.3
    Generates a GraphQL resolver
    
    USAGE
      $ codestore generate:resolver
    
    OPTIONS
      -f, --force                        Force overwrite file if it already exists
      -n, --name=name                    Resolver name
      -t, --resolverType=query|mutation  Resolver type, one of: 'query' or 'mutation'
    $ cs generate:rest --help                                                                                            3s   12.18.3
    Generates a REST API handler
    
    USAGE
      $ codestore generate:rest
    
    OPTIONS
      -f, --force                       Force overwrite file if it already exists
      -m, --method=get|post|put|delete  HTTP method, one of: get, post, put, delete
      -n, --name=name                   REST endpoint name
    codestore login
    codestore service:create
    # Example of the directory structure of a Service
    ./
    ├── codestore.yaml # main configuration file
    ├── package.json # standard NPM configuration file
    └── src
        ├── data # TypeORM entities
        │   ├── entities
        │   └── migrations
        ├── resolvers # GraphQL resolvers 
        │   ├── mutations # mutations as used to create new objects  
        │   ├── queries # queries are used to retrieve objects
        │   │   └── helloWorld.ts
        │   └── resolvers.ts
        └── schema.graphql # GraphQL definition of your service's API
    type Query {
        helloWorld: String!
    }
    curl \
      -X POST \
      -H "Content-Type: application/json" \
      --data '{ "query": "{ helloWorld }" }' \
      https://api.code.store/{service_url_hash}/graphql
    // src/resolvers/queries/helloWorld.ts
    
    import { logger, Resolver } from 'codestore-utils';
    
    const resolver: Resolver = async (parent, args, context, info) => {
      logger.log('This is a helloWorld resolver!', 'helloWorld');
      return 'Hello, World!';
    }
    
    export default resolver;
    # ./codestore.yaml
    
    localConfiguration:
     database:
       port: 5432
       database: my-local-database
       password: my-secure-password
       username: my-db-username
       host: localhost
     application:
       port: 3000
    $ codestore dev
    ✔ Installing dependencies
    ✔ Compiling code
    2020-08-10T16:12:18.250Z Starting development server
    2020-08-10T16:12:18.251Z [bootstrap] Start bootstrapping the application
    2020-08-10T16:12:18.251Z [DatabaseConnector] Connecting to database
    2020-08-10T16:12:18.279Z [DatabaseConnector] Successfully connected to database my-local-database
    2020-08-10T16:12:18.279Z [DatabaseConnector] Running migrations
    2020-08-10T16:12:18.289Z [DatabaseConnector] Loaded entities:
    2020-08-10T16:12:18.735Z [GraphqlLoader] Loaded queries: helloWorld
    2020-08-10T16:12:18.749Z [bootstrap] Server is running on http://localhost:3000
    2020-08-10T16:12:18.749Z [bootstrap] Graphql is available on http://localhost:3000/graphql
    curl \
      -X POST \
      -H "Content-Type: application/json" \
      --data '{ "query": "{ helloWorld }" }' \
      http://localhost:3000/graphql
    # src/schema.graphql
    
    # API schema for a simple Blog-post service
    
    type Post {
        id: ID!
        createdAt: String!
        title: String!
        body: String!
        authorName: String!
    }
    
    type Query {
        allPosts: [Post]
    }
    // src/resolvers/queries/allPosts.ts
    
    import { logger, Resolver } from 'codestore-utils';
    
    const resolver: Resolver = async (parent, args, context, info) => {
        logger.log('This is a allPosts resolver!', 'allPosts');
        return [
            {
                id: 1,
                createdAt: '2020-06-30',
                title: 'Test post',
                body: 'Test body',
                authorName: 'Test author',
            }
        ];
    }
    
    export default resolver;
    
    curl \
      -X POST \
      -H "Content-Type: application/json" \
      --data '{ "query": "{ allPosts { id title authorName } }" }' \
      http://localhost:3000/graphql
    // src/resolvers/queries/allPosts.ts
    
    import { logger, Resolver } from 'codestore-utils';
    import Post from '../../data/entities/Post';
    
    const resolver: Resolver = async (parent, args, context, info) => {
        logger.log('This is a allPosts resolver!', 'allPosts');
        const postRepository = context.db.connection.getRepository(Post);
        
        return postRepository.find();
    }
    
    export default resolver;
    
    curl \
      -X POST \
      -H "Content-Type: application/json" \
      --data '{ "query": "{ allPosts { id title authorName } }" }' \
      http://localhost:3000/graphql
    # src/schema.graphql
    
    # API schema for a simple Blog-post service
    
    type Post {
        id: ID!
        createdAt: String!
        title: String!
        body: String!
        authorName: String!
    }
    
    type Query {
        allPosts: [Post]
    }
    
    type Mutation {
        createPost(title: String!, body: String!, authorName: String!): Post
    }
    // src/resolvers/mutations/createPost.ts
    import { logger, Resolver } from 'codestore-utils';
    import Post from '../../data/entities/Post';
    
    const resolver: Resolver = async (parent, args, context, info) => {
        logger.log('creating a new Post', 'createPost');
        
        const post = new Post();
        post.title = args.title;
        post.authorName = args.authorName;
        post.body = args.body;
        post.createdAt = new Date().toISOString();
    
        logger.log(post, 'createPost');
    
        // Getting a database connection
        const repository = context.db.connection.getRepository(Post);
        
        // Saving our first post entity
        return await repository.save(post);
    }
    
    export default resolver;
    # Create a couple of new posts
    $ curl 'http://localhost:3000/graphql' \
        -X POST \
        -H 'Content-Type: application/json' \
        --data '{"query":"mutation createPost($title:String!, $body:String!, $authorName:String!) { createPost(title:$title, body:$body, authorName:$authorName) { id title body authorName } }","variables":{"title":"Our First Article","body":"Body","authorName":"Arthur Conan Doyle"}}'
    
    # And you will get output like this, meaning post successfully created
    {"data":{"createPost":{"id":"1","title":"Our First Article","body":"Body","authorName":"Arthur Conan Doyle"}}}
    
    # Create another one
    $ curl 'http://localhost:3000/graphql' \
        -X POST \
        -H 'Content-Type: application/json' \
        --data '{"query":"mutation createPost($title:String!, $body:String!, $authorName:String!) { createPost(title:$title, body:$body, authorName:$authorName) { id title body authorName } }","variables":{"title":"Our Second Article","body":"Body","authorName":"Arthur Conan Doyle"}}'
    
    # Output  
    {"data":{"createPost":{"id":"2","title":"Our Second Article","body":"Body","authorName":"Arthur Conan Doyle"}}}
    
    
    # Let's retrieve the posts now
    $ curl \
      -X POST \
      -H "Content-Type: application/json" \
      --data '{ "query": "{ allPosts { id title authorName } }" }' \
      http://localhost:3000/graphql
      
    # All posts that we created for now
    {"data":{"allPosts":[{"id":"1","title":"Our First Article","authorName":"Arthur Conan Doyle"},{"id":"2","title":"Our Second Article","authorName":"Arthur Conan Doyle"}]}}
    
    # Or if we format the JSON for more readability
    {
      "data": {
        "allPosts": [
          {
            "id": "1",
            "title": "Our First Article",
            "authorName": "Arthur Conan Doyle"
          },
          {
            "id": "2",
            "title": "Our Second Article",
            "authorName": "Arthur Conan Doyle"
          }
        ]
      }
    }
    otherwise, it will either do nothing or it will inject some information (like the role of the user or an array of permissions, in the case of RBAC) into the request context by returning an object with that information from the auth.handler.
    Quick Start guide
    Quick Start
    The return result of auth.handler.ts is getting injected into the _context_ argument of subsequent resolvers.
    type Post {
        id: ID!
        createdAt: String!
        title: String!
        body: String!
        authorName: String!
    }
    
    type Query {
        allPosts: [Post]
        helloWorld: String!
    }
    
    type Mutation {
        createPost(title: String!, body: String!, authorName: String!): Post
    }
    directive @auth on FIELD_DEFINITION
    
    type Post {
        id: ID!
        createdAt: String!
        title: String!
        body: String!
        authorName: String!
    }
    
    type Query {
        allPosts: [Post] @auth
        helloWorld: String!
    }
    
    type Mutation {
        createPost(title: String!, body: String!, authorName: String!): Post @auth
    }
    
    cs generate:handler -t auth
    # this will generate src/resolvers/auth.handler.ts
    // src/resolvers/auth.handler.ts
    
    import { AuthHandler } from 'codestore-utils';
    
    const authHandler: AuthHandler = async (context) => {
      // your code goes here
      return {};
    };
    
    export default authHandler;
    import { logger, AuthHandler } from 'codestore-utils';
    
    const authHandler: AuthHandler = async (context) => {
      // read the Authorization header from the request
      const authHeader = context.request.header('Authorization');
      logger.log(authHeader, 'auth.handler');
    
      // in this example we authorize and assign permissions based on two tokens
      // in reality these tokens should at least be encrypted
      if (authHeader === 'admin_token') {
        return {
          permissions: {
            read: true,
            write: true,
          }
        };
      } else if (authHeader === 'user_token') {
        return {
          permissions: {
            read: true,
            write: false,
          }
        };
      }
      
      // nope, we can't let you use this query/mutation without a token
      throw new Error('You shall not pass!');
    };
    
    export default authHandler;
    // src/resolvers/queries/allPosts.ts
    
    import { logger, Resolver } from 'codestore-utils';
    import Post from '../../data/entities/Post';
    
    const resolver: Resolver = async (parent, args, context, info) => {
        // Here is how we check for permissions
        if (context?.permissions?.read !== true) {
            throw new Error('You do not have enough permission to read this article!');
        }
        
        logger.log('This is a allPosts resolver!', 'allPosts');
        const postRepository = context.db.connection.getRepository(Post);
        
        return postRepository.find();
    }
    
    export default resolver;
    if (context?.permissions?.read !== true) {
        throw new Error('You do not have enough permission to read this article!');
    }
    // src/resolvers/mutations/createPost.ts
    import { logger, Resolver } from 'codestore-utils';
    import Post from '../../data/entities/Post';
    
    const resolver: Resolver = async (parent, args, context, info) => {
        // Checking permissions
        if (context?.permissions?.write !== true) {
            throw new Error('You do not have enough permission to create a Post!');
        }
    
        logger.log('creating a new Post', 'createPost');
        
        const post = new Post();
        post.title = args.title;
        post.authorName = args.authorName;
        post.body = args.body;
        post.createdAt = new Date().toISOString();
    
        logger.log(post, 'createPost');
    
        // Getting a database connection
        const repository = context.db.connection.getRepository(Post);
        
        // Saving our first post entity
        return await repository.save(post);
    }
    
    export default resolver;
    $ curl 'http://localhost:3000/graphql' \
      -H "Content-Type: application/json" \
      --data '{ "query": "{ helloWorld }" }'
      
    {"data":{"helloWorld":"Hello, World!"}}
    # This should normally fail
    $ curl 'http://localhost:3000/graphql' \
      -H "Content-Type: application/json" \
      --data '{ "query": "{ allPosts { id title } }" }'                                                             12.18.3
      
    {
      "errors": [
        {
          "message": "You shall not pass!",
          "locations": [
            {
              "line": 1,
              "column": 3
            }
          ],
          "path": [
            "allPosts"
          ],
          "extensions": {
            "code": "INTERNAL_SERVER_ERROR",
            "exception": {
              "stacktrace": [
                "Error: You shall not pass!",
                "..."
              ]
            }
          }
        }
      ],
      "data": {
        "allPosts": null
      }
    }
    $ curl 'http://localhost:3000/graphql' \
      -H "Authorization: user_token" \
      -H "Content-Type: application/json" \
      --data '{ "query": "{ allPosts { id title } }" }'
    
    {
      "data": {
        "allPosts": [
          {
            "id": "1",
            "title": "Our First Article"
          },
          {
            "id": "2",
            "title": "Our Second Article"
          },
          {
            "id": "3",
            "title": "Our Third Article"
          }
        ]
      }
    }
    $ curl 'http://localhost:3000/graphql' \
        -H "Authorization: user_token" 
        -H "Content-Type: application/json" 
        --data '{ "query": "mutation createPost($title:String!, $body:String!, $authorName:String!) { createPost(title:$title, body:$body, authorName:$authorName) { id title body authorName } }", "variables": "{ \"title\": \"Our Fourth Article\", \"body\": \"Body\", \"authorName\": \"Arthur Conan Doyle\" }" }'
        
    {
      "errors": [
        {
          "message": "You do not have enough permission to create a Post!",
          "locations": [
            {
              "line": 1,
              "column": 75
            }
          ],
          "path": [
            "createPost"
          ],
          "extensions": {
            "code": "INTERNAL_SERVER_ERROR",
            "exception": {
              "stacktrace": [
                "Error: You do not have enough permission to create a Post!"
              ]
            }
          }
        }
      ],
      "data": {
        "createPost": null
      }
    }
    $ curl 'http://localhost:3000/graphql' \
        -H "Authorization: admin_token" \
        -H "Content-Type: application/json" \
        --data '{ "query": "mutation createPost($title:String!, $body:String!, $authorName:String!) { createPost(title:$title, body:$body, authorName:$authorName) { id title body authorName } }", "variables": "{ \"title\": \"Our Fourth Article\", \"body\": \"Body\", \"authorName\": \"Arthur Conan Doyle\" }" }'
        
    {
      "data": {
        "createPost": {
          "id": "4",
          "title": "Our Fourth Article",
          "body": "Body",
          "authorName": "Arthur Conan Doyle"
        }
      }
    }